Skip to content

Intro

Feed

A collection of short notes, interesting links, and the occasional long form post.

Items

  • Published

    Man can do what he wills, but he cannot will what he wills

  • Published

    The Founder List: A Digital Cartography of Creation

    A curated dataset of Silicon Valley founders, their ventures, and the intricate web of connections that shape the startup ecosystem. Track founding patterns, investment networks, and the geographic clustering of innovation through structured data on entrepreneurs, their companies, and career trajectories.

  • Published

    From Puddle to Lake: Auto-Transforming Your Raw Data with Cloudflare Event Notifications

    Set up automatic data transformation for your Cloudflare data lake. This step-by-step guide shows how to configure event notifications and Workers to seamlessly process raw pipeline data into analytics-ready Iceberg tables.

  • Published

    Foundation & Strategic Alignment

  • Published

    Text Reveal on Scroll Animation (anime.js)

    A smooth animation that reveals text elements and SVG drawings as the user scrolls, transitioning them from half-visible to fully visible with subtle movements and opacity changes.

  • Published

    Building Your Own Data Lake with Cloudflare: The Hidden Alternative to Enterprise SaaS

    Learn how to build a cost-effective data lake using Cloudflare's tools (Pipelines, R2 Data Catalog) and DuckDB. This practical guide shows how to create a modern data platform without expensive enterprise solutions.

  • Published

    With Email Workers you can leverage the power of Cloudflare Workers to implement any logic you need to process your emails and create complex rules. These rules determine what happens when you receive an email. read more ->

  • Published

    If you haven’t scrolled enought on hono’s documentation and ended up googling the problem:

    If you are developing an application for Cloudflare Workers, a streaming may not work well on Wrangler. If so, add Identity for Content-Encoding header.

    app.get('/streamText', (c) => {
      c.header('Content-Encoding', 'Identity')
      return streamText(c, async (stream) => {
        // ...
      })
    })
    
  • Published

    (based on writing https://alexkrupp.typepad.com/sensemaking/2021/06/django-for-startup-founders-a-better-software-architecture-for-saas-startups-and-consumer-apps.html)

    You are an expert in Python, Django, and scalable web application development.

    Predictability

    1. Every Endpoint Should Tell a Story

      • Explanation: Structure each REST API endpoint to follow a consistent pattern. This makes your code predictable and easier to understand. The pattern includes specifying permissions, handling inputs, performing business logic, and returning responses in a standard way.

      • Example:

        from rest_framework.views import APIView
        from rest_framework.permissions import IsAuthenticated
        from rest_framework.response import Response
        
        class UserProfileView(APIView):
            permission_classes = [IsAuthenticated]
        
            def get(self, request):
                # Step 1: Copy input to local variables
                user_id = request.query_params.get('user_id')
        
                # Step 2: Sanitize input
                user_id = sanitize_input(user_id)
        
                # Step 3: Validate input
                if not user_id:
                    return Response({'error': 'User ID is required.'}, status=400)
        
                # Step 4: Enforce business requirements
                if not user_exists(user_id):
                    return Response({'error': 'User does not exist.'}, status=404)
        
                # Step 5: Perform business logic
                user_profile = get_user_profile(user_id)
        
                # Step 6: Return HTTP response
                return Response({'data': user_profile}, status=200)
        
    2. Keep Business Logic in Services

      • Explanation: Separate your business logic from views and models. Place it in service modules to promote reusability and maintainability.

      • Example:

        # services/user_services.py
        def get_user_profile(user_id):
            # Complex logic to retrieve and process user profile
            pass
        
        # views.py
        from services.user_services import get_user_profile
        
    3. Make Services the Locus of Reusability

      • Explanation: Reuse service methods across your project wherever the same functionality is needed. This avoids code duplication and keeps your logic consistent.

      • Example:

        # services/notification_services.py
        def send_welcome_email(user_email):
            # Logic to send email
            pass
        
        # Used in multiple places
        send_welcome_email(user_email)
        
    4. Always Sanitize User Input, Sometimes Save Raw Input, Always Escape Output

      • Explanation: Sanitize all user inputs immediately to prevent security vulnerabilities like XSS attacks. Save raw input only when necessary for future reference, and always escape outputs when displaying data.

      • Example:

        import html
        
        def sanitize_input(input_value):
            return html.escape(input_value)
        
        # Sanitize input
        user_input = sanitize_input(request.data.get('comment'))
        
    5. Don’t Split Files by Default & Never Split Your URLs File

      • Explanation: Keep related code together to make it easier to find and understand. Avoid unnecessary splitting of files, especially the urls.py file.

      • Example:

        • Keep all URL patterns in a single urls.py file with clear comments separating sections.
        # urls.py
        from django.urls import path
        from .views import UserProfileView, UserSettingsView
        
        urlpatterns = [
            # User-related URLs
            path('user/profile/', UserProfileView.as_view(), name='user-profile'),
            path('user/settings/', UserSettingsView.as_view(), name='user-settings'),
            # Other sections...
        ]
        

    Readability

    1. Each Variable’s Type or Kind Should Be Obvious from Its Name

      • Explanation: Use clear and descriptive names for variables that indicate their type or purpose, reducing confusion.

      • Example:

        user_list = []
        user_dict = {}
        is_active_user = True
        
    2. Assign Unique Names to Files, Classes, and Functions

      • Explanation: Ensure that each file, class, and function has a unique name to avoid conflicts and improve searchability.

      • Example:

        • Instead of multiple views.py files, use user_views.py, product_views.py.
    3. **Avoid *args and **kwargs in User Code**

      • Explanation: Use explicit parameters in functions to enhance clarity and prevent unexpected behaviors.

      • Example:

        def create_user(username, email):
            pass  # Good
        
        def create_user(*args, **kwargs):
            pass  # Avoid this
        
    4. Use Functions, Not Classes

      • Explanation:

        • Simplicity and Clarity: Functions are simpler and more straightforward than classes. They perform specific tasks and are easier to read, understand, and test.
        • Avoid Unnecessary Complexity: Classes introduce complexity with state management, inheritance, and side effects, which can make the code harder to maintain, especially for small to medium-sized projects.
        • Functional Programming Benefits: Emphasizing functions aligns with functional programming principles, leading to more predictable and bug-resistant code.
        • Statelessness: Functions that avoid maintaining state reduce the likelihood of unintended interactions and make concurrent execution safer.
      • Guidelines:

        • Use plain functions for operations that don’t require object-oriented features.
        • Only use classes when you need to maintain state across multiple function calls or when leveraging polymorphism and inheritance is essential.
        • Favor pure functions that return outputs solely based on inputs without side effects.
      • Examples:

        # Good Practice: Using Functions
        
        # utils/math_utils.py
        def calculate_discount(price, discount_percent):
            return price * (discount_percent / 100)
        
        def apply_tax(price, tax_rate):
            return price + (price * (tax_rate / 100))
        
        # Usage in your code
        discounted_price = calculate_discount(original_price, 10)
        final_price = apply_tax(discounted_price, 5)
        
        # Avoid: Unnecessary Use of Classes
        
        # utils/math_utils.py
        class PriceCalculator:
            def __init__(self, price):
                self.price = price
        
            def calculate_discount(self, discount_percent):
                return self.price * (discount_percent / 100)
        
            def apply_tax(self, tax_rate):
                return self.price + (self.price * (tax_rate / 100))
        
        # Usage in your code
        calculator = PriceCalculator(original_price)
        discounted_price = calculator.calculate_discount(10)
        final_price = calculator.apply_tax(5)
        

        Why Prefer Functions Over Classes in This Context:

        • Reduced Boilerplate: Functions eliminate the need for boilerplate code like __init__ methods.
        • Easier Testing: Pure functions are easier to test since they don’t rely on or alter external state.
        • Better Readability: Functions focus on performing a single task, making the code more readable and maintainable.
        • Avoiding Side Effects: Without class state, there’s a lower risk of side effects from shared mutable data.
      • When to Use Classes:

        • Stateful Operations: If you need to maintain state between function calls.
        • Complex Data Structures: When modeling entities with both data and behaviors tightly coupled together.
        • Inheritance and Polymorphism: When you need to extend or modify behaviors through inheritance hierarchies.
      • Example of Appropriate Class Use:

        # models/user.py
        class User:
            def __init__(self, username, email):
                self.username = username
                self.email = email
        
            def send_email(self, subject, message):
                # Logic to send email to self.email
                pass
        
        # Using the User class
        user = User('john_doe', '[email protected]')
        user.send_email('Welcome', 'Thank you for signing up!')
        

        In this case, using a class makes sense because User represents an entity with attributes and behaviors.

    5. There Are Exactly Four Types of Errors

      • Explanation:

        Standardizing error handling across your application improves consistency and makes your code easier to maintain and debug. The four types of errors are:

        1. Upstream Errors:
          • Errors that originate from middleware or external services before reaching your application logic.
          • Handling: Generally, allow these errors to propagate. Customize handling only if necessary.
        2. Validation Errors:
          • Occur when user input fails to meet predefined validation rules (e.g., missing fields, invalid formats).
          • Handling: Collect and return all validation errors together with descriptive messages.
        3. Business Requirement Errors:
          • Occur when input is valid, but the action violates business rules (e.g., insufficient funds, access denied).
          • Handling: Return specific error messages indicating why the action cannot be completed.
        4. Internal Errors (500 Errors):
          • Unexpected errors due to bugs or exceptions in the server.
          • Handling: Log details for debugging but return a generic error message to the client to avoid exposing sensitive information.
      • Guidelines:

        • Use consistent error response structures.
        • Include meaningful error messages and appropriate HTTP status codes.
        • Avoid exposing internal implementation details in error messages sent to clients.
        • Implement centralized error handling where possible to maintain consistency.
      • Examples:

        from rest_framework.views import APIView
        from rest_framework.response import Response
        from rest_framework import status
        
        class TransactionView(APIView):
            permission_classes = [IsAuthenticated]
        
            def post(self, request):
                # 1. Copy and sanitize inputs
                amount = sanitize_input(request.data.get('amount'))
                recipient_id = sanitize_input(request.data.get('recipient_id'))
        
                # 2. Validate inputs
                errors = {}
                if not amount:
                    errors['amount'] = ['Amount is required.']
                elif not is_valid_amount(amount):
                    errors['amount'] = ['Invalid amount format.']
        
                if not recipient_id:
                    errors['recipient_id'] = ['Recipient ID is required.']
        
                if errors:
                    # **Validation Error**
                    return Response({'errors': errors}, status=status.HTTP_400_BAD_REQUEST)
        
                # 3. Business logic and requirements
                if not has_sufficient_funds(request.user, amount):
                    # **Business Requirement Error**
                    return Response(
                        {'error': 'Insufficient funds.'},
                        status=status.HTTP_403_FORBIDDEN
                    )
        
                if not recipient_exists(recipient_id):
                    return Response(
                        {'error': 'Recipient not found.'},
                        status=status.HTTP_404_NOT_FOUND
                    )
        
                try:
                    # 4. Perform transaction
                    transaction = perform_transaction(request.user, recipient_id, amount)
                except ExternalServiceError as e:
                    # **Upstream Error**
                    return Response(
                        {'error': 'Transaction service is unavailable.'},
                        status=status.HTTP_503_SERVICE_UNAVAILABLE
                    )
                except Exception as e:
                    # **Internal Error**
                    log_error(e)
                    return Response(
                        {'error': 'An unexpected error occurred.'},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )
        
                # 5. Success response
                return Response({'message': 'Transaction completed successfully.'}, status=status.HTTP_200_OK)
        
      • Detailed Breakdown:

        • Validation Errors (400 Bad Request):

          • Collect all input validation errors.
          • Return them together so the client can fix all issues at once.
          if errors:
              return Response({'errors': errors}, status=status.HTTP_400_BAD_REQUEST)
          

          Error Response Structure:

          {
            "errors": {
              "amount": ["Amount is required."],
              "recipient_id": ["Recipient ID is required."]
            }
          }
          
        • Business Requirement Errors (403 Forbidden, 404 Not Found):

          • Return a specific error message indicating the business rule violation.
          • Use appropriate status codes to reflect the error type.
          if not has_sufficient_funds(request.user, amount):
              return Response(
                  {'error': 'Insufficient funds.'},
                  status=status.HTTP_403_FORBIDDEN
              )
          

          Error Response Structure:

          {
            "error": "Insufficient funds."
          }
          
        • Upstream Errors (503 Service Unavailable):

          • Errors from external services or middleware.
          • Communicate service unavailability without exposing internal details.
          except ExternalServiceError as e:
              return Response(
                  {'error': 'Transaction service is unavailable.'},
                  status=status.HTTP_503_SERVICE_UNAVAILABLE
              )
          
        • Internal Errors (500 Internal Server Error):

          • Catch-all for unexpected exceptions.
          • Log the exception details internally.
          • Return a generic error message to the client.
          except Exception as e:
              log_error(e)
              return Response(
                  {'error': 'An unexpected error occurred.'},
                  status=status.HTTP_500_INTERNAL_SERVER_ERROR
              )
          
      • Consistent Error Response Structure:

        • For Validation Errors:

          {
            "errors": {
              "field_name": ["Error message."]
            }
          }
          
        • For Business Requirement, Upstream, and Internal Errors:

          {
            "error": "Error message."
          }
          
      • Best Practices:

        • Logging:
          • Always log exceptions and errors on the server side for auditing and debugging purposes.
        • User-Friendly Messages:
          • Provide clear and actionable error messages without exposing sensitive information.
        • HTTP Status Codes:
          • Use appropriate status codes to represent the error type (e.g., 400, 403, 404, 500).
        • Avoid Exception Swallowing:
          • Do not catch exceptions without handling them properly. This could mask issues and make debugging difficult.
        • Error Handling Middleware:
          • Implement middleware to handle uncaught exceptions globally, ensuring consistent error responses.

    Simplicity

    1. URL Parameters Are a Scam

      • Explanation: Avoid using URL parameters. Use query parameters for GET requests and body parameters for POST/PUT requests for consistency.

      • Example:

        # Instead of this
        path('user/<int:user_id>/', UserProfileView.as_view(), name='user-profile')
        
        # Use this
        path('user/profile/', UserProfileView.as_view(), name='user-profile')
        # And pass user_id as a query parameter: /user/profile/?user_id=123
        
    2. Write Tests. Not Too Many. Mostly Integration.

      • Explanation: Focus on writing integration tests for your endpoints to ensure they work correctly when combined. Don’t overdo unit tests.

      • Example:

        from rest_framework.test import APITestCase
        
        class UserProfileTests(APITestCase):
            def test_get_user_profile(self):
                response = self.client.get('/user/profile/', {'user_id': 1})
                self.assertEqual(response.status_code, 200)
        
    3. Treat Unit Tests as a Specialist Tool

      • Explanation: Use unit tests sparingly for complex functions or algorithms that need isolated testing.

      • Example:

        import unittest
        
        def calculate_discount(price, percentage):
            return price * (percentage / 100)
        
        class DiscountTests(unittest.TestCase):
            def test_calculate_discount(self):
                self.assertEqual(calculate_discount(100, 10), 10)
        
    4. Use Serializers Responsibly, or Not at All

      • Explanation: Use serializers for input validation and output formatting, but avoid overcomplicating them. Consider simpler alternatives when appropriate.

      • Example:

        from rest_framework import serializers
        
        class UserSerializer(serializers.Serializer):
            username = serializers.CharField(max_length=100)
            email = serializers.EmailField()
        
    5. Write Admin Functionality as API Endpoints

      • Explanation: Implement admin actions as API endpoints with proper permissions. This keeps logic consistent and testable.

      • Example:

        # views.py
        class AdminUserListView(APIView):
            permission_classes = [IsAdminUser]
        
            def get(self, request):
                users = get_all_users()
                return Response({'users': users}, status=200)
        

    Upgradability

    1. Your App Lives Until Your Dependencies Die

      • Explanation: Choose well-maintained and widely-used dependencies. Keep them updated to ensure long-term sustainability.

      • Example:

        • Use the latest stable versions of Django and other libraries.
        • Regularly update dependencies using pip-upgrade.
    2. Keep Logic Out of the Front End

      • Explanation: Minimize business logic in the front end. Handle it on the server side to simplify maintenance and upgrades.

      • Example:

        • Perform data processing in views or services, and send prepared data to the front end.
    3. Don’t Break Core Dependencies

      • Explanation: Avoid altering or making assumptions about the internal behavior of core frameworks and libraries. Use them as intended.

      • Example:

        • Don’t override internal Django methods unless absolutely necessary.
        • Avoid hacking into library internals to change behavior.

    Using uv for the project, and to run manage.py use uv run python manage.py etc

  • Published

    …if anything I want to become what I’ve called an information trillionaire, I’m not going to make that but its a good aspiration to have, just collect more information and be an information trillionaire…

    from https://www.youtube.com/watch?v=W1eEPAUE6nY

  • Published

    canScroll() { return false } wasn’t working on my custom shape. Did this instead.

    const TableComponent = () => {
      const containerRef = useRef<HTMLDivElement>(null);
    
      useEffect(() => {
        const containerElement = containerRef.current;
    
        const handleWheel = (event: WheelEvent) => {
          const isOverCardShape = containerElement?.contains(event.target as Node);
    
          // to determine if the event should be prevented
          if (isOverCardShape) {
            // event.preventDefault();
            event.stopPropagation();
          }
        };
    
        containerElement?.addEventListener("wheel", handleWheel, {
          passive: false,
        });
    
        return () => {
          containerElement?.removeEventListener("wheel", handleWheel);
        };
      }, [containerRef]);
    
      ...
    
  • Published
    import { DayPicker } from "react-day-picker";
    import "react-day-picker/style.css";
    
    function MyDatePicker() {
      const [selected, setSelected] = useState<Date>();
    
      return (
        <DayPicker
          mode="single"
          selected={selected}
          onSelect={setSelected}
          footer={
            selected ? `Selected: ${selected.toLocaleDateString()}` : "Pick a day."
          }
        />
      );
    }
    

    DayPicker + Radix UI Popover

    "use client";
    import React from "react";
    import { useState } from "react";
    import { DayPicker } from "react-day-picker";
    import * as Popover from "@radix-ui/react-popover";
    import { format } from "date-fns";
    import "react-day-picker/style.css";
    import { useRouter } from "next/navigation";
    
    export function MyDatePicker({ displayDate }: { displayDate: string }) {
      const router = useRouter();
    
      const [selected, setSelected] = useState<Date>();
      const [open, setOpen] = useState(false);
    
      const handleDateSelect = (date: Date) => {
        setSelected(date);
        const formattedDate = format(date, "yyyy-MM-dd");
        router.push(`/schedule?date=${formattedDate}`);
        setOpen(false);
      };
    
      return (
        <Popover.Root open={open} onOpenChange={setOpen}>
          <Popover.Trigger asChild>
            <button className="display-date">{displayDate}</button>
          </Popover.Trigger>
          <Popover.Content className="PopoverContent">
            <DayPicker
              mode="single"
              selected={selected}
              onDayClick={handleDateSelect}
              footer={
                selected
                  ? `Selected: ${selected.toLocaleDateString()}`
                  : "Pick a day."
              }
            />
          </Popover.Content>
        </Popover.Root>
      );
    }
    
    
  • Published

    Astro + Temporal try

    This code demonstrates how to initiate a workflow in Astro using the Temporal client