micro-block-quick-reference.md
Ultra-concise quick reference for micro-block patterns with corrected workflow composition showing proper command dependency injection
micro-block-quick-reference.mdv1.1.06.3 KB
micro-block-quick-reference.md(markdown)
1# Micro-Block Quick Reference Card
2
3*Essential patterns for AI developers - minimal context version*
4
5## ๐๏ธ Command Template
6
7```typescript
8export interface MyInput { field: string; }
9export interface MyOutput { result: string; }
10export class MyError extends BaseError {}
11
12export class MyCommand extends OutputCommand<MyInput, MyOutput, MyError> {
13 private dbService: IDatabaseService;
14
15 static readonly metadata: CommandMetadata = {
16 name: "MyCommand",
17 category: "folder-name", // MUST match parent folder
18 inputType: "MyInput",
19 outputType: "MyOutput",
20 errorType: "MyError",
21 version: "1.0.0",
22 contractVersion: "1.0.0",
23 dependencies: {
24 services: ["IDatabaseService", "ICacheService"],
25 commands: ["user/CreateUserCommand"],
26 external: ["bcryptjs", "uuid"]
27 }
28 };
29
30 constructor(
31 input?: MyInput,
32 private logger?: any,
33 private services?: Record<string, any>,
34 private commands?: Record<string, any>
35 ) {
36 super();
37 if (input) this.setInput(input);
38
39 // Services injected via constructor based on metadata
40 this.dbService = services?.['IDatabaseService'];
41 if (!this.dbService) {
42 throw new MyError('IDatabaseService required', 'MISSING_SERVICE');
43 }
44 }
45
46 validate(): void { /* throw errors */ }
47 async execute(): Promise<MyOutput> { /* business logic */ }
48 getMetadata() { return MyCommand.metadata; }
49}
50```
51
52## ๐จ Critical Rules
53
54### Command Access
55```typescript
56// โ NEVER
57const cmd = new MyCommand();
58
59// โ
ALWAYS
60const serviceRegistry = ServiceRegistry.getInstance();
61const commandRegistry = serviceRegistry.getCommandRegistry();
62const cmd = await commandRegistry.get(MyCommand, input);
63```
64
65### Service Dependencies
66```typescript
67// โ
CORRECT: Services injected via constructor based on metadata
68constructor(
69 input?: MyInput,
70 logger?: any,
71 private services?: Record<string, any> // Services injected here
72) {
73 this.dbService = services?.['IDatabaseService'];
74 this.cacheService = services?.['ICacheService'];
75
76 // Validate required services
77 if (!this.dbService) {
78 throw new MyError('IDatabaseService required', 'MISSING_SERVICE');
79 }
80}
81
82// โ WRONG: Commands should NOT directly call ServiceRegistry
83const serviceRegistry = ServiceRegistry.getInstance();
84this.dbService = serviceRegistry.get<IDatabaseService>('IDatabaseService');
85```
86
87### Metadata Requirements
88- `category` = parent folder name exactly
89- Declare ALL dependencies in `metadata.dependencies`
90- Use interface names: `"IDatabaseService"` not `"DatabaseService"`
91- Services auto-injected via constructor based on declared dependencies
92- Commands get other commands via `commands` parameter
93
94## ๐ง Service Pattern
95
96```typescript
97// Service config interface
98export interface MyServiceConfig {
99 connectionString: string;
100 timeout: number;
101}
102
103// Service implementation
104export class MyService extends BaseService implements IMyService {
105 constructor(
106 private config: MyServiceConfig, // Own config interface
107 private logger: ILogger
108 ) { super(); }
109
110 getMetadata(): ServiceMetadata {
111 return {
112 name: 'MyService',
113 contract: 'IMyService',
114 version: '1.0.0',
115 features: ['Feature1', 'Feature2'],
116 limitations: ['Limitation1'],
117 recommendations: ['Use case 1', 'Use case 2'],
118 dependencies: {
119 services: ['ILogger', 'IMetricsService']
120 }
121 };
122 }
123}
124```
125
126## ๐ Registry Registration
127
128```typescript
129// In ServiceRegistry.initialize()
130this.register('IMyService', () => {
131 const serviceConfig: MyServiceConfig = {
132 connectionString: this.config.database.connectionString,
133 timeout: this.config.database.timeout
134 };
135 return new MyService(serviceConfig, this.getLogger('MyService'));
136});
137```
138
139## โก Workflow Composition
140
141```typescript
142export class WorkflowCommand extends OutputCommand<WorkflowInput, WorkflowOutput, WorkflowError> {
143 private step1Command: Step1Command;
144 private step2Command: Step2Command;
145
146 static readonly metadata: CommandMetadata = {
147 name: "WorkflowCommand",
148 category: "workflow",
149 inputType: "WorkflowInput",
150 outputType: "WorkflowOutput",
151 errorType: "WorkflowError",
152 version: "1.0.0",
153 contractVersion: "1.0.0",
154 dependencies: {
155 services: ["ILogger"],
156 commands: ["user/Step1Command", "user/Step2Command"], // Define command dependencies
157 external: []
158 }
159 };
160
161 constructor(
162 input?: WorkflowInput,
163 private logger?: any,
164 private services?: Record<string, any>,
165 private commands?: Record<string, any> // Commands injected here
166 ) {
167 super();
168 if (input) this.setInput(input);
169
170 // Verify injected commands
171 this.step1Command = commands?.['user/Step1Command'];
172 this.step2Command = commands?.['user/Step2Command'];
173
174 if (!this.step1Command || !this.step2Command) {
175 throw new WorkflowError('Required commands not injected', 'MISSING_COMMANDS');
176 }
177 }
178
179 async execute(): Promise<WorkflowOutput> {
180 // Use injected commands - they're already instantiated and ready
181 const result1 = await this.step1Command.execute();
182 const result2 = await this.step2Command.execute();
183
184 return { combinedResult: result1.data + result2.data };
185 }
186}
187```
188
189## ๐งช Testing Pattern
190
191```typescript
192describe('MyCommand', () => {
193 beforeEach(() => {
194 // Mock ServiceRegistry if needed
195 vi.mock('@/core/registry/ServiceRegistry', () => ({
196 ServiceRegistry: {
197 getInstance: () => ({ get: vi.fn().mockReturnValue(mockService) })
198 }
199 }));
200 });
201
202 it('validates input', () => {
203 const cmd = new MyCommand(validInput);
204 expect(() => cmd.validate()).not.toThrow();
205 });
206});
207```
208
209## ๐ฏ Key Principles
210
211- **Commands**: Single responsibility, explicit contracts
212- **Services**: Portable, own config interfaces
213- **Registry**: Single access point via ServiceRegistry
214- **Validation**: Throw errors with details
215- **Metadata**: Rich, discoverable information
216- **Composition**: Commands orchestrate other commands via dependency injection
217
218## โ Common Mistakes
219
220- Direct command instantiation: `new MyCommand()`
221- Commands calling ServiceRegistry directly
222- Commands requesting other commands from registry during execution
223- Missing category/folder alignment
224- Concrete service references in dependencies
225- Missing metadata dependency declarations
226- Project-specific config in services
Metadata
- Path
- utaba/main/patterns/micro-block/micro-block-quick-reference.md
- Namespace
- utaba/main/patterns/micro-block
- Author
- utaba
- Category
- patterns
- Technology
- design-pattern
- Contract Version
- 1.1.0
- MIME Type
- text/markdown
- Published
- 18-Jul-2025
- Last Updated
- 18-Jul-2025