Building Scalable Microservices Architecture
•8 min readArchitecture
Building Scalable Microservices Architecture
When designing microservices at scale, there are several key principles to consider:
1. Service Boundaries
interface ServiceBoundary { domain: string; context: string; responsibilities: string[]; } const userService: ServiceBoundary = { domain: 'users', context: 'authentication', responsibilities: ['user registration', 'authentication', 'profile management'] };
2. Inter-Service Communication
Here's an example of implementing event-driven communication:
interface Event { type: string; payload: unknown; timestamp: Date; } class EventBus { private subscribers: Map<string, Function[]> = new Map(); publish(event: Event) { const subscribers = this.subscribers.get(event.type) || []; subscribers.forEach((callback) => callback(event.payload)); } subscribe(eventType: string, callback: Function) { if (!this.subscribers.has(eventType)) { this.subscribers.set(eventType, []); } this.subscribers.get(eventType)?.push(callback); } }
3. Let's update the blog page to handle markdown files:
```typescript:src/app/blog/page.tsx
import { Metadata } from 'next'
import { getAllPosts, Post } from '@/lib/blog'
import Navigation from '@/components/Navigation'
export const metadata: Metadata = {
title: 'Blog | Mirko Friedrich',
description: 'Technical insights, software development best practices, and industry trends from my experience as a senior software developer.'
}
export default async function Blog() {
const posts = await getAllPosts()
return (
<>
<Navigation />
<div className="bg-white dark:bg-gray-900 py-24 sm:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-3xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-4xl">
Technical Insights & Industry Trends
</h2>
<p className="mt-2 text-lg leading-8 text-gray-600 dark:text-gray-300">
Sharing knowledge and experiences from 15+ years in software development.
</p>
</div>
<div className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-3">
{posts.map((post) => (
<article key={post.slug} className="flex flex-col items-start">
<div className="flex items-center gap-x-4 text-xs">
<time dateTime={post.date} className="text-gray-500 dark:text-gray-400">
{new Date(post.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</time>
<span className="relative z-10 rounded-full bg-gray-50 dark:bg-gray-800 px-3 py-1.5 font-medium text-gray-600 dark:text-gray-400">
{post.category}
</span>
</div>
<div className="group relative">
<h3 className="mt-3 text-lg font-semibold leading-6 text-gray-900 dark:text-white group-hover:text-gray-600 dark:group-hover:text-gray-300">
<a href={`/blog/${post.slug}`}>
<span className="absolute inset-0" />
{post.title}
</a>
</h3>
<p className="mt-5 line-clamp-3 text-sm leading-6 text-gray-600 dark:text-gray-300">
{post.description}
</p>
</div>
<div className="relative mt-8 flex items-center gap-x-4">
<div className="text-sm leading-6">
<p className="font-semibold text-gray-900 dark:text-white">
{post.readingTime}
</p>
</div>
</div>
</article>
))}
</div>
</div>
</div>
</>
)
}
- Create the blog post page:
import { Metadata } from 'next' import { notFound } from 'next/navigation' import { getPostBySlug, getAllPosts } from '@/lib/blog' import Navigation from '@/components/Navigation' import Markdown from '@/components/Markdown' interface Props { params: { slug: string } } export async function generateMetadata({ params }: Props): Promise<Metadata> { const post = await getPostBySlug(params.slug) if (!post) { return {} } return { title: post.title, description: post.description } } export async function generateStaticParams() { const posts = await getAllPosts() return posts.map((post) => ({ slug: post.slug, })) } export default async function BlogPost({ params }: Props) { const post = await getPostBySlug(params.slug) if (!post) { notFound() } return ( <> <Navigation /> <article className="mx-auto max-w-3xl px-6 py-24 prose dark:prose-invert"> <h1>{post.title}</h1> <div className="flex gap-4 text-sm text-gray-600 dark:text-gray-400"> <time dateTime={post.date}> {new Date(post.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} </time> <span>{post.readingTime}</span> </div> <Markdown content={post.content} /> </article> </> ) }
- Create the blog utilities:
import fs from 'fs/promises' import path from 'path' import matter from 'gray-matter' const postsDirectory = path.join(process.cwd(), 'src/content/blog') export interface Post { slug: string title: string date: string description: string category: string readingTime: string content: string } export async function getAllPosts(): Promise<Post[]> { const files = await fs.readdir(postsDirectory) const posts = await Promise.all( files .filter((file) => path.extname(file) === '.md') .map(async (file) => { const filePath = path.join(postsDirectory, file) const fileContent = await fs.readFile(filePath, 'utf8') const { data, content } = matter(fileContent) return { slug: path.basename(file, '.md'), title: data.title, date: data.date, description: data.description, category: data.category, readingTime: data.readingTime, content } }) ) return posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) } export async function getPostBySlug(slug: string): Promise<Post | null> { try { const filePath = path.join(postsDirectory, `${slug}.md`) const fileContent = await fs.readFile(filePath, 'utf8') const { data, content } = matter(fileContent) return { slug, title: data.title, date: data.date, description: data.description, category: data.category, readingTime: data.readingTime, content } } catch { return null } }
- Create a Markdown component to render the content:
'use client' import { ReactMarkdown } from 'react-markdown/lib/react-markdown' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism' interface Props { content: string } export default function Markdown({ content }: Props) { return ( <ReactMarkdown components={{ code({ node, inline, className, children, ...props }) { const match = /language-(\w+)/.exec(className || '') return !inline && match ? ( <SyntaxHighlighter style={vscDarkPlus} language={match[1]} PreTag="div" {...props} > {String(children).replace(/\n$/, '')} </SyntaxHighlighter> ) : ( <code className={className} {...props}> {children} </code> ) } }} > {content} </ReactMarkdown> ) }
- Install required dependencies:
pnpm add gray-matter react-markdown react-syntax-highlighter @types/react-syntax-highlighter
This setup provides:
- Markdown file-based blog posts
- Frontmatter for post metadata
- Automatic slug-based routing
- Code syntax highlighting
- Static page generation for better performance
- Proper TypeScript support
Create more blog posts in the src/content/blog
directory following the same frontmatter structure as the example. The posts will be automatically added to the blog listing and individual pages will be generated.
Would you like me to:
- Add more markdown features (like images, tables, etc.)?
- Create additional blog posts?
- Add search functionality?
- Implement categories/tags filtering?