micro-block-pattern.md

Micro-block architecture pattern for AI-native development

micro-block-pattern.mdv3.0.134.7 KB
micro-block-pattern.md(markdown)
1# Micro-Block Design Pattern
2
3## Overview
4
5The Micro-Block Design Pattern is a command-based pattern designed for AI-collaborative development. It decomposes complex systems into small, discrete, contract-driven building blocks that can be discovered, composed, and substituted automatically by AI agents.
6
7This pattern enables intelligent software development where AI can understand, select, and compose functionality through rich metadata and explicit contracts.
8
9**Note**: While the examples in this document are written in TypeScript for clarity and precision, the design pattern concepts are language-agnostic and can be implemented in any object-oriented programming language that supports interfaces, classes, and dependency injection (Java, C#, Python, Go, Rust, etc.).
10
11## Core Principles
12
131. **Contract-First Design**: All commands implement explicit Input, Output, and Error contracts
142. **Self-Describing Components**: Commands include rich metadata for AI understanding
153. **Loose Coupling**: Commands are isolated and interact only through well-defined interfaces
164. **Dynamic Discovery**: Registry enables automatic command discovery and composition
175. **Substitutability**: Commands with identical contracts are interchangeable
186. **Hierarchical Composition**: Commands can include other commands, enabling complex workflow orchestration
197. **Self-Contained Modularity**: Each command is a portable, independent unit
208. **Service Abstraction**: Commands depend on service interfaces, not concrete implementations
219. **Lazy Loading**: Commands are loaded on-demand, services are registered at startup
22
23## Design Components
24
25### Component Architecture
26
27```
28┌──────────────────────────────────────────────────────────────────┐
29│                    Micro-Block Ecosystem                         │
30├──────────────────────────────────────────────────────────────────┤
31│                                                                  │
32│                    ┌───────────────────────────────────┐         │
33│                    │         Registry Layer            │         │
34│                    │                                   │         │
35│                    │  ┌─────────────────────────────┐  │         │
36│                    │  │    ServiceRegistry          │  │         │
37│                    │  │  • Service Management       │  │         │
38│                    │  │  • Configuration Mapping    │  │         │
39│                    │  │  • Primary Access Point     │  │         │
40│                    │  └─────────────────────────────┘  │         │
41│                    │             │                     │         │
42│                    │             ▼                     │         │
43│  ┌─────────────────┐│  ┌────────────────────────────┐  │         │
44│  │  Command Layer  ││  │    CommandRegistry         │  │         │
45│  │                 │◄──│  • Command Discovery       │  │         │
46│  │ ┌─────────────┐ ││  │  • Lazy Loading            │  │         │
47│  │ │   Command   │ ││  │  • Metadata Analysis       │  │         │
48│  │ │             │ ││  │  • Dependency Injection    │  │         │
49│  │ │ • Metadata  │ ││  └────────────────────────────┘  │         │
50│  │ │ • Contracts │ │└──────────────────────────────────┐         │
51│  │ │ • Validation│ │                                   │         │
52│  │ │ • Execute   │ │                                   │         │
53│  │ └─────────────┘ │    ┌─────────────────────────────┐│         │
54│  │       │         │    │         Service Layer       ││         │
55│  │       ▼         │    │                             ││         │
56│  │ ┌─────────────┐ │    │  ┌─────────────────────────┐││         │
57│  │ │Error/Output │ │    │  │    Service Interface    │││         │
58│  │ │  Contracts  │ │    │  │  • Abstract Capabilities│││         │
59│  │ └─────────────┘ │    │  │  • Contract Definition  │││         │
60│  └─────────────────┘    │  └─────────────────────────┘││         │
61│                         │             │               ││         │
62│                         │             ▼               ││         │
63│                         │  ┌─────────────────────────┐││         │
64│                         │  │   Service Implementation│││         │
65│                         │  │  • Portable Design      │││         │
66│                         │  │  • Configuration Interface││        │
67│                         │  │  • Rich Metadata        │││         │
68│                         │  └─────────────────────────┘││         │
69│                         └──────────────────────────────┘│        │
70└──────────────────────────────────────────────────────────────────┘
71
72           Data Flow: Registry ► Commands ► Services
73           Discovery: Metadata-driven component selection and composition
74```
75
76### Core Components
77
78- **Commands**: Self-contained units of business logic with explicit contracts
79- **Service Interfaces**: Abstract definitions of capabilities (data access, external APIs, etc.)
80- **Service Implementations**: Concrete implementations of service interfaces with rich metadata
81- **Command Registry**: Discovery mechanism for finding and composing commands with lazy loading
82- **Service Registry**: Configuration mapping and service management with dependency injection
83
84## Command Structure & Contracts
85
86### Base Command Interface
87
88All commands must implement the BaseCommand interface with error-throwing validation:
89
90```typescript
91interface BaseCommand {
92  /** 
93   * Validate that the command can execute with current configuration.
94   * Throws detailed validation errors instead of returning boolean.
95   */
96  validate(): void;
97  
98  /** Execute the command's business logic */
99  execute(): Promise<any>;
100  
101  /** Get the static metadata for this command */
102  getMetadata(): CommandMetadata;
103}
104```
105
106### Command Metadata Structure
107
108Commands must include comprehensive metadata for AI-driven discovery:
109
110```typescript
111interface CommandMetadata {
112  name: string;                    // Unique command identifier
113  description: string;             // Human-readable description
114  category: string;                // Grouping category (user, email, cache, etc.)
115  inputType: string;               // Input contract type name
116  outputType: string;              // Output contract type name
117  errorType: string;               // Error contract type name
118  version: string;                 // Command implementation version
119  contractVersion: string;         // Input/output contract version
120  
121  dependencies?: {
122    services?: string[];           // Service interface dependencies
123    commands?: string[];           // Command dependencies for composition
124    external?: string[];           // External package dependencies
125  };
126  
127  dataFlow?: {
128    inputs: string[];              // Input data fields
129    outputs: string[];             // Output data fields
130    sideEffects: string[];         // Side effects performed (database-write, email-send)
131  };
132  
133  performance?: {
134    expectedDuration: string;      // Expected execution time (fast, medium, slow)
135    scaling: string;               // Performance scaling characteristics
136  };
137}
138```
139
140### Contract Patterns
141
142#### Input/Output/Error Contracts
143
144Each command defines three explicit contracts:
145
146```typescript
147// Input Contract - What the command needs
148interface CreateUserInput {
149  email: string;
150  password: string;
151  name: string;
152}
153
154// Output Contract - What the command produces  
155interface CreateUserOutput {
156  userId: string;
157  email: string;
158  createdAt: Date;
159  requiresVerification: boolean;
160}
161
162// Error Contract - What can go wrong
163class CreateUserError extends BaseError {
164  constructor(message: string, code?: string, context?: Record<string, any>) {
165    super(message, code, context);
166    this.name = "CreateUserError";
167  }
168}
169```
170
171#### Self-Contained Command Implementation
172
173Commands are self-contained with all related types in the same module:
174
175```typescript
176export class CreateUserCommand implements OutputCommand<CreateUserInput, CreateUserOutput, CreateUserError> {
177  // Static metadata accessible before instantiation
178  static readonly metadata: CommandMetadata = {
179    name: 'CreateUserCommand',
180    description: 'Creates a new user account with email verification',
181    category: 'user',
182    inputType: 'CreateUserInput',
183    outputType: 'CreateUserOutput', 
184    errorType: 'CreateUserError',
185    version: '1.2.0',
186    contractVersion: '1.0',
187    dependencies: {
188      services: ['IDatabaseService', 'IEmailService'],
189      commands: [],
190      external: ['bcryptjs']
191    },
192    dataFlow: {
193      inputs: ['email', 'password', 'name'],
194      outputs: ['userId', 'email', 'createdAt', 'requiresVerification'],
195      sideEffects: ['database-write', 'email-send']
196    },
197    performance: {
198      expectedDuration: 'medium',
199      scaling: 'linear'
200    }
201  };
202
203  constructor(
204    public input?: CreateUserInput,
205    private logger?: ICommandLogger,
206    private services?: Record<string, any>
207  ) {
208    // Dependency injection of services
209    this.databaseService = services?.['IDatabaseService'];
210    this.emailService = services?.['IEmailService'];
211  }
212
213  validate(): void {
214    // Error-throwing validation with detailed feedback
215    if (!this.input) {
216      const error = new CreateUserError(
217        'Command input cannot be null or undefined',
218        'VALIDATION_ERROR'
219      );
220      error.setValidationError('input', 'input');
221      throw error;
222    }
223    
224    if (!this.input.email || !this.input.email.includes('@')) {
225      const error = new CreateUserError(
226        'Valid email address is required',
227        'VALIDATION_ERROR'
228      );
229      error.setValidationError('email', 'input.email');
230      throw error;
231    }
232  }
233
234  async execute(): Promise<CreateUserOutput> {
235    this.validate(); // Throws detailed errors if invalid
236    
237    // Business logic implementation
238    const hashedPassword = await this.hashPassword(this.input.password);
239    const user = await this.databaseService.createUser({
240      email: this.input.email,
241      passwordHash: hashedPassword,
242      name: this.input.name
243    });
244    
245    await this.emailService.sendVerificationEmail(user.email, user.verificationToken);
246    
247    return {
248      userId: user.id,
249      email: user.email,
250      createdAt: user.createdAt,
251      requiresVerification: true
252    };
253  }
254
255  getMetadata(): CommandMetadata {
256    return CreateUserCommand.metadata;
257  }
258}
259```
260
261### Validation Error Pattern
262
263Commands use error-throwing validation with detailed context:
264
265```typescript
266export class BaseError extends Error {
267  public readonly timestamp: Date;
268  public readonly code?: string;
269  public readonly context?: Record<string, any>;
270  
271  // Validation error properties
272  public invalidInput: boolean = false;
273  public invalidInputName: string = '';
274  public invalidInputPath: string = '';
275
276  constructor(message: string, code?: string, context?: Record<string, any>) {
277    super(message);
278    this.name = this.constructor.name;
279    this.timestamp = new Date();
280    this.code = code;
281    this.context = context;
282  }
283  
284  /**
285   * Mark this error as a validation error with specific input details
286   */
287  setValidationError(inputName: string, inputPath: string): this {
288    this.invalidInput = true;
289    this.invalidInputName = inputName;
290    this.invalidInputPath = inputPath;
291    return this;
292  }
293}
294```
295
296## Service Design & Portability
297
298### Service Portability Principle
299
300**CRITICAL**: Services must be portable across projects. They cannot depend on project-specific configuration classes. All dependencies must be injected through constructor parameters.
301
302**Why Portability Matters:**
303- **Cross-Project Reusability**: Services work in any project without modification
304- **Easier Testing**: Services can be tested in isolation with custom configurations
305- **Package Publishing**: Services can be published as reusable packages
306- **Configuration Independence**: Project config changes don't affect service code
307- **AI-Friendly Discovery**: Portable services with rich metadata enable intelligent selection
308
309### Service Configuration Pattern
310
311Every service defines its own configuration interface:
312
313```typescript
314// Service-specific configuration interface
315export interface CacheServiceConfig {
316  maxMemoryMB: number;
317  defaultTtlSeconds: number;
318  evictionPolicy: 'LRU' | 'LFU' | 'FIFO';
319  enableMetrics: boolean;
320}
321
322// Service interface with BaseService extension
323export interface ICacheService extends BaseService {
324  get<T>(key: string): T | null;
325  set<T>(key: string, value: T, ttlSeconds?: number): void;
326  delete(key: string): boolean;
327  flush(): void;
328  getStats(): CacheStats;
329}
330
331// Portable service implementation
332export class MemoryCacheService extends BaseService implements ICacheService {
333  constructor(
334    private config: CacheServiceConfig,    // Own config interface
335    private logger: ILogger,               // Interface dependency
336    private metricsService?: IMetricsService // Optional interface dependency
337  ) {
338    super();
339  }
340  
341  // Implementation uses this.config, never project-specific config
342  async set<T>(key: string, value: T, ttlSeconds?: number): Promise<void> {
343    const ttl = ttlSeconds || this.config.defaultTtlSeconds;
344    // Use service-specific configuration
345  }
346}
347```
348
349### Service Metadata Pattern
350
351Services include comprehensive metadata for AI-driven selection:
352
353```typescript
354interface ServiceMetadata {
355  name: string;                    // Unique service identifier
356  displayName: string;             // Human-readable name
357  description: string;             // Detailed capability description
358  contract: string;                // Interface name implemented
359  implementation: string;          // Implementation class name
360  version: string;                 // Service version
361  contractVersion: string;         // Interface version compatibility
362  features: string[];              // Key features and capabilities
363  limitations: string[];           // Known constraints
364  requirements: string[];          // External dependencies
365  recommendations: string[];       // Optimal use cases
366  dependencies: {
367    services: string[];            // Required service interfaces
368  };
369}
370```
371
372### Multiple Implementation Pattern
373
374Multiple services can implement the same contract with different characteristics:
375
376```typescript
377// Memory-based cache implementation
378export class MemoryCacheService extends BaseService implements ICacheService {
379  getMetadata(): ServiceMetadata {
380    return {
381      name: 'MemoryCacheService',
382      displayName: 'In-Memory Cache',
383      description: 'High-performance in-memory caching with TTL support',
384      contract: 'ICacheService',
385      implementation: 'MemoryCacheService',
386      version: '1.0.0',
387      contractVersion: '1.0',
388      features: ['In-memory storage', 'TTL expiration', 'Fast access'],
389      limitations: ['Memory-bound storage', 'Single-process scope'],
390      requirements: ['CacheServiceConfig', 'ILogger'],
391      recommendations: ['Development environments', 'Small datasets'],
392      dependencies: { services: ['IMetricsService'] }
393    };
394  }
395}
396
397// Redis-based cache implementation  
398export class RedisCacheService extends BaseService implements ICacheService {
399  getMetadata(): ServiceMetadata {
400    return {
401      name: 'RedisCacheService',
402      displayName: 'Redis Distributed Cache',
403      description: 'Distributed caching with Redis backend and clustering',
404      contract: 'ICacheService',
405      implementation: 'RedisCacheService',
406      version: '1.0.0',
407      contractVersion: '1.0',
408      features: ['Distributed caching', 'Data persistence', 'Clustering'],
409      limitations: ['Requires Redis server', 'Network latency'],
410      requirements: ['RedisCacheServiceConfig', 'ILogger', 'IRedisClient'],
411      recommendations: ['Production environments', 'Multi-instance applications'],
412      dependencies: { services: ['IRedisClient'] }
413    };
414  }
415}
416```
417
418## Registry & Discovery Patterns
419
420### ServiceRegistry for Configuration Mapping
421
422The ServiceRegistry enables service portability by mapping project-specific configuration into service-specific configuration interfaces:
423
424```typescript
425interface ServiceRegistry {
426  // Singleton access - Primary entry point
427  static getInstance(): ServiceRegistry;
428  
429  // Service management with configuration mapping
430  register<T>(serviceName: string, factory: () => T): void;
431  get<T>(serviceName: string): T;
432  
433  // Command registry access - THE ONLY CORRECT WAY
434  getCommandRegistry(): CommandRegistry;
435  
436  // Configuration and logging
437  getLogger(serviceName: string): ILogger;
438  getConfig(): AppConfig;
439}
440```
441
442### CommandRegistry for Discovery
443
444The CommandRegistry provides sophisticated command discovery and composition:
445
446```typescript
447interface CommandRegistry {
448  // Lazy loading with automatic service injection
449  get<T extends BaseCommand>(
450    commandClass: CommandConstructor, 
451    input?: any, 
452    logger?: ICommandLogger
453  ): Promise<T>;
454  
455  // Service integration (managed by ServiceRegistry)
456  setServiceResolver(resolver: (serviceName: string) => any): void;
457  
458  // Metadata-driven discovery
459  findByCategory(category: string): CommandMetadata[];
460  findByDependency(serviceName: string): CommandMetadata[];
461  findByDataFlow(inputType?: string, outputType?: string): CommandMetadata[];
462  
463  // Contract-based discovery for workflow composition
464  findNextCommands(producingCommandName: string): CommandMetadata[];
465  findPreviousCommands(consumingCommandName: string): CommandMetadata[];
466  findAlternativeCommands(commandName: string): CommandMetadata[];
467  
468  // Workflow composition
469  findWorkflowChains(startContract: string, endContract: string): WorkflowChain[];
470  getContractAnalysis(): ContractAnalysis;
471}
472```
473
474### Registry Access Patterns
475
476**CRITICAL**: There is only ONE correct way to access commands:
477
478#### Pattern 1: Constructor Injection (Frequent Command Users)
479```typescript
480// Services that frequently use commands receive CommandRegistry via constructor
481export class WorkflowManagerService extends BaseService {
482  constructor(
483    config: WorkflowManagerConfig,
484    logger: ILogger,
485    commandRegistry: CommandRegistry  // ✅ Injected by ServiceRegistry
486  ) {
487    super();
488    this.commandRegistry = commandRegistry;
489  }
490  
491  async processWorkflow(): Promise<void> {
492    // CommandRegistry readily available
493    const command = await this.commandRegistry.get(ProcessStepCommand, input);
494    await command.execute();
495  }
496}
497```
498
499#### Pattern 2: Runtime Access (Occasional Command Users)
500```typescript
501// Services that need commands receive CommandRegistry via constructor
502export class MonitorService extends BaseService {
503  constructor(
504    private config: MonitorServiceConfig,
505    private logger: ILogger,
506    private commandRegistry: CommandRegistry  // ✅ Injected by ServiceRegistry
507  ) {
508    super();
509  }
510  
511  private async analyzeMetrics(): Promise<any> {
512    // ✅ CORRECT: Use injected CommandRegistry
513    const command = await this.commandRegistry.get(AnalyzeMetricsCommand, input);
514    return await command.execute();
515  }
516}
517```
518
519#### ❌ NEVER DO THIS:
520```typescript
521// WRONG: Commands should not access ServiceRegistry directly
522const serviceRegistry = ServiceRegistry.getInstance();
523const commandRegistry = serviceRegistry.getCommandRegistry();
524
525// WRONG: Direct command instantiation bypasses registry
526const command = new SomeCommand();
527
528// WRONG: Commands calling registry during execution
529const command = await this.commandRegistry.get(SomeCommand, input);
530```
531
532## Dependency Injection Patterns
533
534### Service Dependencies
535
536Commands specify dependencies using service interface names in metadata:
537
538```typescript
539// ✅ CORRECT - Interface references
540static readonly metadata: CommandMetadata = {
541  dependencies: {
542    services: [
543      'IDatabaseService',    // Database operations
544      'ICacheService',       // Caching layer  
545      'IEmailService'        // Email notifications
546    ]
547  }
548};
549
550// ❌ INCORRECT - Concrete class or technology references
551static readonly metadata: CommandMetadata = {
552  dependencies: {
553    services: [
554      'DatabaseService',     // Don't reference concrete classes
555      'SQL Server',         // Don't use technology names
556      'Redis Cache'         // Don't reference specific implementations
557    ]
558  }
559};
560```
561
562### Command Dependencies
563
564Commands that use other commands declare them in metadata:
565
566```typescript
567export class WorkflowCommand {
568  static readonly metadata: CommandMetadata = {
569    name: 'UserRegistrationWorkflow',
570    dependencies: {
571      services: ['IDatabaseService'],
572      commands: ['user/CreateUserCommand', 'email/SendWelcomeEmailCommand']
573    }
574  };
575  
576  constructor(
577    public input?: WorkflowInput,
578    private logger?: ICommandLogger,
579    private services?: Record<string, any>,
580    private commands?: Record<string, any>  // ✅ Commands injected here
581  ) {
582    // Resolve command dependencies
583    this.createUserCommand = commands?.['user/CreateUserCommand'];
584    this.sendEmailCommand = commands?.['email/SendWelcomeEmailCommand'];
585  }
586  
587  async execute(): Promise<WorkflowOutput> {
588    // Use injected commands
589    const user = await this.createUserCommand.execute();
590    await this.sendEmailCommand.setInput({ userId: user.userId }).execute();
591    return { success: true, userId: user.userId };
592  }
593}
594```
595
596## Error Handling & Validation
597
598### Error Contract Design
599
600All command errors extend BaseError with validation capabilities:
601
602```typescript
603export class CreateUserError extends BaseError {
604  constructor(message: string, code?: string, context?: Record<string, any>) {
605    super(message, code, context);
606    this.name = "CreateUserError";
607  }
608}
609```
610
611### Validation Pattern
612
613Commands use error-throwing validation with detailed feedback:
614
615```typescript
616validate(): void {
617  if (!this.input?.email) {
618    const error = new CreateUserError(
619      'Email field is required and cannot be empty',
620      'VALIDATION_ERROR'
621    );
622    error.setValidationError('email', 'input.email');
623    throw error;
624  }
625  
626  if (this.input.password.length < 8) {
627    const error = new CreateUserError(
628      'Password must be at least 8 characters long',
629      'VALIDATION_ERROR'
630    );
631    error.setValidationError('password', 'input.password');
632    throw error;
633  }
634}
635```
636
637## Workflow Composition
638
639### Sequential Workflows
640
641Commands can be composed into sequential workflows:
642
643```typescript
644export class VideoProcessingWorkflow {
645  async execute(input: VideoInput): Promise<VideoOutput> {
646    const serviceRegistry = ServiceRegistry.getInstance();
647    const commandRegistry = serviceRegistry.getCommandRegistry();
648    
649    // Step 1: Extract metadata
650    const metadataCommand = await commandRegistry.get(
651      ExtractMetadataCommand, 
652      { videoUrl: input.url }
653    );
654    const metadata = await metadataCommand.execute();
655    
656    // Step 2: Process audio (using output from step 1)
657    const audioCommand = await commandRegistry.get(
658      ProcessAudioCommand,
659      { videoId: metadata.videoId }
660    );
661    const audio = await audioCommand.execute();
662    
663    // Step 3: Generate summary (using outputs from steps 1 & 2)
664    const summaryCommand = await commandRegistry.get(
665      GenerateSummaryCommand,
666      { title: metadata.title, transcript: audio.transcript }
667    );
668    const summary = await summaryCommand.execute();
669    
670    return { summary: summary.text, metadata };
671  }
672}
673```
674
675### Parallel Workflows
676
677Commands can execute in parallel for performance:
678
679```typescript
680export class ParallelProcessingWorkflow {
681  async execute(input: ProcessingInput): Promise<ProcessingOutput> {
682    // Execute multiple commands in parallel
683    const [validation, enrichment, analysis] = await Promise.all([
684      this.validateData(input.data),
685      this.enrichData(input.data), 
686      this.analyzeData(input.data)
687    ]);
688    
689    return this.combineResults(validation, enrichment, analysis);
690  }
691}
692```
693
694## AI-Driven Selection
695
696### Service Selection by AI
697
698AI agents use service metadata to select optimal implementations:
699
700```typescript
701function selectOptimalCacheService(useCase: string): string {
702  const serviceRegistry = ServiceRegistry.getInstance();
703  
704  // Find all cache implementations
705  const cacheServices = serviceRegistry.findServicesByContract('ICacheService');
706  
707  // AI analyzes metadata to choose optimal implementation
708  // Based on: features, limitations, recommendations, performance
709  for (const service of cacheServices) {
710    const metadata = service.getMetadata();
711    if (metadata.recommendations.includes(useCase)) {
712      return metadata.name;
713    }
714  }
715  
716  return cacheServices[0].name; // Fallback
717}
718```
719
720### Command Discovery by AI
721
722AI agents discover commands through metadata analysis:
723
724```typescript
725function findOptimalWorkflow(startType: string, endType: string): CommandMetadata[] {
726  const serviceRegistry = ServiceRegistry.getInstance();
727  const commandRegistry = serviceRegistry.getCommandRegistry();
728  
729  // Find possible workflow chains
730  const workflows = commandRegistry.findWorkflowChains(startType, endType);
731  
732  // AI selects optimal based on performance, complexity, dependencies
733  return workflows
734    .sort((a, b) => a.complexity - b.complexity)
735    .map(w => w.commands)[0];
736}
737```
738
739### Contract Analysis
740
741The registry provides contract analysis for intelligent composition:
742
743```typescript
744interface ContractAnalysis {
745  availableInputTypes: string[];
746  availableOutputTypes: string[];
747  possibleChains: WorkflowChain[];
748  orphanedCommands: CommandMetadata[];
749  circularDependencies: string[];
750}
751```
752
753## Design Best Practices
754
755### Command Design Principles
756
7571. **Static Metadata**: Always provide static metadata accessible before instantiation
7582. **Self-Contained**: Keep all command-related types in the same module
7593. **Interface Dependencies**: Use service interfaces, never concrete implementations
7604. **Contract Naming**: Use domain-focused names, not platform-specific ones
7615. **Error Handling**: Extend BaseError for all command-specific errors
7626. **Validation**: Use error-throwing validation with detailed context
763
764### Service Design Principles
765
7661. **Rich Metadata**: Provide comprehensive metadata for AI-driven selection
7672. **Clear Recommendations**: Specify optimal use cases and environments
7683. **Honest Limitations**: Document constraints and boundaries clearly
7694. **Version Compatibility**: Track both service and contract versions
7705. **Feature Clarity**: List specific capabilities, not vague descriptions
7716. **Portability**: Never depend on project-specific configuration classes
772
773### Registry Integration Principles
774
7751. **Single Access Path**: Commands and services access dependencies through constructor injection
7762. **Configuration Mapping**: ServiceRegistry maps project config to service-specific config interfaces
7773. **Category Organization**: Group commands by functional categories
7784. **Dependency Analysis**: Use registry to validate service availability
7795. **Workflow Discovery**: Leverage registry for automatic workflow construction
780
781## Presentation Layer Integration
782
783### Lightweight Implementation Principle
784
785Presentation layers (API routes, web page handlers, UI components) should act as thin orchestration layers that delegate business logic to Services and Commands. These components focus on:
786
787- **Request/Response Handling**: Accept input data and format responses
788- **Input Validation**: Basic format and presence validation
789- **Service Orchestration**: Delegate business operations to services
790- **Error Translation**: Convert service/command errors to appropriate presentation formats
791- **Cross-cutting Concerns**: Handle logging, monitoring, security, caching through service layer
792
793### Service-First vs Command-First Usage
794
795The micro-block pattern supports two valid orchestration approaches:
796
797#### Service-First Approach
798```typescript
799// Presentation Layer → Service → Commands
800export async function handleUserRegistration(requestData: any): Promise<any> {
801  // Lightweight orchestration layer
802  const securityService = serviceRegistry.get<ISecurityService>('ISecurityService');
803  const result = await securityService.registerUser(
804    requestData, 
805    baseUrl, 
806    requestContext
807  );
808  
809  return {
810    success: true,
811    message: result.message,
812    user: result.user
813  };
814}
815```
816
817**When to use Service-First:**
818- Cross-cutting concerns (security, caching, monitoring)
819- Operations requiring service-level coordination
820- Business operations needing multiple service interactions
821
822#### Command-First Approach
823```typescript
824// Presentation Layer → Commands directly
825export async function handleSimpleOperation(requestData: any): Promise<any> {
826  const serviceRegistry = ServiceRegistry.getInstance();
827  const commandRegistry = serviceRegistry.getCommandRegistry();
828  
829  const command = await commandRegistry.get<SimpleCommand>(
830    SimpleCommand, 
831    requestData
832  );
833  const result = await command.execute();
834  
835  return {
836    success: true,
837    data: result
838  };
839}
840```
841
842**When to use Command-First:**
843- Workflow commands
844- Self-contained business operations
845- Direct data retrieval/manipulation
846- Operations with no cross-cutting concerns
847
848### Service Orchestration Patterns
849
850Services provide valuable abstraction for:
851
852#### Cross-Cutting Concerns
853```typescript
854export class SecurityService extends BaseService {
855  async registerUser(userData: any, baseUrl: string, context: SecurityContext): Promise<any> {
856    // Rate limiting (cross-cutting concern)
857    await this.checkRateLimit(context.ip, 'user-registration');
858    
859    // Business logic delegation to commands
860    const createUserCommand = await this.commandRegistry.get<CreateUserCommand>(
861      CreateUserCommand, userData
862    );
863    const userResult = await createUserCommand.execute();
864    
865    // Email sending (cross-cutting concern)
866    const emailCommand = await this.commandRegistry.get<SendVerificationEmailCommand>(
867      SendVerificationEmailCommand, 
868      { email: userResult.email, baseUrl }
869    );
870    await emailCommand.execute();
871    
872    // Monitoring (cross-cutting concern)
873    this.monitorService.logUserEvent('user-registered', userResult.userId, context);
874    
875    return userResult;
876  }
877}
878```
879
880#### Workflow Coordination
881```typescript
882export class WorkflowService extends BaseService {
883  async processComplexWorkflow(input: WorkflowInput): Promise<WorkflowOutput> {
884    // Sequential command execution with error handling
885    const step1Result = await this.executeCommand(ValidateDataCommand, input.data);
886    const step2Result = await this.executeCommand(TransformDataCommand, step1Result);
887    const step3Result = await this.executeCommand(PersistDataCommand, step2Result);
888    
889    // Parallel command execution
890    const [notification, audit] = await Promise.all([
891      this.executeCommand(SendNotificationCommand, step3Result),
892      this.executeCommand(CreateAuditLogCommand, { workflow: 'complex', result: step3Result })
893    ]);
894    
895    return {
896      success: true,
897      dataId: step3Result.id,
898      notificationSent: notification.sent,
899      auditCreated: audit.created
900    };
901  }
902  
903  private async executeCommand<T>(CommandClass: any, input: any): Promise<T> {
904    const command = await this.commandRegistry.get<T>(CommandClass, input);
905    return await command.execute();
906  }
907}
908```
909
910### Error Handling in Presentation Layers
911
912```typescript
913export async function handleRequest(requestData: any): Promise<any> {
914  try {
915    const result = await businessService.performOperation(requestData);
916    return {
917      success: true,
918      data: result
919    };
920  } catch (error: any) {
921    // Translate service/command errors to presentation format
922    if (error.invalidInput) {
923      return {
924        success: false,
925        error: 'VALIDATION_ERROR',
926        message: error.message,
927        field: error.invalidInputName
928      };
929    }
930    
931    if (error.code === 'RATE_LIMIT_EXCEEDED') {
932      return {
933        success: false,
934        error: 'RATE_LIMITED',
935        message: 'Too many requests, please try again later',
936        retryAfter: error.context?.retryAfter
937      };
938    }
939    
940    // Generic error fallback
941    return {
942      success: false,
943      error: 'INTERNAL_ERROR',
944      message: 'An unexpected error occurred'
945    };
946  }
947}
948```
949
950## Implementation Guidelines
951
952The Micro-Block Design Pattern is technology-agnostic and can be implemented in various languages and frameworks. The key is maintaining the core principles:
953
954### Essential Elements
955
956- **Contract-first design** with explicit Input/Output/Error interfaces
957- **Rich metadata** for AI-driven discovery and composition
958- **Dependency injection** using service interfaces
959- **Registry-based discovery** for commands and services
960- **Self-contained modularity** with clear boundaries
961- **Error-throwing validation** with detailed context
962- **Service portability** through configuration interfaces
963
964### Implementation Considerations
965
966- **Technology Stack**: Pattern works with any OOP language with interfaces/abstract classes
967- **Serialization**: Metadata should be serializable for cross-process discovery
968- **Performance**: Lazy loading and caching for production performance
969- **Testing**: Mock services through registry for clean unit testing
970- **Documentation**: Rich metadata serves as living documentation
971
972This design pattern creates a robust foundation for AI-collaborative development where components are discoverable, composable, and properly abstracted through well-defined contracts. The comprehensive metadata system enables AI to make informed decisions about component selection and composition while maintaining clear dependency tracking and automatic registration.

Metadata

Path
utaba/main/patterns/micro-block/micro-block-pattern.md
Namespace
utaba/main/patterns/micro-block
Author
utaba
Category
patterns
Contract Version
3.0.1
MIME Type
text/markdown
Published
22-Jul-2025
Last Updated
22-Jul-2025