@mytechtoday/augment-extensions 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +35 -3
- package/README.md +3 -3
- package/augment-extensions/domain-rules/software-architecture/README.md +143 -0
- package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -0
- package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -0
- package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -0
- package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -0
- package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -0
- package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -0
- package/augment-extensions/domain-rules/software-architecture/module.json +119 -0
- package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -0
- package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -0
- package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -0
- package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -0
- package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -0
- package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -0
- package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -0
- package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -0
- package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -0
- package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -0
- package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -0
- package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -0
- package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -0
- package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -0
- package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -0
- package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -0
- package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -0
- package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -0
- package/augment-extensions/workflows/beads/examples/complete-workflow-example.md +8 -8
- package/augment-extensions/workflows/beads/rules/best-practices.md +2 -2
- package/augment-extensions/workflows/beads/rules/file-format.md +4 -4
- package/augment-extensions/workflows/beads/rules/manual-setup.md +4 -4
- package/augment-extensions/workflows/beads/rules/workflow.md +3 -3
- package/modules.md +40 -3
- package/package.json +1 -1
|
@@ -0,0 +1,1381 @@
|
|
|
1
|
+
# Architecture Evaluation and Testing
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document covers architecture evaluation methods including ATAM (Architecture Tradeoff Analysis Method), chaos engineering, architecture reviews, and testing strategies for validating architectural decisions.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Knowledge
|
|
10
|
+
|
|
11
|
+
### ATAM (Architecture Tradeoff Analysis Method)
|
|
12
|
+
|
|
13
|
+
**What is ATAM?**
|
|
14
|
+
- Systematic method for evaluating software architectures
|
|
15
|
+
- Developed by Software Engineering Institute (SEI)
|
|
16
|
+
- Focuses on quality attribute tradeoffs
|
|
17
|
+
- Identifies architectural risks and sensitivity points
|
|
18
|
+
- Stakeholder-centric evaluation
|
|
19
|
+
|
|
20
|
+
**ATAM Phases**
|
|
21
|
+
|
|
22
|
+
**Phase 1: Presentation**
|
|
23
|
+
1. **Present ATAM Method** - Explain process to stakeholders
|
|
24
|
+
2. **Present Business Drivers** - Business goals, context, constraints
|
|
25
|
+
3. **Present Architecture** - Architectural approaches and patterns
|
|
26
|
+
4. **Identify Architectural Approaches** - Key architectural decisions
|
|
27
|
+
5. **Generate Quality Attribute Utility Tree** - Prioritize quality attributes
|
|
28
|
+
6. **Analyze Architectural Approaches** - Evaluate against quality attributes
|
|
29
|
+
|
|
30
|
+
**Phase 2: Investigation and Analysis**
|
|
31
|
+
7. **Brainstorm and Prioritize Scenarios** - Stakeholder scenarios
|
|
32
|
+
8. **Analyze Architectural Approaches** - Deep dive into scenarios
|
|
33
|
+
9. **Present Results** - Findings, risks, sensitivity points
|
|
34
|
+
|
|
35
|
+
**Quality Attribute Utility Tree**
|
|
36
|
+
```
|
|
37
|
+
Quality Attributes
|
|
38
|
+
├── Performance
|
|
39
|
+
│ ├── Latency (H, H)
|
|
40
|
+
│ │ └── Scenario: API response < 200ms under 1000 req/s
|
|
41
|
+
│ └── Throughput (H, M)
|
|
42
|
+
│ └── Scenario: Process 10,000 orders/hour
|
|
43
|
+
├── Security
|
|
44
|
+
│ ├── Authentication (H, H)
|
|
45
|
+
│ │ └── Scenario: Prevent unauthorized access
|
|
46
|
+
│ └── Data Protection (H, H)
|
|
47
|
+
│ └── Scenario: Encrypt sensitive data at rest
|
|
48
|
+
└── Scalability
|
|
49
|
+
├── Horizontal Scaling (M, H)
|
|
50
|
+
│ └── Scenario: Scale to 10x traffic
|
|
51
|
+
└── Database Scaling (M, M)
|
|
52
|
+
└── Scenario: Handle 1M users
|
|
53
|
+
|
|
54
|
+
(H, H) = High Importance, High Difficulty
|
|
55
|
+
(H, M) = High Importance, Medium Difficulty
|
|
56
|
+
(M, H) = Medium Importance, High Difficulty
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**ATAM Outputs**
|
|
60
|
+
- **Architectural Approaches** - Key design decisions
|
|
61
|
+
- **Quality Attribute Scenarios** - Concrete quality requirements
|
|
62
|
+
- **Sensitivity Points** - Decisions critical to quality attributes
|
|
63
|
+
- **Tradeoff Points** - Decisions affecting multiple attributes
|
|
64
|
+
- **Risks** - Potential problems
|
|
65
|
+
- **Non-Risks** - Decisions that are sound
|
|
66
|
+
|
|
67
|
+
### Chaos Engineering
|
|
68
|
+
|
|
69
|
+
**What is Chaos Engineering?**
|
|
70
|
+
- Discipline of experimenting on distributed systems
|
|
71
|
+
- Proactively inject failures to test resilience
|
|
72
|
+
- Validate system behavior under adverse conditions
|
|
73
|
+
- Build confidence in system reliability
|
|
74
|
+
- Pioneered by Netflix (Chaos Monkey)
|
|
75
|
+
|
|
76
|
+
**Chaos Engineering Principles**
|
|
77
|
+
|
|
78
|
+
**1. Build a Hypothesis**
|
|
79
|
+
- Define steady state (normal behavior)
|
|
80
|
+
- Hypothesize steady state continues during chaos
|
|
81
|
+
- Example: "API latency remains < 200ms even if one service instance fails"
|
|
82
|
+
|
|
83
|
+
**2. Vary Real-World Events**
|
|
84
|
+
- Simulate realistic failure scenarios
|
|
85
|
+
- Hardware failures, network issues, resource exhaustion
|
|
86
|
+
- Dependency failures, traffic spikes
|
|
87
|
+
|
|
88
|
+
**3. Run Experiments in Production**
|
|
89
|
+
- Test in production (with safeguards)
|
|
90
|
+
- Staging doesn't replicate production complexity
|
|
91
|
+
- Start small, increase blast radius gradually
|
|
92
|
+
|
|
93
|
+
**4. Automate Experiments**
|
|
94
|
+
- Continuous chaos engineering
|
|
95
|
+
- Integrate into CI/CD pipeline
|
|
96
|
+
- Automated rollback on failure
|
|
97
|
+
|
|
98
|
+
**5. Minimize Blast Radius**
|
|
99
|
+
- Limit impact of experiments
|
|
100
|
+
- Start with small percentage of traffic
|
|
101
|
+
- Have kill switch ready
|
|
102
|
+
|
|
103
|
+
**Chaos Experiments**
|
|
104
|
+
|
|
105
|
+
**Infrastructure Chaos**
|
|
106
|
+
- **Instance Termination** - Kill random instances
|
|
107
|
+
- **Network Latency** - Inject network delays
|
|
108
|
+
- **Network Partition** - Simulate network splits
|
|
109
|
+
- **Resource Exhaustion** - CPU/memory/disk stress
|
|
110
|
+
- **Clock Skew** - Time synchronization issues
|
|
111
|
+
|
|
112
|
+
**Application Chaos**
|
|
113
|
+
- **Dependency Failures** - Simulate service unavailability
|
|
114
|
+
- **Exception Injection** - Trigger error paths
|
|
115
|
+
- **Latency Injection** - Slow down operations
|
|
116
|
+
- **Data Corruption** - Invalid data scenarios
|
|
117
|
+
|
|
118
|
+
**Tools**
|
|
119
|
+
- **Chaos Monkey** - Random instance termination (Netflix)
|
|
120
|
+
- **Chaos Toolkit** - Open-source chaos engineering
|
|
121
|
+
- **Gremlin** - Chaos engineering platform
|
|
122
|
+
- **Litmus** - Kubernetes chaos engineering
|
|
123
|
+
- **Pumba** - Docker chaos testing
|
|
124
|
+
|
|
125
|
+
### Architecture Reviews
|
|
126
|
+
|
|
127
|
+
**Types of Architecture Reviews**
|
|
128
|
+
|
|
129
|
+
**1. Design Review**
|
|
130
|
+
- **When**: Before implementation
|
|
131
|
+
- **Purpose**: Validate design decisions
|
|
132
|
+
- **Participants**: Architects, senior developers, stakeholders
|
|
133
|
+
- **Focus**: Alignment with requirements, quality attributes
|
|
134
|
+
|
|
135
|
+
**2. Code Review (Architecture Focus)**
|
|
136
|
+
- **When**: During implementation
|
|
137
|
+
- **Purpose**: Ensure code follows architecture
|
|
138
|
+
- **Participants**: Developers, architects
|
|
139
|
+
- **Focus**: Architectural patterns, dependency rules
|
|
140
|
+
|
|
141
|
+
**3. Post-Implementation Review**
|
|
142
|
+
- **When**: After deployment
|
|
143
|
+
- **Purpose**: Validate architecture in production
|
|
144
|
+
- **Participants**: Architects, operations, developers
|
|
145
|
+
- **Focus**: Performance, scalability, maintainability
|
|
146
|
+
|
|
147
|
+
**4. Periodic Review**
|
|
148
|
+
- **When**: Quarterly/annually
|
|
149
|
+
- **Purpose**: Assess architecture evolution
|
|
150
|
+
- **Participants**: Architecture team, stakeholders
|
|
151
|
+
- **Focus**: Technical debt, modernization opportunities
|
|
152
|
+
|
|
153
|
+
**Architecture Review Checklist**
|
|
154
|
+
|
|
155
|
+
**Functional Requirements**
|
|
156
|
+
- ✓ All use cases supported
|
|
157
|
+
- ✓ Business logic correctly implemented
|
|
158
|
+
- ✓ Integration points defined
|
|
159
|
+
|
|
160
|
+
**Quality Attributes**
|
|
161
|
+
- ✓ Performance targets met
|
|
162
|
+
- ✓ Security requirements addressed
|
|
163
|
+
- ✓ Scalability approach defined
|
|
164
|
+
- ✓ Reliability/availability targets
|
|
165
|
+
- ✓ Maintainability considerations
|
|
166
|
+
|
|
167
|
+
**Architecture Principles**
|
|
168
|
+
- ✓ Separation of concerns
|
|
169
|
+
- ✓ Loose coupling, high cohesion
|
|
170
|
+
- ✓ Appropriate abstraction levels
|
|
171
|
+
- ✓ Consistent patterns used
|
|
172
|
+
|
|
173
|
+
**Technical Debt**
|
|
174
|
+
- ✓ Known limitations documented
|
|
175
|
+
- ✓ Workarounds identified
|
|
176
|
+
- ✓ Refactoring plan exists
|
|
177
|
+
|
|
178
|
+
### Architecture Testing
|
|
179
|
+
|
|
180
|
+
**Types of Architecture Tests**
|
|
181
|
+
|
|
182
|
+
**1. Fitness Functions**
|
|
183
|
+
- Automated tests for architectural characteristics
|
|
184
|
+
- Enforce architectural constraints
|
|
185
|
+
- Run in CI/CD pipeline
|
|
186
|
+
|
|
187
|
+
**2. Performance Testing**
|
|
188
|
+
- Load testing
|
|
189
|
+
- Stress testing
|
|
190
|
+
- Endurance testing
|
|
191
|
+
- Spike testing
|
|
192
|
+
|
|
193
|
+
**3. Security Testing**
|
|
194
|
+
- Penetration testing
|
|
195
|
+
- Vulnerability scanning
|
|
196
|
+
- Security code review
|
|
197
|
+
- Threat modeling validation
|
|
198
|
+
|
|
199
|
+
**4. Resilience Testing**
|
|
200
|
+
- Chaos engineering experiments
|
|
201
|
+
- Failover testing
|
|
202
|
+
- Disaster recovery drills
|
|
203
|
+
- Circuit breaker validation
|
|
204
|
+
|
|
205
|
+
**5. Integration Testing**
|
|
206
|
+
- Service integration tests
|
|
207
|
+
- Contract testing
|
|
208
|
+
- End-to-end testing
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Skills
|
|
213
|
+
|
|
214
|
+
### Conducting ATAM Evaluations
|
|
215
|
+
|
|
216
|
+
**Preparation**
|
|
217
|
+
1. Identify stakeholders (business, development, operations)
|
|
218
|
+
2. Schedule evaluation sessions (typically 2-3 days)
|
|
219
|
+
3. Gather architecture documentation
|
|
220
|
+
4. Prepare presentation materials
|
|
221
|
+
|
|
222
|
+
**Execution**
|
|
223
|
+
1. Present ATAM method to stakeholders
|
|
224
|
+
2. Elicit business drivers and constraints
|
|
225
|
+
3. Present architecture and key decisions
|
|
226
|
+
4. Build quality attribute utility tree
|
|
227
|
+
5. Generate and prioritize scenarios
|
|
228
|
+
6. Analyze architectural approaches
|
|
229
|
+
7. Identify risks, sensitivity points, tradeoffs
|
|
230
|
+
8. Document findings and recommendations
|
|
231
|
+
|
|
232
|
+
**Follow-up**
|
|
233
|
+
1. Present results to stakeholders
|
|
234
|
+
2. Prioritize risks for mitigation
|
|
235
|
+
3. Create action plan for improvements
|
|
236
|
+
4. Schedule follow-up reviews
|
|
237
|
+
|
|
238
|
+
### Designing Chaos Experiments
|
|
239
|
+
|
|
240
|
+
**1. Define Steady State**
|
|
241
|
+
```typescript
|
|
242
|
+
// Example: API latency steady state
|
|
243
|
+
interface SteadyState {
|
|
244
|
+
metric: string;
|
|
245
|
+
threshold: number;
|
|
246
|
+
unit: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const apiLatencySteadyState: SteadyState = {
|
|
250
|
+
metric: 'p95_latency',
|
|
251
|
+
threshold: 200,
|
|
252
|
+
unit: 'ms'
|
|
253
|
+
};
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**2. Formulate Hypothesis**
|
|
257
|
+
```typescript
|
|
258
|
+
interface ChaosHypothesis {
|
|
259
|
+
steadyState: SteadyState;
|
|
260
|
+
experiment: string;
|
|
261
|
+
expectedOutcome: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const hypothesis: ChaosHypothesis = {
|
|
265
|
+
steadyState: apiLatencySteadyState,
|
|
266
|
+
experiment: 'Terminate 1 of 3 API instances',
|
|
267
|
+
expectedOutcome: 'p95 latency remains < 200ms'
|
|
268
|
+
};
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**3. Design Experiment**
|
|
272
|
+
```typescript
|
|
273
|
+
interface ChaosExperiment {
|
|
274
|
+
name: string;
|
|
275
|
+
hypothesis: ChaosHypothesis;
|
|
276
|
+
blastRadius: number; // percentage of traffic
|
|
277
|
+
duration: number; // seconds
|
|
278
|
+
rollbackCondition: string;
|
|
279
|
+
steps: ExperimentStep[];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface ExperimentStep {
|
|
283
|
+
action: string;
|
|
284
|
+
target: string;
|
|
285
|
+
parameters: Record<string, any>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const instanceTerminationExperiment: ChaosExperiment = {
|
|
289
|
+
name: 'API Instance Termination',
|
|
290
|
+
hypothesis,
|
|
291
|
+
blastRadius: 10, // 10% of traffic
|
|
292
|
+
duration: 300, // 5 minutes
|
|
293
|
+
rollbackCondition: 'p95_latency > 500ms OR error_rate > 1%',
|
|
294
|
+
steps: [
|
|
295
|
+
{
|
|
296
|
+
action: 'terminate_instance',
|
|
297
|
+
target: 'api-service',
|
|
298
|
+
parameters: { count: 1, random: true }
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
action: 'monitor_metrics',
|
|
302
|
+
target: 'api-service',
|
|
303
|
+
parameters: {
|
|
304
|
+
metrics: ['p95_latency', 'error_rate'],
|
|
305
|
+
interval: 10
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
};
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**4. Run Experiment**
|
|
313
|
+
```typescript
|
|
314
|
+
class ChaosRunner {
|
|
315
|
+
async runExperiment(experiment: ChaosExperiment): Promise<ExperimentResult> {
|
|
316
|
+
// 1. Verify steady state
|
|
317
|
+
const baselineMetrics = await this.measureSteadyState(
|
|
318
|
+
experiment.hypothesis.steadyState
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
if (!this.isSteadyState(baselineMetrics, experiment.hypothesis.steadyState)) {
|
|
322
|
+
throw new Error('System not in steady state');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// 2. Execute chaos
|
|
326
|
+
const chaosHandle = await this.executeChaos(experiment.steps);
|
|
327
|
+
|
|
328
|
+
// 3. Monitor metrics
|
|
329
|
+
const results = await this.monitorExperiment(
|
|
330
|
+
experiment.duration,
|
|
331
|
+
experiment.rollbackCondition
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
// 4. Rollback
|
|
335
|
+
await this.rollback(chaosHandle);
|
|
336
|
+
|
|
337
|
+
// 5. Analyze results
|
|
338
|
+
return this.analyzeResults(baselineMetrics, results, experiment.hypothesis);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private async measureSteadyState(steadyState: SteadyState): Promise<Metrics> {
|
|
342
|
+
// Measure current metrics
|
|
343
|
+
return await this.metricsCollector.collect([steadyState.metric]);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private isSteadyState(metrics: Metrics, steadyState: SteadyState): boolean {
|
|
347
|
+
return metrics[steadyState.metric] <= steadyState.threshold;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private async executeChaos(steps: ExperimentStep[]): Promise<ChaosHandle> {
|
|
351
|
+
// Execute chaos actions
|
|
352
|
+
const handles = [];
|
|
353
|
+
for (const step of steps) {
|
|
354
|
+
const handle = await this.chaosEngine.execute(step);
|
|
355
|
+
handles.push(handle);
|
|
356
|
+
}
|
|
357
|
+
return { handles };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private async monitorExperiment(
|
|
361
|
+
duration: number,
|
|
362
|
+
rollbackCondition: string
|
|
363
|
+
): Promise<ExperimentMetrics> {
|
|
364
|
+
const startTime = Date.now();
|
|
365
|
+
const metrics: ExperimentMetrics = { samples: [] };
|
|
366
|
+
|
|
367
|
+
while (Date.now() - startTime < duration * 1000) {
|
|
368
|
+
const sample = await this.metricsCollector.collect();
|
|
369
|
+
metrics.samples.push(sample);
|
|
370
|
+
|
|
371
|
+
// Check rollback condition
|
|
372
|
+
if (this.evaluateRollbackCondition(sample, rollbackCondition)) {
|
|
373
|
+
throw new Error('Rollback condition triggered');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
await this.sleep(10000); // 10 second intervals
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return metrics;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private async rollback(chaosHandle: ChaosHandle): Promise<void> {
|
|
383
|
+
// Rollback chaos actions
|
|
384
|
+
for (const handle of chaosHandle.handles) {
|
|
385
|
+
await this.chaosEngine.rollback(handle);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private analyzeResults(
|
|
390
|
+
baseline: Metrics,
|
|
391
|
+
experiment: ExperimentMetrics,
|
|
392
|
+
hypothesis: ChaosHypothesis
|
|
393
|
+
): ExperimentResult {
|
|
394
|
+
// Compare experiment metrics to baseline and hypothesis
|
|
395
|
+
const steadyStateMaintained = experiment.samples.every(sample =>
|
|
396
|
+
sample[hypothesis.steadyState.metric] <= hypothesis.steadyState.threshold
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
success: steadyStateMaintained,
|
|
401
|
+
baseline,
|
|
402
|
+
experiment,
|
|
403
|
+
hypothesis,
|
|
404
|
+
findings: this.generateFindings(baseline, experiment, steadyStateMaintained)
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Performing Architecture Reviews
|
|
411
|
+
|
|
412
|
+
**Design Review Process**
|
|
413
|
+
|
|
414
|
+
**1. Pre-Review Preparation**
|
|
415
|
+
- Review architecture documentation
|
|
416
|
+
- Identify key architectural decisions
|
|
417
|
+
- Prepare questions and concerns
|
|
418
|
+
- Review quality attribute requirements
|
|
419
|
+
|
|
420
|
+
**2. Review Meeting**
|
|
421
|
+
- Present architecture overview
|
|
422
|
+
- Walk through key decisions
|
|
423
|
+
- Discuss alternatives considered
|
|
424
|
+
- Address reviewer questions
|
|
425
|
+
- Document action items
|
|
426
|
+
|
|
427
|
+
**3. Post-Review**
|
|
428
|
+
- Document findings
|
|
429
|
+
- Prioritize action items
|
|
430
|
+
- Update architecture documentation
|
|
431
|
+
- Schedule follow-up if needed
|
|
432
|
+
|
|
433
|
+
**Architecture Review Template**
|
|
434
|
+
|
|
435
|
+
```markdown
|
|
436
|
+
# Architecture Review: [System Name]
|
|
437
|
+
|
|
438
|
+
## Review Information
|
|
439
|
+
- **Date**: YYYY-MM-DD
|
|
440
|
+
- **Reviewers**: [Names]
|
|
441
|
+
- **Architect**: [Name]
|
|
442
|
+
- **System**: [System Name]
|
|
443
|
+
|
|
444
|
+
## Architecture Overview
|
|
445
|
+
[Brief description of the architecture]
|
|
446
|
+
|
|
447
|
+
## Key Architectural Decisions
|
|
448
|
+
1. **Decision**: [Description]
|
|
449
|
+
- **Rationale**: [Why this decision was made]
|
|
450
|
+
- **Alternatives**: [What else was considered]
|
|
451
|
+
- **Tradeoffs**: [Pros and cons]
|
|
452
|
+
|
|
453
|
+
## Quality Attributes Assessment
|
|
454
|
+
|
|
455
|
+
### Performance
|
|
456
|
+
- **Target**: [e.g., < 200ms p95 latency]
|
|
457
|
+
- **Approach**: [How it's achieved]
|
|
458
|
+
- **Risks**: [Potential issues]
|
|
459
|
+
|
|
460
|
+
### Security
|
|
461
|
+
- **Requirements**: [Security requirements]
|
|
462
|
+
- **Approach**: [Security measures]
|
|
463
|
+
- **Risks**: [Security concerns]
|
|
464
|
+
|
|
465
|
+
### Scalability
|
|
466
|
+
- **Target**: [e.g., 10,000 concurrent users]
|
|
467
|
+
- **Approach**: [Scaling strategy]
|
|
468
|
+
- **Risks**: [Scalability concerns]
|
|
469
|
+
|
|
470
|
+
## Findings
|
|
471
|
+
|
|
472
|
+
### Strengths
|
|
473
|
+
1. [Positive aspect]
|
|
474
|
+
2. [Positive aspect]
|
|
475
|
+
|
|
476
|
+
### Risks
|
|
477
|
+
1. **Risk**: [Description]
|
|
478
|
+
- **Impact**: High/Medium/Low
|
|
479
|
+
- **Likelihood**: High/Medium/Low
|
|
480
|
+
- **Mitigation**: [Recommended action]
|
|
481
|
+
|
|
482
|
+
### Recommendations
|
|
483
|
+
1. [Recommendation]
|
|
484
|
+
2. [Recommendation]
|
|
485
|
+
|
|
486
|
+
## Action Items
|
|
487
|
+
1. [ ] [Action item] - Owner: [Name] - Due: [Date]
|
|
488
|
+
2. [ ] [Action item] - Owner: [Name] - Due: [Date]
|
|
489
|
+
|
|
490
|
+
## Follow-up
|
|
491
|
+
- **Next Review**: [Date]
|
|
492
|
+
- **Focus Areas**: [What to review next time]
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Implementing Fitness Functions
|
|
496
|
+
|
|
497
|
+
**What are Fitness Functions?**
|
|
498
|
+
- Automated tests for architectural characteristics
|
|
499
|
+
- Enforce architectural constraints
|
|
500
|
+
- Run in CI/CD pipeline
|
|
501
|
+
- Provide continuous architecture validation
|
|
502
|
+
|
|
503
|
+
**Types of Fitness Functions**
|
|
504
|
+
|
|
505
|
+
**1. Dependency Rules**
|
|
506
|
+
```typescript
|
|
507
|
+
// ArchUnit-style test (conceptual TypeScript)
|
|
508
|
+
import { ArchRule, classes } from 'arch-test';
|
|
509
|
+
|
|
510
|
+
describe('Architecture Fitness Functions', () => {
|
|
511
|
+
it('should enforce layered architecture', () => {
|
|
512
|
+
const rule = classes()
|
|
513
|
+
.that().resideInPackage('..domain..')
|
|
514
|
+
.should().onlyDependOn(['..domain..', 'std-lib'])
|
|
515
|
+
.because('Domain layer should not depend on infrastructure');
|
|
516
|
+
|
|
517
|
+
rule.check();
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it('should prevent circular dependencies', () => {
|
|
521
|
+
const rule = classes()
|
|
522
|
+
.should().beFreeOfCycles()
|
|
523
|
+
.because('Circular dependencies make code hard to maintain');
|
|
524
|
+
|
|
525
|
+
rule.check();
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it('should enforce naming conventions', () => {
|
|
529
|
+
const rule = classes()
|
|
530
|
+
.that().resideInPackage('..services..')
|
|
531
|
+
.should().haveSimpleNameEndingWith('Service')
|
|
532
|
+
.because('Services should follow naming convention');
|
|
533
|
+
|
|
534
|
+
rule.check();
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**2. Performance Fitness Functions**
|
|
540
|
+
```typescript
|
|
541
|
+
import { performance } from 'perf_hooks';
|
|
542
|
+
|
|
543
|
+
describe('Performance Fitness Functions', () => {
|
|
544
|
+
it('should complete API request within 200ms', async () => {
|
|
545
|
+
const start = performance.now();
|
|
546
|
+
await apiClient.get('/users/123');
|
|
547
|
+
const duration = performance.now() - start;
|
|
548
|
+
|
|
549
|
+
expect(duration).toBeLessThan(200);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should handle 1000 concurrent requests', async () => {
|
|
553
|
+
const requests = Array(1000).fill(null).map(() =>
|
|
554
|
+
apiClient.get('/health')
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
const start = performance.now();
|
|
558
|
+
await Promise.all(requests);
|
|
559
|
+
const duration = performance.now() - start;
|
|
560
|
+
|
|
561
|
+
// Should complete in reasonable time
|
|
562
|
+
expect(duration).toBeLessThan(5000);
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**3. Security Fitness Functions**
|
|
568
|
+
```typescript
|
|
569
|
+
describe('Security Fitness Functions', () => {
|
|
570
|
+
it('should not expose sensitive data in logs', () => {
|
|
571
|
+
const logContent = fs.readFileSync('app.log', 'utf-8');
|
|
572
|
+
|
|
573
|
+
// Check for common sensitive patterns
|
|
574
|
+
expect(logContent).not.toMatch(/password/i);
|
|
575
|
+
expect(logContent).not.toMatch(/api[_-]?key/i);
|
|
576
|
+
expect(logContent).not.toMatch(/secret/i);
|
|
577
|
+
expect(logContent).not.toMatch(/\d{16}/); // Credit card numbers
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it('should use HTTPS for all external APIs', () => {
|
|
581
|
+
const configFiles = glob.sync('**/*.config.ts');
|
|
582
|
+
|
|
583
|
+
configFiles.forEach(file => {
|
|
584
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
585
|
+
const httpUrls = content.match(/http:\/\/[^\s"']+/g) || [];
|
|
586
|
+
|
|
587
|
+
// Filter out localhost
|
|
588
|
+
const externalHttpUrls = httpUrls.filter(url =>
|
|
589
|
+
!url.includes('localhost') && !url.includes('127.0.0.1')
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
expect(externalHttpUrls).toHaveLength(0);
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**4. Scalability Fitness Functions**
|
|
599
|
+
```typescript
|
|
600
|
+
describe('Scalability Fitness Functions', () => {
|
|
601
|
+
it('should be stateless (no in-memory session storage)', () => {
|
|
602
|
+
const sourceFiles = glob.sync('src/**/*.ts');
|
|
603
|
+
|
|
604
|
+
sourceFiles.forEach(file => {
|
|
605
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
606
|
+
|
|
607
|
+
// Check for in-memory session patterns
|
|
608
|
+
expect(content).not.toMatch(/express-session.*MemoryStore/);
|
|
609
|
+
expect(content).not.toMatch(/const\s+sessions\s*=\s*\{/);
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it('should use connection pooling for database', () => {
|
|
614
|
+
const dbConfig = require('../config/database');
|
|
615
|
+
|
|
616
|
+
expect(dbConfig.pool).toBeDefined();
|
|
617
|
+
expect(dbConfig.pool.min).toBeGreaterThan(0);
|
|
618
|
+
expect(dbConfig.pool.max).toBeGreaterThan(dbConfig.pool.min);
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**5. Maintainability Fitness Functions**
|
|
624
|
+
```typescript
|
|
625
|
+
describe('Maintainability Fitness Functions', () => {
|
|
626
|
+
it('should have test coverage above 80%', () => {
|
|
627
|
+
const coverage = require('../coverage/coverage-summary.json');
|
|
628
|
+
const totalCoverage = coverage.total.lines.pct;
|
|
629
|
+
|
|
630
|
+
expect(totalCoverage).toBeGreaterThan(80);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
it('should have no files exceeding 300 lines', () => {
|
|
634
|
+
const sourceFiles = glob.sync('src/**/*.ts');
|
|
635
|
+
|
|
636
|
+
sourceFiles.forEach(file => {
|
|
637
|
+
const lines = fs.readFileSync(file, 'utf-8').split('\n').length;
|
|
638
|
+
expect(lines).toBeLessThan(300);
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
it('should have no functions exceeding 50 lines', () => {
|
|
643
|
+
// Use static analysis tool
|
|
644
|
+
const report = eslint.lintFiles(['src/**/*.ts']);
|
|
645
|
+
const complexityIssues = report.results.flatMap(r => r.messages)
|
|
646
|
+
.filter(m => m.ruleId === 'max-lines-per-function');
|
|
647
|
+
|
|
648
|
+
expect(complexityIssues).toHaveLength(0);
|
|
649
|
+
});
|
|
650
|
+
});
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## Examples
|
|
656
|
+
|
|
657
|
+
### Example 1: Complete ATAM Evaluation
|
|
658
|
+
|
|
659
|
+
**System**: E-commerce Platform
|
|
660
|
+
|
|
661
|
+
**Business Drivers**
|
|
662
|
+
- Support 1M concurrent users during Black Friday
|
|
663
|
+
- 99.9% uptime SLA
|
|
664
|
+
- PCI DSS compliance for payment processing
|
|
665
|
+
- Global expansion to 50 countries
|
|
666
|
+
|
|
667
|
+
**Architecture Overview**
|
|
668
|
+
- Microservices architecture
|
|
669
|
+
- Event-driven communication
|
|
670
|
+
- Multi-region deployment
|
|
671
|
+
- CDN for static assets
|
|
672
|
+
- Kubernetes orchestration
|
|
673
|
+
|
|
674
|
+
**Quality Attribute Utility Tree**
|
|
675
|
+
|
|
676
|
+
```
|
|
677
|
+
Quality Attributes
|
|
678
|
+
├── Performance (H)
|
|
679
|
+
│ ├── API Latency (H, H)
|
|
680
|
+
│ │ └── Scenario: Checkout API responds in < 500ms at 10,000 req/s
|
|
681
|
+
│ └── Page Load Time (H, M)
|
|
682
|
+
│ └── Scenario: Product page loads in < 2s globally
|
|
683
|
+
├── Availability (H)
|
|
684
|
+
│ ├── Uptime (H, H)
|
|
685
|
+
│ │ └── Scenario: 99.9% uptime (< 8.76 hours downtime/year)
|
|
686
|
+
│ └── Disaster Recovery (H, H)
|
|
687
|
+
│ └── Scenario: Recover from region failure in < 5 minutes
|
|
688
|
+
├── Security (H)
|
|
689
|
+
│ ├── Payment Security (H, H)
|
|
690
|
+
│ │ └── Scenario: PCI DSS Level 1 compliance
|
|
691
|
+
│ └── Data Protection (H, M)
|
|
692
|
+
│ └── Scenario: GDPR compliance for EU customers
|
|
693
|
+
├── Scalability (H)
|
|
694
|
+
│ ├── Traffic Spikes (H, H)
|
|
695
|
+
│ │ └── Scenario: Handle 10x traffic during Black Friday
|
|
696
|
+
│ └── Geographic Expansion (M, M)
|
|
697
|
+
│ └── Scenario: Deploy to new region in < 1 week
|
|
698
|
+
└── Maintainability (M)
|
|
699
|
+
├── Deployment Frequency (M, M)
|
|
700
|
+
│ └── Scenario: Deploy 10+ times per day
|
|
701
|
+
└── Mean Time to Recovery (M, H)
|
|
702
|
+
└── Scenario: Recover from incidents in < 30 minutes
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**Architectural Approaches**
|
|
706
|
+
|
|
707
|
+
**1. Microservices for Scalability**
|
|
708
|
+
- **Decision**: Decompose into 15 microservices
|
|
709
|
+
- **Quality Attributes**: Scalability, Maintainability
|
|
710
|
+
- **Rationale**: Independent scaling, team autonomy
|
|
711
|
+
- **Tradeoffs**: Increased complexity, distributed system challenges
|
|
712
|
+
|
|
713
|
+
**2. Event-Driven Architecture for Decoupling**
|
|
714
|
+
- **Decision**: Use Kafka for inter-service communication
|
|
715
|
+
- **Quality Attributes**: Scalability, Availability
|
|
716
|
+
- **Rationale**: Asynchronous processing, loose coupling
|
|
717
|
+
- **Tradeoffs**: Eventual consistency, debugging complexity
|
|
718
|
+
|
|
719
|
+
**3. Multi-Region Deployment for Availability**
|
|
720
|
+
- **Decision**: Deploy to 3 AWS regions (US, EU, APAC)
|
|
721
|
+
- **Quality Attributes**: Availability, Performance
|
|
722
|
+
- **Rationale**: Geographic redundancy, low latency
|
|
723
|
+
- **Tradeoffs**: Increased cost, data consistency challenges
|
|
724
|
+
|
|
725
|
+
**4. CDN for Performance**
|
|
726
|
+
- **Decision**: CloudFront for static assets and API caching
|
|
727
|
+
- **Quality Attributes**: Performance, Scalability
|
|
728
|
+
- **Rationale**: Reduce latency, offload origin servers
|
|
729
|
+
- **Tradeoffs**: Cache invalidation complexity
|
|
730
|
+
|
|
731
|
+
**Sensitivity Points**
|
|
732
|
+
1. **Kafka Cluster Size**: Critical for event throughput
|
|
733
|
+
2. **Database Sharding Strategy**: Affects query performance
|
|
734
|
+
3. **Cache TTL Settings**: Impacts data freshness vs. performance
|
|
735
|
+
4. **Circuit Breaker Thresholds**: Affects availability vs. cascading failures
|
|
736
|
+
|
|
737
|
+
**Tradeoff Points**
|
|
738
|
+
1. **Consistency vs. Availability**: Eventual consistency for better availability
|
|
739
|
+
2. **Cost vs. Performance**: Multi-region deployment increases cost
|
|
740
|
+
3. **Complexity vs. Scalability**: Microservices add complexity for scalability
|
|
741
|
+
|
|
742
|
+
**Risks**
|
|
743
|
+
1. **High Risk**: Kafka single point of failure
|
|
744
|
+
- **Mitigation**: Multi-AZ Kafka cluster, replication factor 3
|
|
745
|
+
2. **High Risk**: Database bottleneck during traffic spikes
|
|
746
|
+
- **Mitigation**: Read replicas, caching layer, connection pooling
|
|
747
|
+
3. **Medium Risk**: Cross-region data consistency
|
|
748
|
+
- **Mitigation**: Event sourcing, CQRS pattern
|
|
749
|
+
4. **Medium Risk**: Microservices debugging complexity
|
|
750
|
+
- **Mitigation**: Distributed tracing (Jaeger), centralized logging
|
|
751
|
+
|
|
752
|
+
**Non-Risks**
|
|
753
|
+
1. CDN configuration is well-understood
|
|
754
|
+
2. Kubernetes orchestration is proven at scale
|
|
755
|
+
3. Payment gateway integration follows PCI DSS standards
|
|
756
|
+
|
|
757
|
+
**Recommendations**
|
|
758
|
+
1. Implement chaos engineering to validate resilience
|
|
759
|
+
2. Add database read replicas in each region
|
|
760
|
+
3. Implement distributed tracing before production
|
|
761
|
+
4. Create runbooks for common failure scenarios
|
|
762
|
+
5. Conduct load testing at 2x expected Black Friday traffic
|
|
763
|
+
|
|
764
|
+
### Example 2: Chaos Engineering Experiment
|
|
765
|
+
|
|
766
|
+
**Experiment**: Database Failover
|
|
767
|
+
|
|
768
|
+
**Hypothesis**
|
|
769
|
+
- **Steady State**: API error rate < 0.1%, p95 latency < 300ms
|
|
770
|
+
- **Experiment**: Terminate primary database instance
|
|
771
|
+
- **Expected Outcome**: Automatic failover to replica, error rate < 1% during failover, recovery < 30 seconds
|
|
772
|
+
|
|
773
|
+
**Experiment Configuration**
|
|
774
|
+
```typescript
|
|
775
|
+
const databaseFailoverExperiment: ChaosExperiment = {
|
|
776
|
+
name: 'Database Primary Failover',
|
|
777
|
+
hypothesis: {
|
|
778
|
+
steadyState: {
|
|
779
|
+
metric: 'error_rate',
|
|
780
|
+
threshold: 0.1,
|
|
781
|
+
unit: 'percent'
|
|
782
|
+
},
|
|
783
|
+
experiment: 'Terminate primary database instance',
|
|
784
|
+
expectedOutcome: 'Automatic failover with < 1% error rate, < 30s recovery'
|
|
785
|
+
},
|
|
786
|
+
blastRadius: 100, // Full production traffic
|
|
787
|
+
duration: 600, // 10 minutes
|
|
788
|
+
rollbackCondition: 'error_rate > 5% OR p95_latency > 2000ms',
|
|
789
|
+
steps: [
|
|
790
|
+
{
|
|
791
|
+
action: 'terminate_instance',
|
|
792
|
+
target: 'database-primary',
|
|
793
|
+
parameters: {
|
|
794
|
+
instanceId: 'db-primary-1',
|
|
795
|
+
graceful: false
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
action: 'monitor_metrics',
|
|
800
|
+
target: 'api-service',
|
|
801
|
+
parameters: {
|
|
802
|
+
metrics: ['error_rate', 'p95_latency', 'database_connections'],
|
|
803
|
+
interval: 5
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
action: 'monitor_failover',
|
|
808
|
+
target: 'database-cluster',
|
|
809
|
+
parameters: {
|
|
810
|
+
checkInterval: 1,
|
|
811
|
+
maxFailoverTime: 30
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
]
|
|
815
|
+
};
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
**Execution**
|
|
819
|
+
```bash
|
|
820
|
+
# Run chaos experiment
|
|
821
|
+
chaos-toolkit run database-failover.yaml
|
|
822
|
+
|
|
823
|
+
# Monitor metrics
|
|
824
|
+
watch -n 1 'curl -s http://metrics-api/current | jq .'
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
**Results**
|
|
828
|
+
```
|
|
829
|
+
Baseline Metrics (5 minutes before experiment):
|
|
830
|
+
- Error Rate: 0.05%
|
|
831
|
+
- P95 Latency: 245ms
|
|
832
|
+
- Database Connections: 150
|
|
833
|
+
|
|
834
|
+
Experiment Metrics:
|
|
835
|
+
T+0s: Terminate primary database instance
|
|
836
|
+
T+2s: Error rate spikes to 15% (connection errors)
|
|
837
|
+
T+8s: Replica promoted to primary
|
|
838
|
+
T+10s: Connection pool reconnects to new primary
|
|
839
|
+
T+12s: Error rate drops to 2%
|
|
840
|
+
T+30s: Error rate returns to 0.1%
|
|
841
|
+
T+35s: P95 latency returns to 250ms
|
|
842
|
+
|
|
843
|
+
Recovery Time: 30 seconds
|
|
844
|
+
Peak Error Rate: 15%
|
|
845
|
+
Total Failed Requests: ~450 (out of 30,000)
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
**Findings**
|
|
849
|
+
1. ✅ Automatic failover worked as expected
|
|
850
|
+
2. ❌ Error rate exceeded 1% target during failover (15% peak)
|
|
851
|
+
3. ✅ Recovery time met 30-second target
|
|
852
|
+
4. ❌ Connection pool took 10 seconds to reconnect (too slow)
|
|
853
|
+
|
|
854
|
+
**Action Items**
|
|
855
|
+
1. Reduce connection pool reconnect timeout from 10s to 2s
|
|
856
|
+
2. Implement retry logic with exponential backoff
|
|
857
|
+
3. Add circuit breaker to fail fast during failover
|
|
858
|
+
4. Pre-warm connection pool to replica instances
|
|
859
|
+
5. Re-run experiment after improvements
|
|
860
|
+
|
|
861
|
+
### Example 3: Architecture Fitness Functions Suite
|
|
862
|
+
|
|
863
|
+
**Complete Fitness Function Suite**
|
|
864
|
+
|
|
865
|
+
```typescript
|
|
866
|
+
// tests/architecture/fitness-functions.test.ts
|
|
867
|
+
|
|
868
|
+
import { describe, it, expect } from '@jest/globals';
|
|
869
|
+
import { ArchRule, classes, packages } from 'ts-arch';
|
|
870
|
+
import { performance } from 'perf_hooks';
|
|
871
|
+
import * as fs from 'fs';
|
|
872
|
+
import * as glob from 'glob';
|
|
873
|
+
|
|
874
|
+
describe('Architecture Fitness Functions', () => {
|
|
875
|
+
|
|
876
|
+
// ===== STRUCTURAL FITNESS FUNCTIONS =====
|
|
877
|
+
|
|
878
|
+
describe('Layered Architecture', () => {
|
|
879
|
+
it('domain layer should not depend on infrastructure', () => {
|
|
880
|
+
const rule = classes()
|
|
881
|
+
.that().resideInPackage('..domain..')
|
|
882
|
+
.should().onlyDependOn(['..domain..', 'std-lib'])
|
|
883
|
+
.because('Domain layer must be independent');
|
|
884
|
+
|
|
885
|
+
rule.check();
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
it('application layer should not depend on infrastructure', () => {
|
|
889
|
+
const rule = classes()
|
|
890
|
+
.that().resideInPackage('..application..')
|
|
891
|
+
.should().onlyDependOn(['..domain..', '..application..', 'std-lib'])
|
|
892
|
+
.because('Application layer should not know about infrastructure');
|
|
893
|
+
|
|
894
|
+
rule.check();
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it('infrastructure layer can depend on all layers', () => {
|
|
898
|
+
const rule = classes()
|
|
899
|
+
.that().resideInPackage('..infrastructure..')
|
|
900
|
+
.should().dependOn(['..domain..', '..application..'])
|
|
901
|
+
.because('Infrastructure implements interfaces from other layers');
|
|
902
|
+
|
|
903
|
+
rule.check();
|
|
904
|
+
});
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
describe('Dependency Rules', () => {
|
|
908
|
+
it('should have no circular dependencies', () => {
|
|
909
|
+
const rule = packages()
|
|
910
|
+
.should().beFreeOfCycles()
|
|
911
|
+
.because('Circular dependencies create tight coupling');
|
|
912
|
+
|
|
913
|
+
rule.check();
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
it('controllers should not directly access repositories', () => {
|
|
917
|
+
const rule = classes()
|
|
918
|
+
.that().resideInPackage('..controllers..')
|
|
919
|
+
.should().notDependOn(['..repositories..'])
|
|
920
|
+
.because('Controllers should use services, not repositories directly');
|
|
921
|
+
|
|
922
|
+
rule.check();
|
|
923
|
+
});
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
describe('Naming Conventions', () => {
|
|
927
|
+
it('services should end with Service', () => {
|
|
928
|
+
const rule = classes()
|
|
929
|
+
.that().resideInPackage('..services..')
|
|
930
|
+
.should().haveSimpleNameEndingWith('Service');
|
|
931
|
+
|
|
932
|
+
rule.check();
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
it('repositories should end with Repository', () => {
|
|
936
|
+
const rule = classes()
|
|
937
|
+
.that().resideInPackage('..repositories..')
|
|
938
|
+
.should().haveSimpleNameEndingWith('Repository');
|
|
939
|
+
|
|
940
|
+
rule.check();
|
|
941
|
+
});
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
// ===== PERFORMANCE FITNESS FUNCTIONS =====
|
|
945
|
+
|
|
946
|
+
describe('Performance', () => {
|
|
947
|
+
it('API endpoints should respond within 200ms', async () => {
|
|
948
|
+
const endpoints = ['/users', '/products', '/orders'];
|
|
949
|
+
|
|
950
|
+
for (const endpoint of endpoints) {
|
|
951
|
+
const start = performance.now();
|
|
952
|
+
await fetch(`http://localhost:3000${endpoint}`);
|
|
953
|
+
const duration = performance.now() - start;
|
|
954
|
+
|
|
955
|
+
expect(duration).toBeLessThan(200);
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
it('should handle 1000 concurrent requests', async () => {
|
|
960
|
+
const requests = Array(1000).fill(null).map(() =>
|
|
961
|
+
fetch('http://localhost:3000/health')
|
|
962
|
+
);
|
|
963
|
+
|
|
964
|
+
const start = performance.now();
|
|
965
|
+
const responses = await Promise.all(requests);
|
|
966
|
+
const duration = performance.now() - start;
|
|
967
|
+
|
|
968
|
+
expect(responses.every(r => r.ok)).toBe(true);
|
|
969
|
+
expect(duration).toBeLessThan(5000);
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
it('database queries should use indexes', () => {
|
|
973
|
+
const migrations = glob.sync('migrations/**/*.sql');
|
|
974
|
+
|
|
975
|
+
migrations.forEach(file => {
|
|
976
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
977
|
+
const createTableStatements = content.match(/CREATE TABLE/gi) || [];
|
|
978
|
+
const createIndexStatements = content.match(/CREATE INDEX/gi) || [];
|
|
979
|
+
|
|
980
|
+
// Should have at least one index per table
|
|
981
|
+
expect(createIndexStatements.length).toBeGreaterThanOrEqual(
|
|
982
|
+
createTableStatements.length
|
|
983
|
+
);
|
|
984
|
+
});
|
|
985
|
+
});
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
// ===== SECURITY FITNESS FUNCTIONS =====
|
|
989
|
+
|
|
990
|
+
describe('Security', () => {
|
|
991
|
+
it('should not expose sensitive data in logs', () => {
|
|
992
|
+
const logFiles = glob.sync('logs/**/*.log');
|
|
993
|
+
|
|
994
|
+
logFiles.forEach(file => {
|
|
995
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
996
|
+
|
|
997
|
+
expect(content).not.toMatch(/password/i);
|
|
998
|
+
expect(content).not.toMatch(/api[_-]?key/i);
|
|
999
|
+
expect(content).not.toMatch(/secret/i);
|
|
1000
|
+
expect(content).not.toMatch(/\d{16}/); // Credit cards
|
|
1001
|
+
expect(content).not.toMatch(/\d{3}-\d{2}-\d{4}/); // SSN
|
|
1002
|
+
});
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
it('should use HTTPS for all external APIs', () => {
|
|
1006
|
+
const configFiles = glob.sync('src/**/*.config.ts');
|
|
1007
|
+
|
|
1008
|
+
configFiles.forEach(file => {
|
|
1009
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1010
|
+
const httpUrls = content.match(/http:\/\/[^\s"']+/g) || [];
|
|
1011
|
+
const externalHttpUrls = httpUrls.filter(url =>
|
|
1012
|
+
!url.includes('localhost') && !url.includes('127.0.0.1')
|
|
1013
|
+
);
|
|
1014
|
+
|
|
1015
|
+
expect(externalHttpUrls).toHaveLength(0);
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
it('should validate all user inputs', () => {
|
|
1020
|
+
const controllerFiles = glob.sync('src/controllers/**/*.ts');
|
|
1021
|
+
|
|
1022
|
+
controllerFiles.forEach(file => {
|
|
1023
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1024
|
+
|
|
1025
|
+
// Check for validation decorators or middleware
|
|
1026
|
+
if (content.includes('req.body') || content.includes('req.query')) {
|
|
1027
|
+
expect(
|
|
1028
|
+
content.includes('@Validate') ||
|
|
1029
|
+
content.includes('validate(') ||
|
|
1030
|
+
content.includes('validateRequest')
|
|
1031
|
+
).toBe(true);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
it('should use parameterized queries', () => {
|
|
1037
|
+
const repositoryFiles = glob.sync('src/repositories/**/*.ts');
|
|
1038
|
+
|
|
1039
|
+
repositoryFiles.forEach(file => {
|
|
1040
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1041
|
+
|
|
1042
|
+
// Check for SQL injection vulnerabilities
|
|
1043
|
+
const rawQueries = content.match(/query\([`'"].*\$\{/g) || [];
|
|
1044
|
+
expect(rawQueries).toHaveLength(0);
|
|
1045
|
+
});
|
|
1046
|
+
});
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
// ===== SCALABILITY FITNESS FUNCTIONS =====
|
|
1050
|
+
|
|
1051
|
+
describe('Scalability', () => {
|
|
1052
|
+
it('should be stateless (no in-memory sessions)', () => {
|
|
1053
|
+
const sourceFiles = glob.sync('src/**/*.ts');
|
|
1054
|
+
|
|
1055
|
+
sourceFiles.forEach(file => {
|
|
1056
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1057
|
+
|
|
1058
|
+
expect(content).not.toMatch(/express-session.*MemoryStore/);
|
|
1059
|
+
expect(content).not.toMatch(/const\s+sessions\s*=\s*\{/);
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
it('should use connection pooling', () => {
|
|
1064
|
+
const dbConfig = require('../../src/config/database');
|
|
1065
|
+
|
|
1066
|
+
expect(dbConfig.pool).toBeDefined();
|
|
1067
|
+
expect(dbConfig.pool.min).toBeGreaterThan(0);
|
|
1068
|
+
expect(dbConfig.pool.max).toBeGreaterThan(dbConfig.pool.min);
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
it('should implement caching for expensive operations', () => {
|
|
1072
|
+
const serviceFiles = glob.sync('src/services/**/*.ts');
|
|
1073
|
+
|
|
1074
|
+
let hasCaching = false;
|
|
1075
|
+
serviceFiles.forEach(file => {
|
|
1076
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1077
|
+
if (content.includes('@Cache') || content.includes('cache.get')) {
|
|
1078
|
+
hasCaching = true;
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
expect(hasCaching).toBe(true);
|
|
1083
|
+
});
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// ===== MAINTAINABILITY FITNESS FUNCTIONS =====
|
|
1087
|
+
|
|
1088
|
+
describe('Maintainability', () => {
|
|
1089
|
+
it('should have test coverage above 80%', () => {
|
|
1090
|
+
const coverage = require('../../coverage/coverage-summary.json');
|
|
1091
|
+
expect(coverage.total.lines.pct).toBeGreaterThan(80);
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
it('should have no files exceeding 300 lines', () => {
|
|
1095
|
+
const sourceFiles = glob.sync('src/**/*.ts');
|
|
1096
|
+
|
|
1097
|
+
sourceFiles.forEach(file => {
|
|
1098
|
+
const lines = fs.readFileSync(file, 'utf-8').split('\n').length;
|
|
1099
|
+
expect(lines).toBeLessThan(300);
|
|
1100
|
+
});
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
it('should have no functions exceeding 50 lines', () => {
|
|
1104
|
+
const sourceFiles = glob.sync('src/**/*.ts');
|
|
1105
|
+
|
|
1106
|
+
sourceFiles.forEach(file => {
|
|
1107
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1108
|
+
const functions = content.match(/function\s+\w+\s*\([^)]*\)\s*\{/g) || [];
|
|
1109
|
+
|
|
1110
|
+
functions.forEach(func => {
|
|
1111
|
+
const funcStart = content.indexOf(func);
|
|
1112
|
+
const funcBody = content.substring(funcStart);
|
|
1113
|
+
const funcEnd = this.findMatchingBrace(funcBody);
|
|
1114
|
+
const funcLines = funcBody.substring(0, funcEnd).split('\n').length;
|
|
1115
|
+
|
|
1116
|
+
expect(funcLines).toBeLessThan(50);
|
|
1117
|
+
});
|
|
1118
|
+
});
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
it('should have no TODO comments older than 30 days', () => {
|
|
1122
|
+
const sourceFiles = glob.sync('src/**/*.ts');
|
|
1123
|
+
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
|
|
1124
|
+
|
|
1125
|
+
sourceFiles.forEach(file => {
|
|
1126
|
+
const stats = fs.statSync(file);
|
|
1127
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1128
|
+
const todos = content.match(/\/\/\s*TODO/gi) || [];
|
|
1129
|
+
|
|
1130
|
+
if (todos.length > 0 && stats.mtimeMs < thirtyDaysAgo) {
|
|
1131
|
+
throw new Error(`File ${file} has TODO comments older than 30 days`);
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
});
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
// ===== RELIABILITY FITNESS FUNCTIONS =====
|
|
1138
|
+
|
|
1139
|
+
describe('Reliability', () => {
|
|
1140
|
+
it('should implement circuit breakers for external services', () => {
|
|
1141
|
+
const serviceFiles = glob.sync('src/services/**/*Client.ts');
|
|
1142
|
+
|
|
1143
|
+
serviceFiles.forEach(file => {
|
|
1144
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1145
|
+
|
|
1146
|
+
expect(
|
|
1147
|
+
content.includes('CircuitBreaker') ||
|
|
1148
|
+
content.includes('@CircuitBreaker') ||
|
|
1149
|
+
content.includes('breaker.')
|
|
1150
|
+
).toBe(true);
|
|
1151
|
+
});
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
it('should implement retry logic for transient failures', () => {
|
|
1155
|
+
const serviceFiles = glob.sync('src/services/**/*Client.ts');
|
|
1156
|
+
|
|
1157
|
+
serviceFiles.forEach(file => {
|
|
1158
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
1159
|
+
|
|
1160
|
+
expect(
|
|
1161
|
+
content.includes('retry(') ||
|
|
1162
|
+
content.includes('@Retry') ||
|
|
1163
|
+
content.includes('retryPolicy')
|
|
1164
|
+
).toBe(true);
|
|
1165
|
+
});
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
it('should have health check endpoints', async () => {
|
|
1169
|
+
const response = await fetch('http://localhost:3000/health');
|
|
1170
|
+
expect(response.ok).toBe(true);
|
|
1171
|
+
|
|
1172
|
+
const health = await response.json();
|
|
1173
|
+
expect(health.status).toBe('healthy');
|
|
1174
|
+
expect(health.checks).toBeDefined();
|
|
1175
|
+
});
|
|
1176
|
+
});
|
|
1177
|
+
});
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
**Running Fitness Functions in CI/CD**
|
|
1181
|
+
|
|
1182
|
+
```yaml
|
|
1183
|
+
# .github/workflows/architecture-tests.yml
|
|
1184
|
+
name: Architecture Fitness Functions
|
|
1185
|
+
|
|
1186
|
+
on: [push, pull_request]
|
|
1187
|
+
|
|
1188
|
+
jobs:
|
|
1189
|
+
architecture-tests:
|
|
1190
|
+
runs-on: ubuntu-latest
|
|
1191
|
+
|
|
1192
|
+
steps:
|
|
1193
|
+
- uses: actions/checkout@v3
|
|
1194
|
+
|
|
1195
|
+
- name: Setup Node.js
|
|
1196
|
+
uses: actions/setup-node@v3
|
|
1197
|
+
with:
|
|
1198
|
+
node-version: '18'
|
|
1199
|
+
|
|
1200
|
+
- name: Install dependencies
|
|
1201
|
+
run: npm ci
|
|
1202
|
+
|
|
1203
|
+
- name: Run fitness functions
|
|
1204
|
+
run: npm run test:architecture
|
|
1205
|
+
|
|
1206
|
+
- name: Upload results
|
|
1207
|
+
if: failure()
|
|
1208
|
+
uses: actions/upload-artifact@v3
|
|
1209
|
+
with:
|
|
1210
|
+
name: architecture-test-results
|
|
1211
|
+
path: test-results/
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1216
|
+
## Understanding
|
|
1217
|
+
|
|
1218
|
+
### When to Use Each Evaluation Method
|
|
1219
|
+
|
|
1220
|
+
**ATAM**
|
|
1221
|
+
- **Use When**: Evaluating major architectural decisions
|
|
1222
|
+
- **Best For**: New systems, major refactoring, architecture reviews
|
|
1223
|
+
- **Timing**: Before implementation, during design phase
|
|
1224
|
+
- **Effort**: High (2-3 days with stakeholders)
|
|
1225
|
+
- **Output**: Comprehensive risk assessment, tradeoff analysis
|
|
1226
|
+
|
|
1227
|
+
**Chaos Engineering**
|
|
1228
|
+
- **Use When**: Validating system resilience
|
|
1229
|
+
- **Best For**: Distributed systems, microservices, cloud-native apps
|
|
1230
|
+
- **Timing**: After initial deployment, continuously
|
|
1231
|
+
- **Effort**: Medium (setup experiments, monitor results)
|
|
1232
|
+
- **Output**: Confidence in system reliability, failure scenarios
|
|
1233
|
+
|
|
1234
|
+
**Architecture Reviews**
|
|
1235
|
+
- **Use When**: Regular validation of architecture
|
|
1236
|
+
- **Best For**: Ongoing projects, architecture governance
|
|
1237
|
+
- **Timing**: Quarterly, before major releases
|
|
1238
|
+
- **Effort**: Low to Medium (few hours to 1 day)
|
|
1239
|
+
- **Output**: Findings, recommendations, action items
|
|
1240
|
+
|
|
1241
|
+
**Fitness Functions**
|
|
1242
|
+
- **Use When**: Continuous architecture validation
|
|
1243
|
+
- **Best For**: All projects with CI/CD
|
|
1244
|
+
- **Timing**: Every commit, every build
|
|
1245
|
+
- **Effort**: Low (automated)
|
|
1246
|
+
- **Output**: Pass/fail on architectural constraints
|
|
1247
|
+
|
|
1248
|
+
### Best Practices
|
|
1249
|
+
|
|
1250
|
+
**ATAM Best Practices**
|
|
1251
|
+
1. Involve diverse stakeholders (business, dev, ops)
|
|
1252
|
+
2. Focus on quality attributes, not just functionality
|
|
1253
|
+
3. Document all decisions and rationale
|
|
1254
|
+
4. Prioritize scenarios by business value
|
|
1255
|
+
5. Follow up on identified risks
|
|
1256
|
+
6. Update architecture documentation based on findings
|
|
1257
|
+
|
|
1258
|
+
**Chaos Engineering Best Practices**
|
|
1259
|
+
1. Start small, increase blast radius gradually
|
|
1260
|
+
2. Always have a rollback plan
|
|
1261
|
+
3. Run experiments during business hours (with monitoring)
|
|
1262
|
+
4. Automate experiments for continuous validation
|
|
1263
|
+
5. Document all experiments and results
|
|
1264
|
+
6. Share learnings across teams
|
|
1265
|
+
7. Build a culture of resilience
|
|
1266
|
+
|
|
1267
|
+
**Architecture Review Best Practices**
|
|
1268
|
+
1. Prepare documentation in advance
|
|
1269
|
+
2. Focus on key decisions, not every detail
|
|
1270
|
+
3. Encourage constructive criticism
|
|
1271
|
+
4. Document findings and action items
|
|
1272
|
+
5. Follow up on recommendations
|
|
1273
|
+
6. Make reviews regular, not one-time events
|
|
1274
|
+
|
|
1275
|
+
**Fitness Function Best Practices**
|
|
1276
|
+
1. Start with critical constraints
|
|
1277
|
+
2. Make tests fast and reliable
|
|
1278
|
+
3. Run in CI/CD pipeline
|
|
1279
|
+
4. Fail the build on violations
|
|
1280
|
+
5. Keep tests maintainable
|
|
1281
|
+
6. Document the architectural intent
|
|
1282
|
+
7. Review and update regularly
|
|
1283
|
+
|
|
1284
|
+
### Common Pitfalls
|
|
1285
|
+
|
|
1286
|
+
**ATAM Pitfalls**
|
|
1287
|
+
- ❌ Not involving right stakeholders
|
|
1288
|
+
- ❌ Focusing only on technical aspects
|
|
1289
|
+
- ❌ Ignoring business drivers
|
|
1290
|
+
- ❌ Not following up on risks
|
|
1291
|
+
- ❌ Making it a one-time event
|
|
1292
|
+
|
|
1293
|
+
**Chaos Engineering Pitfalls**
|
|
1294
|
+
- ❌ Running experiments without monitoring
|
|
1295
|
+
- ❌ No rollback plan
|
|
1296
|
+
- ❌ Starting with too large blast radius
|
|
1297
|
+
- ❌ Not documenting experiments
|
|
1298
|
+
- ❌ Blaming teams for failures found
|
|
1299
|
+
|
|
1300
|
+
**Architecture Review Pitfalls**
|
|
1301
|
+
- ❌ Rubber-stamp reviews
|
|
1302
|
+
- ❌ Focusing on code style, not architecture
|
|
1303
|
+
- ❌ Not documenting findings
|
|
1304
|
+
- ❌ No follow-up on action items
|
|
1305
|
+
- ❌ Making it adversarial, not collaborative
|
|
1306
|
+
|
|
1307
|
+
**Fitness Function Pitfalls**
|
|
1308
|
+
- ❌ Tests that are too slow
|
|
1309
|
+
- ❌ Flaky tests that fail randomly
|
|
1310
|
+
- ❌ Testing implementation, not architecture
|
|
1311
|
+
- ❌ Too many tests (maintenance burden)
|
|
1312
|
+
- ❌ Not updating tests as architecture evolves
|
|
1313
|
+
|
|
1314
|
+
### Integration with Development Process
|
|
1315
|
+
|
|
1316
|
+
**Architecture Evaluation Lifecycle**
|
|
1317
|
+
|
|
1318
|
+
```
|
|
1319
|
+
Design Phase
|
|
1320
|
+
├── ATAM Evaluation
|
|
1321
|
+
│ ├── Identify quality attributes
|
|
1322
|
+
│ ├── Evaluate architectural approaches
|
|
1323
|
+
│ └── Document risks and tradeoffs
|
|
1324
|
+
│
|
|
1325
|
+
Implementation Phase
|
|
1326
|
+
├── Fitness Functions
|
|
1327
|
+
│ ├── Enforce architectural constraints
|
|
1328
|
+
│ ├── Run on every commit
|
|
1329
|
+
│ └── Fail build on violations
|
|
1330
|
+
│
|
|
1331
|
+
├── Architecture Reviews
|
|
1332
|
+
│ ├── Weekly/bi-weekly reviews
|
|
1333
|
+
│ ├── Validate implementation matches design
|
|
1334
|
+
│ └── Identify deviations early
|
|
1335
|
+
│
|
|
1336
|
+
Deployment Phase
|
|
1337
|
+
├── Performance Testing
|
|
1338
|
+
│ ├── Load testing
|
|
1339
|
+
│ ├── Stress testing
|
|
1340
|
+
│ └── Validate quality attributes
|
|
1341
|
+
│
|
|
1342
|
+
Production Phase
|
|
1343
|
+
├── Chaos Engineering
|
|
1344
|
+
│ ├── Validate resilience
|
|
1345
|
+
│ ├── Test failure scenarios
|
|
1346
|
+
│ └── Build confidence
|
|
1347
|
+
│
|
|
1348
|
+
├── Periodic Reviews
|
|
1349
|
+
│ ├── Quarterly architecture reviews
|
|
1350
|
+
│ ├── Assess technical debt
|
|
1351
|
+
│ └── Plan improvements
|
|
1352
|
+
```
|
|
1353
|
+
|
|
1354
|
+
---
|
|
1355
|
+
|
|
1356
|
+
## References
|
|
1357
|
+
|
|
1358
|
+
### Standards and Frameworks
|
|
1359
|
+
- **ISO/IEC 42010** - Architecture description standard
|
|
1360
|
+
- **SEI ATAM** - Architecture Tradeoff Analysis Method
|
|
1361
|
+
- **Principles of Chaos Engineering** - Netflix chaos engineering principles
|
|
1362
|
+
|
|
1363
|
+
### Books
|
|
1364
|
+
- **"Software Architecture in Practice"** by Bass, Clements, Kazman (ATAM)
|
|
1365
|
+
- **"Release It!"** by Michael Nygard (Resilience patterns)
|
|
1366
|
+
- **"Chaos Engineering"** by Casey Rosenthal, Nora Jones
|
|
1367
|
+
- **"Building Evolutionary Architectures"** by Ford, Parsons, Kua (Fitness functions)
|
|
1368
|
+
|
|
1369
|
+
### Tools
|
|
1370
|
+
- **ATAM**: SEI ATAM method, architecture evaluation templates
|
|
1371
|
+
- **Chaos Engineering**: Chaos Monkey, Chaos Toolkit, Gremlin, Litmus
|
|
1372
|
+
- **Fitness Functions**: ArchUnit, NDepend, SonarQube, custom tests
|
|
1373
|
+
- **Performance Testing**: JMeter, Gatling, k6, Locust
|
|
1374
|
+
- **Monitoring**: Prometheus, Grafana, Datadog, New Relic
|
|
1375
|
+
|
|
1376
|
+
### Online Resources
|
|
1377
|
+
- **SEI ATAM Resources**: https://www.sei.cmu.edu/our-work/atam/
|
|
1378
|
+
- **Principles of Chaos Engineering**: https://principlesofchaos.org/
|
|
1379
|
+
- **Netflix Tech Blog**: https://netflixtechblog.com/ (Chaos engineering)
|
|
1380
|
+
- **Thoughtworks Technology Radar**: Architecture testing practices
|
|
1381
|
+
|