import * as React from 'react'; import { notFound } from 'next/navigation'; import { blogPosts } from '../../../src/data/blogPosts'; import { Tag } from '../../../src/components/Tag'; import { CodeBlock } from '../../../src/components/ArticleBlockquote'; import { H2 } from '../../../src/components/ArticleHeading'; import { Paragraph, LeadParagraph } from '../../../src/components/ArticleParagraph'; import { UL, LI } from '../../../src/components/ArticleList'; import { FileExamplesList } from '../../../src/components/FileExamplesList'; import { FileExampleManager } from '../../../src/data/fileExamples'; import { BlogPostClient } from '../../../src/components/BlogPostClient'; import { PageHeader } from '../../../src/components/PageHeader'; import { Section } from '../../../src/components/Section'; import { Reveal } from '../../../src/components/Reveal'; export async function generateStaticParams() { return blogPosts.map((post) => ({ slug: post.slug, })); } export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; const post = blogPosts.find((p) => p.slug === slug); if (!post) { notFound(); } const formattedDate = new Date(post.date).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }); const wordCount = post.description.split(/\s+/).length + 100; const readingTime = Math.max(1, Math.ceil(wordCount / 200)); const showFileExamples = post.tags?.some(tag => ['architecture', 'design-patterns', 'system-design', 'docker', 'deployment'].includes(tag) ); // Load file examples for the post let groups: any[] = []; if (showFileExamples) { const allGroups = await FileExampleManager.getAllGroups(); groups = allGroups .map((group) => ({ ...group, files: group.files.filter((file) => { if (file.postSlug !== slug) return false; return true; }), })) .filter((group) => group.files.length > 0); } return (
{readingTime} min read
{post.tags && post.tags.length > 0 && (
{post.tags.map((tag, index) => ( ))}
)} {slug === 'first-note' && ( <> This blog is a public notebook. It's where I document things I learn, problems I solve, and tools I test.

Why write in public?

I forget things. Writing them down helps. Making them public helps me think more clearly and might help someone else.

What to expect

  • Short entries, usually under 500 words
  • Practical solutions to specific problems
  • Notes on tools and workflows
  • Mistakes and what I learned
)} {slug === 'debugging-tips' && ( <> Sometimes the simplest debugging tool is the best one. Print statements get a bad reputation, but they're often exactly what you need.

Why print statements work

Debuggers are powerful, but they change how your code runs. Print statements don't. {`def process_data(data): print(f"Processing {len(data)} items") result = expensive_operation(data) print(f"Operation result: {result}") return result`}

Complete examples

Here are some practical file examples you can copy and download. These include proper error handling and logging.
)} {slug === 'architecture-patterns' && ( <> Good software architecture is about making the right decisions early. Here are some patterns I've found useful in production systems.

Repository Pattern

The repository pattern provides a clean separation between your business logic and data access layer. It makes your code more testable and maintainable.

Service Layer

Services orchestrate business logic and coordinate between repositories and domain events. They keep your controllers thin and your business rules organized.

Domain Events

Domain events help you decouple components and react to changes in your system. They're essential for building scalable, event-driven architectures.

Complete examples

These TypeScript examples demonstrate modern architecture patterns for scalable applications. You can copy them directly into your project.
)} {slug === 'docker-deployment' && ( <> Docker has become the standard for containerizing applications. Here's how to set up production-ready deployments that are secure, efficient, and maintainable.

Multi-stage builds

Multi-stage builds keep your production images small and secure by separating build and runtime environments. This reduces attack surface and speeds up deployments.

Health checks and monitoring

Proper health checks ensure your containers are running correctly. Combined with restart policies, this gives you resilient, self-healing deployments.

Orchestration with Docker Compose

Docker Compose makes it easy to manage multi-service applications in development and production. Define services, networks, and volumes in a single file.

Complete examples

These Docker configurations are production-ready. Use them as a starting point for your own deployments.
)}
); }