contract-first-development.md
Comprehensive patterns for contract-first development in micro-block architecture with TypeScript interfaces and validation
contract-first-development.mdv1.0.015.4 KB
contract-first-development.md(markdown)
1# Contract-First Development Patterns
2
3## Overview
4
5Contract-First Development is a foundational principle of micro-block architecture where all interfaces, types, and contracts are defined before implementation. This enables AI agents to understand, compose, and substitute components safely.
6
7## Core Principles
8
91. **Define Before Implement**: Always define contracts before writing implementation code
102. **Explicit Contracts**: All inputs, outputs, and errors must have explicit TypeScript interfaces
113. **Version Compatibility**: Track both implementation and contract versions separately
124. **Self-Documenting**: Contracts serve as living documentation
135. **AI-Readable**: Rich metadata enables AI understanding and composition
14
15## Contract Definition Process
16
17### 1. Input Contract Design
18
19Define what data the command accepts:
20
21```typescript
22/**
23 * Input contract for creating a new user account
24 */
25interface CreateUserInput {
26 /** User's email address (must be valid email format) */
27 email: string;
28
29 /** User's password (minimum 8 characters) */
30 password: string;
31
32 /** User's display name */
33 name: string;
34
35 /** Optional user profile information */
36 profile?: {
37 firstName?: string;
38 lastName?: string;
39 bio?: string;
40 avatarUrl?: string;
41 };
42
43 /** Optional user preferences */
44 preferences?: {
45 emailNotifications: boolean;
46 language: string;
47 timezone: string;
48 };
49
50 /** Optional metadata tags */
51 tags?: string[];
52}
53```
54
55### 2. Output Contract Design
56
57Define what data the command returns:
58
59```typescript
60/**
61 * Output contract for user creation result
62 */
63interface CreateUserOutput {
64 /** Unique identifier for the created user */
65 userId: string;
66
67 /** User's email address */
68 email: string;
69
70 /** User's display name */
71 name: string;
72
73 /** Timestamp when user was created */
74 createdAt: Date;
75
76 /** User's initial status */
77 status: 'active' | 'pending' | 'suspended';
78
79 /** Whether email verification is required */
80 emailVerificationRequired: boolean;
81
82 /** Links to related resources */
83 links: {
84 profile: string;
85 preferences: string;
86 avatar?: string;
87 };
88}
89```
90
91### 3. Error Contract Design
92
93Define specific error types with detailed information:
94
95```typescript
96/**
97 * Error contract for user creation failures
98 */
99class CreateUserError extends BaseError {
100 constructor(message: string, code?: string, details?: Record<string, any>) {
101 super(message, code, details);
102 Object.setPrototypeOf(this, CreateUserError.prototype);
103 this.name = "CreateUserError";
104 }
105
106 /** Create validation error for invalid email */
107 static invalidEmail(email: string): CreateUserError {
108 const error = new CreateUserError(
109 'Email must be a valid email address format',
110 'INVALID_EMAIL'
111 );
112 error.setValidationError('email', 'input.email');
113 return error;
114 }
115
116 /** Create error for password requirements */
117 static weakPassword(requirements: string[]): CreateUserError {
118 const error = new CreateUserError(
119 `Password must meet requirements: ${requirements.join(', ')}`,
120 'WEAK_PASSWORD',
121 { requirements }
122 );
123 error.setValidationError('password', 'input.password');
124 return error;
125 }
126
127 /** Create error for duplicate email */
128 static emailExists(email: string): CreateUserError {
129 return new CreateUserError(
130 'A user with this email address already exists',
131 'EMAIL_EXISTS',
132 { email }
133 );
134 }
135}
136```
137
138## Service Contract Patterns
139
140### Service Interface Definition
141
142```typescript
143/**
144 * Database service contract for data persistence operations
145 */
146interface IDatabaseService extends BaseService {
147 /**
148 * Execute a query and return results
149 * @param query SQL query string with parameter placeholders
150 * @param params Parameters for the query
151 * @returns Array of result objects
152 */
153 query<T = any>(query: string, params?: Record<string, any>): Promise<T[]>;
154
155 /**
156 * Execute a command (INSERT, UPDATE, DELETE)
157 * @param command SQL command string with parameter placeholders
158 * @param params Parameters for the command
159 * @returns Number of affected rows
160 */
161 execute(command: string, params?: Record<string, any>): Promise<number>;
162
163 /**
164 * Execute multiple operations in a transaction
165 * @param operations Function containing operations to execute
166 * @returns Result of the transaction function
167 */
168 transaction<T>(operations: (tx: ITransactionContext) => Promise<T>): Promise<T>;
169
170 /**
171 * Check if the database connection is healthy
172 * @returns True if connection is working
173 */
174 isHealthy(): Promise<boolean>;
175
176 /**
177 * Get database connection statistics
178 * @returns Connection and performance statistics
179 */
180 getStats(): Promise<DatabaseStats>;
181}
182
183/**
184 * Configuration contract for database service
185 */
186interface DatabaseServiceConfig {
187 /** Database connection string */
188 connectionString: string;
189
190 /** Maximum number of concurrent connections */
191 maxConnections: number;
192
193 /** Connection timeout in milliseconds */
194 connectionTimeout: number;
195
196 /** Number of retry attempts for failed connections */
197 retryAttempts: number;
198
199 /** Whether to enable connection health monitoring */
200 enableHealthMonitoring: boolean;
201
202 /** Query timeout in milliseconds */
203 queryTimeout: number;
204}
205
206/**
207 * Statistics contract for database service
208 */
209interface DatabaseStats {
210 /** Number of active connections */
211 activeConnections: number;
212
213 /** Total number of queries executed */
214 totalQueries: number;
215
216 /** Average query execution time in milliseconds */
217 averageQueryTime: number;
218
219 /** Number of failed queries */
220 failedQueries: number;
221
222 /** Last health check timestamp */
223 lastHealthCheck: Date;
224
225 /** Whether the service is currently healthy */
226 isHealthy: boolean;
227}
228```
229
230### Service Metadata Contract
231
232```typescript
233/**
234 * Metadata contract for service discovery and selection
235 */
236interface ServiceMetadata {
237 /** Unique service identifier */
238 name: string;
239
240 /** Human-readable display name */
241 displayName: string;
242
243 /** Detailed description of service capabilities */
244 description: string;
245
246 /** Interface contract this service implements */
247 contract: string;
248
249 /** Implementation class name */
250 implementation: string;
251
252 /** Service implementation version */
253 version: string;
254
255 /** Contract version compatibility */
256 contractVersion: string;
257
258 /** Key features and capabilities */
259 features: string[];
260
261 /** Known limitations or constraints */
262 limitations: string[];
263
264 /** External dependencies required */
265 requirements: string[];
266
267 /** Optimal use cases and environments */
268 recommendations: string[];
269
270 /** Service dependencies */
271 dependencies: {
272 /** Required service interfaces */
273 services: string[];
274 };
275
276 /** Performance characteristics */
277 performance?: {
278 /** Expected response time category */
279 responseTime: 'fast' | 'moderate' | 'slow';
280
281 /** Throughput characteristics */
282 throughput: 'high' | 'moderate' | 'low';
283
284 /** Resource usage profile */
285 resourceUsage: 'light' | 'moderate' | 'heavy';
286 };
287
288 /** Deployment characteristics */
289 deployment?: {
290 /** Deployment complexity */
291 complexity: 'simple' | 'moderate' | 'complex';
292
293 /** Infrastructure requirements */
294 infrastructure: string[];
295
296 /** Configuration requirements */
297 configuration: string[];
298 };
299}
300```
301
302## Command Contract Patterns
303
304### Command Metadata Contract
305
306```typescript
307/**
308 * Metadata contract for command discovery and composition
309 */
310interface CommandMetadata {
311 /** Unique command identifier */
312 name: string;
313
314 /** Human-readable description */
315 description: string;
316
317 /** Functional category for organization */
318 category: string;
319
320 /** Input contract type name */
321 inputType: string;
322
323 /** Output contract type name */
324 outputType: string;
325
326 /** Error contract type name */
327 errorType: string;
328
329 /** Command implementation version */
330 version: string;
331
332 /** Input/output contract version */
333 contractVersion: string;
334
335 /** Required permissions */
336 permissions?: string[];
337
338 /** Execution timeout in milliseconds */
339 timeout?: number;
340
341 /** Data flow specification */
342 dataFlow?: {
343 /** Input data fields */
344 inputs: string[];
345
346 /** Output data fields */
347 outputs: string[];
348
349 /** Side effects performed */
350 sideEffects: string[];
351 };
352
353 /** Performance characteristics */
354 performance?: {
355 /** Expected execution duration */
356 expectedDuration: string;
357
358 /** Performance scaling characteristics */
359 scaling: string;
360 };
361
362 /** Dependency specification */
363 dependencies?: {
364 /** Service dependencies (e.g., IDatabaseService) */
365 services?: string[];
366
367 /** Command dependencies (e.g., ValidateUserCommand) */
368 commands?: string[];
369
370 /** External package dependencies (e.g., bcrypt, validator) */
371 external?: string[];
372 };
373
374 /** AI composition hints */
375 composition?: {
376 /** Commands that commonly precede this one */
377 precedingCommands?: string[];
378
379 /** Commands that commonly follow this one */
380 followingCommands?: string[];
381
382 /** Alternative commands with similar functionality */
383 alternatives?: string[];
384 };
385}
386```
387
388## Contract Evolution Patterns
389
390### Version Compatibility
391
392```typescript
393/**
394 * Contract versioning follows semantic versioning principles
395 */
396
397// Version 1.0 - Initial contract
398interface CreateUserInputV1 {
399 email: string;
400 password: string;
401 name: string;
402}
403
404// Version 1.1 - Backward compatible addition
405interface CreateUserInputV1_1 {
406 email: string;
407 password: string;
408 name: string;
409 profile?: UserProfile; // Optional addition - backward compatible
410}
411
412// Version 2.0 - Breaking change
413interface CreateUserInputV2 {
414 email: string;
415 password: string;
416 fullName: string; // Breaking: 'name' renamed to 'fullName'
417 profile: UserProfile; // Breaking: 'profile' now required
418}
419```
420
421### Contract Migration
422
423```typescript
424/**
425 * Contract migration utilities for handling version changes
426 */
427class ContractMigrator {
428 /**
429 * Migrate input from older version to current version
430 */
431 static migrateCreateUserInput(input: any, fromVersion: string): CreateUserInput {
432 switch (fromVersion) {
433 case '1.0':
434 return {
435 email: input.email,
436 password: input.password,
437 name: input.name,
438 profile: undefined // Optional in v1.1+
439 };
440
441 case '1.1':
442 return input; // Already compatible
443
444 default:
445 throw new Error(`Unsupported contract version: ${fromVersion}`);
446 }
447 }
448}
449```
450
451## Contract Validation Patterns
452
453### Runtime Contract Validation
454
455```typescript
456/**
457 * Contract validation utilities
458 */
459class ContractValidator {
460 /**
461 * Validate input against contract
462 */
463 static validateCreateUserInput(input: any): CreateUserInput {
464 if (!input || typeof input !== 'object') {
465 throw new CreateUserError('Input must be an object', 'INVALID_INPUT');
466 }
467
468 if (!input.email || typeof input.email !== 'string') {
469 throw CreateUserError.invalidEmail(input.email);
470 }
471
472 if (!input.password || typeof input.password !== 'string') {
473 throw CreateUserError.weakPassword(['Must be a string']);
474 }
475
476 if (!input.name || typeof input.name !== 'string') {
477 throw new CreateUserError('Name is required and must be a string', 'INVALID_NAME');
478 }
479
480 return input as CreateUserInput;
481 }
482
483 /**
484 * Validate output against contract
485 */
486 static validateCreateUserOutput(output: any): CreateUserOutput {
487 if (!output || typeof output !== 'object') {
488 throw new Error('Output must be an object');
489 }
490
491 const required = ['userId', 'email', 'name', 'createdAt', 'status'];
492 for (const field of required) {
493 if (!(field in output)) {
494 throw new Error(`Output missing required field: ${field}`);
495 }
496 }
497
498 return output as CreateUserOutput;
499 }
500}
501```
502
503## Contract Testing Patterns
504
505### Contract Compliance Testing
506
507```typescript
508describe('CreateUserCommand Contract Compliance', () => {
509 it('should accept valid input contract', () => {
510 const validInput: CreateUserInput = {
511 email: 'test@example.com',
512 password: 'securePassword123',
513 name: 'Test User'
514 };
515
516 expect(() => ContractValidator.validateCreateUserInput(validInput)).not.toThrow();
517 });
518
519 it('should reject invalid input contract', () => {
520 const invalidInput = {
521 email: 123, // Should be string
522 password: 'password',
523 // name missing
524 };
525
526 expect(() => ContractValidator.validateCreateUserInput(invalidInput)).toThrow();
527 });
528
529 it('should return valid output contract', async () => {
530 const command = new CreateUserCommand(validInput, logger, services);
531 const output = await command.execute();
532
533 expect(() => ContractValidator.validateCreateUserOutput(output)).not.toThrow();
534 expect(output.userId).toBeDefined();
535 expect(output.email).toBe(validInput.email);
536 expect(output.createdAt).toBeInstanceOf(Date);
537 });
538});
539```
540
541### Interface Compliance Testing
542
543```typescript
544describe('Service Contract Compliance', () => {
545 it('should implement IDatabaseService interface', () => {
546 const service = new DatabaseService(config, logger);
547
548 // Verify method signatures
549 expect(typeof service.query).toBe('function');
550 expect(typeof service.execute).toBe('function');
551 expect(typeof service.transaction).toBe('function');
552 expect(typeof service.isHealthy).toBe('function');
553
554 // Verify method arity (parameter count)
555 expect(service.query.length).toBe(2); // query, params
556 expect(service.execute.length).toBe(2); // command, params
557 expect(service.transaction.length).toBe(1); // operations
558 expect(service.isHealthy.length).toBe(0); // no parameters
559 });
560});
561```
562
563## Best Practices
564
565### Contract Design
5661. **Start with Contracts**: Define all interfaces before implementation
5672. **Rich Documentation**: Include detailed comments in contract definitions
5683. **Specific Types**: Use specific types instead of `any` or `unknown`
5694. **Optional vs Required**: Carefully consider which fields are optional
5705. **Future-Proofing**: Design contracts to allow backward-compatible evolution
571
572### Version Management
5731. **Semantic Versioning**: Follow semver for contract versions
5742. **Migration Support**: Provide migration utilities for breaking changes
5753. **Deprecation Notices**: Mark deprecated fields with clear alternatives
5764. **Compatibility Matrix**: Document which versions work together
5775. **Gradual Migration**: Support multiple versions during transition periods
578
579### Validation Strategy
5801. **Early Validation**: Validate contracts at command entry points
5812. **Comprehensive Testing**: Test all contract variations
5823. **Error Clarity**: Provide clear error messages for contract violations
5834. **Runtime Checks**: Include runtime validation for dynamic scenarios
5845. **Type Safety**: Use TypeScript's type system for compile-time validation
585
586### AI Enablement
5871. **Rich Metadata**: Include comprehensive metadata for AI understanding
5882. **Composition Hints**: Provide guidance for command composition
5893. **Alternative Options**: Document alternative commands with similar contracts
5904. **Performance Characteristics**: Include performance expectations
5915. **Usage Examples**: Provide examples of contract usage
592
593Contract-first development ensures that micro-block components have clear, well-defined interfaces that enable safe composition, substitution, and AI-driven selection while maintaining type safety and runtime validation.
Metadata
- Path
- utaba/main/patterns/micro-block/contract-first-development.md
- Namespace
- utaba/main/patterns/micro-block
- Author
- utaba
- Category
- patterns
- Technology
- typescript
- Contract Version
- 1.0.0
- MIME Type
- text/markdown
- Published
- 18-Jul-2025
- Last Updated
- 18-Jul-2025