@mytechtoday/augment-extensions 1.2.2 → 1.3.1
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/LICENSE +22 -22
- package/augment-extensions/domain-rules/software-architecture/README.md +143 -143
- package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -961
- package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -990
- package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -882
- package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -703
- package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -957
- package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -747
- package/augment-extensions/domain-rules/software-architecture/module.json +119 -119
- package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -763
- package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -409
- package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -684
- package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -1381
- package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -616
- package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -306
- package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -554
- package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -776
- package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -503
- package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -1199
- package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -351
- package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -556
- package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -797
- package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -1345
- package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -1039
- package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -711
- package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -568
- package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -961
- package/augment-extensions/visual-design/CHANGELOG.md +132 -0
- package/augment-extensions/visual-design/README.md +255 -0
- package/augment-extensions/visual-design/__tests__/README.md +119 -0
- package/augment-extensions/visual-design/__tests__/style-selector.test.ts +172 -0
- package/augment-extensions/visual-design/__tests__/vendor-styles.test.ts +214 -0
- package/augment-extensions/visual-design/domains/other/ai-prompt-helper.ts +157 -0
- package/augment-extensions/visual-design/domains/other/dotnet-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/linux-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/other/mobile-application.ts +157 -0
- package/augment-extensions/visual-design/domains/other/motion-picture.ts +156 -0
- package/augment-extensions/visual-design/domains/other/os-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/print-campaigns.ts +158 -0
- package/augment-extensions/visual-design/domains/other/web-app.ts +157 -0
- package/augment-extensions/visual-design/domains/other/website.ts +161 -0
- package/augment-extensions/visual-design/domains/other/windows-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/web-page-styles/amazon-cloudscape.ts +506 -0
- package/augment-extensions/visual-design/domains/web-page-styles/google-modern.ts +615 -0
- package/augment-extensions/visual-design/domains/web-page-styles/microsoft-fluent.ts +531 -0
- package/augment-extensions/visual-design/examples/README.md +97 -0
- package/augment-extensions/visual-design/examples/ai-prompt-generation.md +233 -0
- package/augment-extensions/visual-design/examples/basic-usage.md +216 -0
- package/augment-extensions/visual-design/examples/domain-workflows.md +257 -0
- package/augment-extensions/visual-design/examples/vendor-comparison.md +247 -0
- package/augment-extensions/visual-design/module.json +78 -0
- package/augment-extensions/visual-design/style-selector.ts +177 -0
- package/augment-extensions/visual-design/types.ts +302 -0
- package/augment-extensions/visual-design/visual-design-core.ts +469 -0
- package/augment-extensions/workflows/adr-support/README.md +227 -0
- package/augment-extensions/workflows/adr-support/__tests__/adr-validator.test.ts +203 -0
- package/augment-extensions/workflows/adr-support/adr-validator.ts +162 -0
- package/augment-extensions/workflows/adr-support/examples/complete-lifecycle-example.md +449 -0
- package/augment-extensions/workflows/adr-support/examples/integration-example.md +580 -0
- package/augment-extensions/workflows/adr-support/examples/superseding-example.md +436 -0
- package/augment-extensions/workflows/adr-support/module.json +112 -0
- package/augment-extensions/workflows/adr-support/rules/adr-creation.md +372 -0
- package/augment-extensions/workflows/adr-support/rules/beads-integration.md +443 -0
- package/augment-extensions/workflows/adr-support/rules/conflict-detection.md +486 -0
- package/augment-extensions/workflows/adr-support/rules/decision-detection.md +362 -0
- package/augment-extensions/workflows/adr-support/rules/lifecycle-management.md +427 -0
- package/augment-extensions/workflows/adr-support/rules/openspec-integration.md +465 -0
- package/augment-extensions/workflows/adr-support/rules/template-selection.md +405 -0
- package/augment-extensions/workflows/adr-support/rules/validation-rules.md +543 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-config.json +191 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-metadata.json +172 -0
- package/augment-extensions/workflows/adr-support/templates/business-case.md +235 -0
- package/augment-extensions/workflows/adr-support/templates/madr-elaborate.md +197 -0
- package/augment-extensions/workflows/adr-support/templates/madr-simple.md +68 -0
- package/augment-extensions/workflows/adr-support/templates/nygard.md +84 -0
- package/augment-extensions/writing-standards/screenplay/rules/file-organization.md +213 -213
- package/augment-extensions/writing-standards/screenplay/utils/__tests__/file-organization.test.ts +169 -169
- package/augment-extensions/writing-standards/screenplay/utils/file-organization.ts +165 -165
- package/cli/dist/utils/auto-sync.js +19 -19
- package/package.json +5 -3
- package/augment-extensions/workflows/openspec/README.md +0 -96
- package/augment-extensions/workflows/openspec/examples/complete-change-example.md +0 -244
- package/augment-extensions/workflows/openspec/module.json +0 -54
- package/augment-extensions/workflows/openspec/rules/best-practices.md +0 -272
- package/augment-extensions/workflows/openspec/rules/manual-setup.md +0 -231
- package/augment-extensions/workflows/openspec/rules/spec-format.md +0 -236
- package/augment-extensions/workflows/openspec/rules/workflow.md +0 -214
|
@@ -1,797 +1,797 @@
|
|
|
1
|
-
# Quality Attributes
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This document covers non-functional requirements (quality attributes) that define how a system performs its functions. Quality attributes are critical architectural drivers that shape system design and implementation.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Knowledge
|
|
10
|
-
|
|
11
|
-
### Performance
|
|
12
|
-
|
|
13
|
-
**Definition**
|
|
14
|
-
- System's responsiveness and throughput under specific workload
|
|
15
|
-
- Measured in response time, latency, throughput, resource utilization
|
|
16
|
-
- Critical for user experience and system efficiency
|
|
17
|
-
- Often involves trade-offs with other attributes
|
|
18
|
-
|
|
19
|
-
**Key Metrics**
|
|
20
|
-
- **Response Time**: Time to respond to a request
|
|
21
|
-
- **Latency**: Delay before transfer begins
|
|
22
|
-
- **Throughput**: Requests processed per unit time
|
|
23
|
-
- **Resource Utilization**: CPU, memory, network, disk usage
|
|
24
|
-
|
|
25
|
-
**Performance Tactics**
|
|
26
|
-
- Caching (in-memory, distributed, CDN)
|
|
27
|
-
- Load balancing (horizontal scaling)
|
|
28
|
-
- Asynchronous processing (queues, workers)
|
|
29
|
-
- Database optimization (indexing, query optimization)
|
|
30
|
-
- Code optimization (algorithms, data structures)
|
|
31
|
-
- Resource pooling (connection pools, thread pools)
|
|
32
|
-
|
|
33
|
-
**Performance Patterns**
|
|
34
|
-
- Cache-Aside Pattern
|
|
35
|
-
- Read-Through/Write-Through Cache
|
|
36
|
-
- Circuit Breaker (prevent cascading failures)
|
|
37
|
-
- Bulkhead (isolate resources)
|
|
38
|
-
- CQRS (separate read/write paths)
|
|
39
|
-
|
|
40
|
-
### Reliability
|
|
41
|
-
|
|
42
|
-
**Definition**
|
|
43
|
-
- System's ability to function correctly over time
|
|
44
|
-
- Measured in uptime, MTBF (Mean Time Between Failures), MTTR (Mean Time To Recovery)
|
|
45
|
-
- Includes fault tolerance and error handling
|
|
46
|
-
- Critical for mission-critical systems
|
|
47
|
-
|
|
48
|
-
**Key Metrics**
|
|
49
|
-
- **Availability**: Percentage of time system is operational (e.g., 99.9% = "three nines")
|
|
50
|
-
- **MTBF**: Average time between failures
|
|
51
|
-
- **MTTR**: Average time to recover from failure
|
|
52
|
-
- **Error Rate**: Percentage of failed requests
|
|
53
|
-
|
|
54
|
-
**Reliability Tactics**
|
|
55
|
-
- Redundancy (active-active, active-passive)
|
|
56
|
-
- Health checks and monitoring
|
|
57
|
-
- Graceful degradation
|
|
58
|
-
- Retry mechanisms (exponential backoff)
|
|
59
|
-
- Timeouts and circuit breakers
|
|
60
|
-
- Data replication and backup
|
|
61
|
-
|
|
62
|
-
**Reliability Patterns**
|
|
63
|
-
- Retry Pattern
|
|
64
|
-
- Circuit Breaker Pattern
|
|
65
|
-
- Bulkhead Pattern
|
|
66
|
-
- Health Endpoint Monitoring
|
|
67
|
-
- Compensating Transaction
|
|
68
|
-
|
|
69
|
-
### Maintainability
|
|
70
|
-
|
|
71
|
-
**Definition**
|
|
72
|
-
- Ease with which system can be modified, extended, and debugged
|
|
73
|
-
- Measured in time to fix bugs, add features, or refactor
|
|
74
|
-
- Includes code quality, documentation, and testability
|
|
75
|
-
- Critical for long-term system evolution
|
|
76
|
-
|
|
77
|
-
**Key Aspects**
|
|
78
|
-
- **Modularity**: Well-defined, independent modules
|
|
79
|
-
- **Readability**: Clear, self-documenting code
|
|
80
|
-
- **Testability**: Easy to write and run tests
|
|
81
|
-
- **Documentation**: Comprehensive, up-to-date docs
|
|
82
|
-
- **Debuggability**: Easy to diagnose and fix issues
|
|
83
|
-
|
|
84
|
-
**Maintainability Tactics**
|
|
85
|
-
- Clear separation of concerns
|
|
86
|
-
- Consistent coding standards
|
|
87
|
-
- Comprehensive testing (unit, integration, e2e)
|
|
88
|
-
- Automated builds and deployments
|
|
89
|
-
- Version control and code reviews
|
|
90
|
-
- Refactoring and technical debt management
|
|
91
|
-
|
|
92
|
-
**Maintainability Patterns**
|
|
93
|
-
- Dependency Injection
|
|
94
|
-
- Repository Pattern
|
|
95
|
-
- Factory Pattern
|
|
96
|
-
- Strategy Pattern
|
|
97
|
-
- Observer Pattern
|
|
98
|
-
|
|
99
|
-
### Scalability
|
|
100
|
-
|
|
101
|
-
**Definition**
|
|
102
|
-
- System's ability to handle increased load
|
|
103
|
-
- Measured in concurrent users, requests per second, data volume
|
|
104
|
-
- Includes horizontal (add servers) and vertical (add resources) scaling
|
|
105
|
-
- Critical for growing systems
|
|
106
|
-
|
|
107
|
-
**Scaling Dimensions**
|
|
108
|
-
- **Horizontal Scaling**: Add more servers/instances
|
|
109
|
-
- **Vertical Scaling**: Add more resources (CPU, RAM) to existing servers
|
|
110
|
-
- **Data Scaling**: Partition data across multiple databases
|
|
111
|
-
- **Functional Scaling**: Decompose into microservices
|
|
112
|
-
|
|
113
|
-
**Scalability Tactics**
|
|
114
|
-
- Stateless services (enable horizontal scaling)
|
|
115
|
-
- Database sharding and partitioning
|
|
116
|
-
- Caching layers (reduce database load)
|
|
117
|
-
- Asynchronous processing (decouple components)
|
|
118
|
-
- Load balancing (distribute traffic)
|
|
119
|
-
- Auto-scaling (dynamic resource allocation)
|
|
120
|
-
|
|
121
|
-
**Scalability Patterns**
|
|
122
|
-
- Sharding Pattern
|
|
123
|
-
- CQRS (Command Query Responsibility Segregation)
|
|
124
|
-
- Event Sourcing
|
|
125
|
-
- Saga Pattern (distributed transactions)
|
|
126
|
-
- Strangler Fig (incremental migration)
|
|
127
|
-
|
|
128
|
-
### Security
|
|
129
|
-
|
|
130
|
-
**Definition**
|
|
131
|
-
- System's ability to protect data and resist attacks
|
|
132
|
-
- Measured in vulnerabilities, incidents, compliance
|
|
133
|
-
- Includes authentication, authorization, encryption, auditing
|
|
134
|
-
- Critical for all systems handling sensitive data
|
|
135
|
-
|
|
136
|
-
**Security Principles**
|
|
137
|
-
- **Confidentiality**: Protect data from unauthorized access
|
|
138
|
-
- **Integrity**: Ensure data is not tampered with
|
|
139
|
-
- **Availability**: Ensure authorized access when needed
|
|
140
|
-
- **Non-repudiation**: Prove actions occurred
|
|
141
|
-
- **Authentication**: Verify identity
|
|
142
|
-
- **Authorization**: Control access to resources
|
|
143
|
-
|
|
144
|
-
**Security Tactics**
|
|
145
|
-
- Authentication (OAuth, JWT, SAML)
|
|
146
|
-
- Authorization (RBAC, ABAC)
|
|
147
|
-
- Encryption (at rest, in transit)
|
|
148
|
-
- Input validation and sanitization
|
|
149
|
-
- Security headers (CORS, CSP, HSTS)
|
|
150
|
-
- Rate limiting and throttling
|
|
151
|
-
- Audit logging
|
|
152
|
-
|
|
153
|
-
**Security Patterns**
|
|
154
|
-
- Zero Trust Architecture
|
|
155
|
-
- Defense in Depth
|
|
156
|
-
- Least Privilege
|
|
157
|
-
- Secure by Default
|
|
158
|
-
- Fail Securely
|
|
159
|
-
|
|
160
|
-
### Usability
|
|
161
|
-
|
|
162
|
-
**Definition**
|
|
163
|
-
- Ease with which users can accomplish tasks
|
|
164
|
-
- Measured in task completion time, error rate, user satisfaction
|
|
165
|
-
- Includes UI/UX design, accessibility, learnability
|
|
166
|
-
- Critical for user-facing systems
|
|
167
|
-
|
|
168
|
-
**Usability Aspects**
|
|
169
|
-
- **Learnability**: How quickly users learn the system
|
|
170
|
-
- **Efficiency**: How quickly users perform tasks
|
|
171
|
-
- **Memorability**: How easily users remember how to use it
|
|
172
|
-
- **Error Prevention**: How well system prevents errors
|
|
173
|
-
- **Satisfaction**: How pleasant the experience is
|
|
174
|
-
|
|
175
|
-
**Usability Tactics**
|
|
176
|
-
- Consistent UI patterns
|
|
177
|
-
- Clear feedback and error messages
|
|
178
|
-
- Progressive disclosure (show complexity gradually)
|
|
179
|
-
- Accessibility (WCAG compliance)
|
|
180
|
-
- Responsive design (mobile, tablet, desktop)
|
|
181
|
-
- User testing and feedback
|
|
182
|
-
|
|
183
|
-
### Testability
|
|
184
|
-
|
|
185
|
-
**Definition**
|
|
186
|
-
- Ease with which system can be tested
|
|
187
|
-
- Measured in test coverage, test execution time, test maintainability
|
|
188
|
-
- Includes unit, integration, and end-to-end testing
|
|
189
|
-
- Critical for quality assurance
|
|
190
|
-
|
|
191
|
-
**Testability Tactics**
|
|
192
|
-
- Dependency injection (mock dependencies)
|
|
193
|
-
- Interface-based design (test doubles)
|
|
194
|
-
- Separation of concerns (isolated testing)
|
|
195
|
-
- Test automation (CI/CD pipelines)
|
|
196
|
-
- Test data management
|
|
197
|
-
- Observability (logging, metrics, tracing)
|
|
198
|
-
|
|
199
|
-
### Interoperability
|
|
200
|
-
|
|
201
|
-
**Definition**
|
|
202
|
-
- System's ability to work with other systems
|
|
203
|
-
- Measured in integration points, data exchange formats, API compatibility
|
|
204
|
-
- Includes standards compliance and protocol support
|
|
205
|
-
- Critical for enterprise systems
|
|
206
|
-
|
|
207
|
-
**Interoperability Tactics**
|
|
208
|
-
- Standard protocols (HTTP, gRPC, AMQP)
|
|
209
|
-
- Standard data formats (JSON, XML, Protocol Buffers)
|
|
210
|
-
- API versioning and backward compatibility
|
|
211
|
-
- Service contracts and schemas
|
|
212
|
-
- Integration patterns (ESB, API Gateway)
|
|
213
|
-
|
|
214
|
-
### Portability
|
|
215
|
-
|
|
216
|
-
**Definition**
|
|
217
|
-
- Ease with which system can be moved to different environments
|
|
218
|
-
- Measured in deployment time, configuration complexity
|
|
219
|
-
- Includes platform independence and containerization
|
|
220
|
-
- Critical for cloud-native systems
|
|
221
|
-
|
|
222
|
-
**Portability Tactics**
|
|
223
|
-
- Containerization (Docker, Kubernetes)
|
|
224
|
-
- Infrastructure as Code (Terraform, CloudFormation)
|
|
225
|
-
- Environment-specific configuration
|
|
226
|
-
- Platform abstraction layers
|
|
227
|
-
- Cloud-agnostic design
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
## Skills
|
|
232
|
-
|
|
233
|
-
### Specifying Quality Attributes
|
|
234
|
-
|
|
235
|
-
**Quality Attribute Scenarios**
|
|
236
|
-
|
|
237
|
-
A quality attribute scenario consists of:
|
|
238
|
-
1. **Source**: Entity generating the stimulus
|
|
239
|
-
2. **Stimulus**: Condition affecting the system
|
|
240
|
-
3. **Environment**: System state when stimulus occurs
|
|
241
|
-
4. **Artifact**: Part of system affected
|
|
242
|
-
5. **Response**: Activity resulting from stimulus
|
|
243
|
-
6. **Response Measure**: Measurable outcome
|
|
244
|
-
|
|
245
|
-
**Example: Performance Scenario**
|
|
246
|
-
- **Source**: User
|
|
247
|
-
- **Stimulus**: Initiates transaction
|
|
248
|
-
- **Environment**: Normal operation
|
|
249
|
-
- **Artifact**: System
|
|
250
|
-
- **Response**: Process transaction
|
|
251
|
-
- **Response Measure**: Within 2 seconds for 95% of requests
|
|
252
|
-
|
|
253
|
-
**Example: Availability Scenario**
|
|
254
|
-
- **Source**: Internal fault
|
|
255
|
-
- **Stimulus**: Server crashes
|
|
256
|
-
- **Environment**: Normal operation
|
|
257
|
-
- **Artifact**: System
|
|
258
|
-
- **Response**: Failover to backup server
|
|
259
|
-
- **Response Measure**: Within 30 seconds, no data loss
|
|
260
|
-
|
|
261
|
-
### Measuring Quality Attributes
|
|
262
|
-
|
|
263
|
-
**Performance Metrics**
|
|
264
|
-
- Response time percentiles (p50, p95, p99)
|
|
265
|
-
- Throughput (requests/second)
|
|
266
|
-
- Resource utilization (CPU, memory, network)
|
|
267
|
-
- Apdex score (Application Performance Index)
|
|
268
|
-
|
|
269
|
-
**Reliability Metrics**
|
|
270
|
-
- Uptime percentage (99.9%, 99.99%, 99.999%)
|
|
271
|
-
- MTBF (Mean Time Between Failures)
|
|
272
|
-
- MTTR (Mean Time To Recovery)
|
|
273
|
-
- Error rate (errors per 1000 requests)
|
|
274
|
-
|
|
275
|
-
**Maintainability Metrics**
|
|
276
|
-
- Code coverage (unit, integration tests)
|
|
277
|
-
- Cyclomatic complexity
|
|
278
|
-
- Technical debt ratio
|
|
279
|
-
- Time to fix bugs
|
|
280
|
-
|
|
281
|
-
**Security Metrics**
|
|
282
|
-
- Vulnerability count (critical, high, medium, low)
|
|
283
|
-
- Time to patch vulnerabilities
|
|
284
|
-
- Failed authentication attempts
|
|
285
|
-
- Security incidents
|
|
286
|
-
|
|
287
|
-
### Trade-offs Between Quality Attributes
|
|
288
|
-
|
|
289
|
-
**Common Trade-offs**
|
|
290
|
-
|
|
291
|
-
**Performance vs. Security**
|
|
292
|
-
- Encryption adds latency
|
|
293
|
-
- Authentication/authorization adds overhead
|
|
294
|
-
- Balance: Use efficient algorithms, cache auth tokens
|
|
295
|
-
|
|
296
|
-
**Performance vs. Maintainability**
|
|
297
|
-
- Optimized code may be harder to read
|
|
298
|
-
- Caching adds complexity
|
|
299
|
-
- Balance: Optimize only bottlenecks, document optimizations
|
|
300
|
-
|
|
301
|
-
**Scalability vs. Consistency**
|
|
302
|
-
- Distributed systems face CAP theorem constraints
|
|
303
|
-
- Eventual consistency improves scalability
|
|
304
|
-
- Balance: Choose consistency model based on requirements
|
|
305
|
-
|
|
306
|
-
**Flexibility vs. Performance**
|
|
307
|
-
- Abstraction layers add overhead
|
|
308
|
-
- Dynamic dispatch slower than static
|
|
309
|
-
- Balance: Abstract only where needed, measure impact
|
|
310
|
-
|
|
311
|
-
**Security vs. Usability**
|
|
312
|
-
- Strong authentication may frustrate users
|
|
313
|
-
- Strict validation may reject valid input
|
|
314
|
-
- Balance: Risk-based authentication, clear error messages
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## Examples
|
|
319
|
-
|
|
320
|
-
### Performance Optimization
|
|
321
|
-
|
|
322
|
-
**Caching Strategy**
|
|
323
|
-
```typescript
|
|
324
|
-
interface CacheService {
|
|
325
|
-
get<T>(key: string): Promise<T | null>;
|
|
326
|
-
set<T>(key: string, value: T, ttl?: number): Promise<void>;
|
|
327
|
-
delete(key: string): Promise<void>;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
class UserService {
|
|
331
|
-
constructor(
|
|
332
|
-
private userRepository: UserRepository,
|
|
333
|
-
private cache: CacheService
|
|
334
|
-
) {}
|
|
335
|
-
|
|
336
|
-
async getUser(id: string): Promise<User> {
|
|
337
|
-
// Try cache first
|
|
338
|
-
const cached = await this.cache.get<User>(`user:${id}`);
|
|
339
|
-
if (cached) {
|
|
340
|
-
return cached;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Cache miss - fetch from database
|
|
344
|
-
const user = await this.userRepository.findById(id);
|
|
345
|
-
if (user) {
|
|
346
|
-
// Cache for 5 minutes
|
|
347
|
-
await this.cache.set(`user:${id}`, user, 300);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
return user;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
async updateUser(id: string, data: Partial<User>): Promise<User> {
|
|
354
|
-
const user = await this.userRepository.update(id, data);
|
|
355
|
-
|
|
356
|
-
// Invalidate cache
|
|
357
|
-
await this.cache.delete(`user:${id}`);
|
|
358
|
-
|
|
359
|
-
return user;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
**Database Query Optimization**
|
|
365
|
-
```typescript
|
|
366
|
-
// Bad: N+1 query problem
|
|
367
|
-
async function getOrdersWithItems(userId: string): Promise<Order[]> {
|
|
368
|
-
const orders = await db.query('SELECT * FROM orders WHERE user_id = ?', [userId]);
|
|
369
|
-
|
|
370
|
-
for (const order of orders) {
|
|
371
|
-
// N additional queries!
|
|
372
|
-
order.items = await db.query('SELECT * FROM order_items WHERE order_id = ?', [order.id]);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return orders;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Good: Single query with JOIN
|
|
379
|
-
async function getOrdersWithItems(userId: string): Promise<Order[]> {
|
|
380
|
-
const rows = await db.query(`
|
|
381
|
-
SELECT
|
|
382
|
-
o.*,
|
|
383
|
-
oi.id as item_id,
|
|
384
|
-
oi.product_id,
|
|
385
|
-
oi.quantity,
|
|
386
|
-
oi.price
|
|
387
|
-
FROM orders o
|
|
388
|
-
LEFT JOIN order_items oi ON o.id = oi.order_id
|
|
389
|
-
WHERE o.user_id = ?
|
|
390
|
-
`, [userId]);
|
|
391
|
-
|
|
392
|
-
// Group items by order
|
|
393
|
-
const ordersMap = new Map<string, Order>();
|
|
394
|
-
for (const row of rows) {
|
|
395
|
-
if (!ordersMap.has(row.id)) {
|
|
396
|
-
ordersMap.set(row.id, {
|
|
397
|
-
id: row.id,
|
|
398
|
-
userId: row.user_id,
|
|
399
|
-
items: []
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (row.item_id) {
|
|
404
|
-
ordersMap.get(row.id)!.items.push({
|
|
405
|
-
id: row.item_id,
|
|
406
|
-
productId: row.product_id,
|
|
407
|
-
quantity: row.quantity,
|
|
408
|
-
price: row.price
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return Array.from(ordersMap.values());
|
|
414
|
-
}
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### Reliability Patterns
|
|
418
|
-
|
|
419
|
-
**Circuit Breaker**
|
|
420
|
-
```typescript
|
|
421
|
-
enum CircuitState {
|
|
422
|
-
CLOSED, // Normal operation
|
|
423
|
-
OPEN, // Failing, reject requests
|
|
424
|
-
HALF_OPEN // Testing if service recovered
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
class CircuitBreaker {
|
|
428
|
-
private state: CircuitState = CircuitState.CLOSED;
|
|
429
|
-
private failureCount = 0;
|
|
430
|
-
private lastFailureTime?: Date;
|
|
431
|
-
|
|
432
|
-
constructor(
|
|
433
|
-
private failureThreshold: number = 5,
|
|
434
|
-
private timeout: number = 60000, // 1 minute
|
|
435
|
-
private successThreshold: number = 2
|
|
436
|
-
) {}
|
|
437
|
-
|
|
438
|
-
async execute<T>(operation: () => Promise<T>): Promise<T> {
|
|
439
|
-
if (this.state === CircuitState.OPEN) {
|
|
440
|
-
if (this.shouldAttemptReset()) {
|
|
441
|
-
this.state = CircuitState.HALF_OPEN;
|
|
442
|
-
} else {
|
|
443
|
-
throw new Error('Circuit breaker is OPEN');
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
try {
|
|
448
|
-
const result = await operation();
|
|
449
|
-
this.onSuccess();
|
|
450
|
-
return result;
|
|
451
|
-
} catch (error) {
|
|
452
|
-
this.onFailure();
|
|
453
|
-
throw error;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
private onSuccess(): void {
|
|
458
|
-
this.failureCount = 0;
|
|
459
|
-
this.state = CircuitState.CLOSED;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
private onFailure(): void {
|
|
463
|
-
this.failureCount++;
|
|
464
|
-
this.lastFailureTime = new Date();
|
|
465
|
-
|
|
466
|
-
if (this.failureCount >= this.failureThreshold) {
|
|
467
|
-
this.state = CircuitState.OPEN;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
private shouldAttemptReset(): boolean {
|
|
472
|
-
return this.lastFailureTime &&
|
|
473
|
-
Date.now() - this.lastFailureTime.getTime() >= this.timeout;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Usage
|
|
478
|
-
const breaker = new CircuitBreaker();
|
|
479
|
-
const paymentService = {
|
|
480
|
-
async processPayment(amount: number): Promise<PaymentResult> {
|
|
481
|
-
return breaker.execute(async () => {
|
|
482
|
-
// Call external payment API
|
|
483
|
-
const response = await fetch('https://api.payment.com/charge', {
|
|
484
|
-
method: 'POST',
|
|
485
|
-
body: JSON.stringify({ amount })
|
|
486
|
-
});
|
|
487
|
-
return response.json();
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
**Retry with Exponential Backoff**
|
|
494
|
-
```typescript
|
|
495
|
-
async function retryWithBackoff<T>(
|
|
496
|
-
operation: () => Promise<T>,
|
|
497
|
-
maxRetries: number = 3,
|
|
498
|
-
baseDelay: number = 1000
|
|
499
|
-
): Promise<T> {
|
|
500
|
-
let lastError: Error;
|
|
501
|
-
|
|
502
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
503
|
-
try {
|
|
504
|
-
return await operation();
|
|
505
|
-
} catch (error) {
|
|
506
|
-
lastError = error as Error;
|
|
507
|
-
|
|
508
|
-
if (attempt < maxRetries) {
|
|
509
|
-
// Exponential backoff: 1s, 2s, 4s, 8s...
|
|
510
|
-
const delay = baseDelay * Math.pow(2, attempt);
|
|
511
|
-
// Add jitter to prevent thundering herd
|
|
512
|
-
const jitter = Math.random() * 1000;
|
|
513
|
-
await new Promise(resolve => setTimeout(resolve, delay + jitter));
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
throw lastError!;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Usage
|
|
522
|
-
const data = await retryWithBackoff(
|
|
523
|
-
() => fetch('https://api.example.com/data').then(r => r.json()),
|
|
524
|
-
3,
|
|
525
|
-
1000
|
|
526
|
-
);
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### Security Implementation
|
|
530
|
-
|
|
531
|
-
**Authentication and Authorization**
|
|
532
|
-
```typescript
|
|
533
|
-
interface User {
|
|
534
|
-
id: string;
|
|
535
|
-
email: string;
|
|
536
|
-
roles: string[];
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
interface AuthService {
|
|
540
|
-
authenticate(email: string, password: string): Promise<string>; // Returns JWT
|
|
541
|
-
verifyToken(token: string): Promise<User>;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Role-Based Access Control (RBAC)
|
|
545
|
-
function requireRole(...roles: string[]) {
|
|
546
|
-
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
547
|
-
const originalMethod = descriptor.value;
|
|
548
|
-
|
|
549
|
-
descriptor.value = async function (...args: any[]) {
|
|
550
|
-
const user = (this as any).currentUser as User;
|
|
551
|
-
|
|
552
|
-
if (!user) {
|
|
553
|
-
throw new Error('Unauthorized');
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
const hasRole = roles.some(role => user.roles.includes(role));
|
|
557
|
-
if (!hasRole) {
|
|
558
|
-
throw new Error('Forbidden');
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return originalMethod.apply(this, args);
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
return descriptor;
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
class OrderController {
|
|
569
|
-
constructor(private currentUser: User) {}
|
|
570
|
-
|
|
571
|
-
@requireRole('admin', 'manager')
|
|
572
|
-
async deleteOrder(orderId: string): Promise<void> {
|
|
573
|
-
// Only admins and managers can delete orders
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
@requireRole('user')
|
|
577
|
-
async viewOrder(orderId: string): Promise<Order> {
|
|
578
|
-
// Any authenticated user can view orders
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
**Input Validation and Sanitization**
|
|
584
|
-
```typescript
|
|
585
|
-
import { z } from 'zod';
|
|
586
|
-
|
|
587
|
-
// Define schema
|
|
588
|
-
const CreateUserSchema = z.object({
|
|
589
|
-
email: z.string().email(),
|
|
590
|
-
password: z.string().min(8).max(100),
|
|
591
|
-
name: z.string().min(1).max(100),
|
|
592
|
-
age: z.number().int().min(18).max(120).optional()
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
type CreateUserInput = z.infer<typeof CreateUserSchema>;
|
|
596
|
-
|
|
597
|
-
class UserController {
|
|
598
|
-
async createUser(input: unknown): Promise<User> {
|
|
599
|
-
// Validate and sanitize input
|
|
600
|
-
const validatedInput = CreateUserSchema.parse(input);
|
|
601
|
-
|
|
602
|
-
// Hash password
|
|
603
|
-
const hashedPassword = await bcrypt.hash(validatedInput.password, 10);
|
|
604
|
-
|
|
605
|
-
// Create user
|
|
606
|
-
return this.userRepository.create({
|
|
607
|
-
...validatedInput,
|
|
608
|
-
password: hashedPassword
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
### Maintainability Practices
|
|
615
|
-
|
|
616
|
-
**Dependency Injection for Testability**
|
|
617
|
-
```typescript
|
|
618
|
-
// Bad: Hard to test
|
|
619
|
-
class OrderService {
|
|
620
|
-
async createOrder(data: OrderData): Promise<Order> {
|
|
621
|
-
const db = new Database(); // Hard-coded dependency
|
|
622
|
-
const emailService = new EmailService(); // Hard-coded dependency
|
|
623
|
-
|
|
624
|
-
const order = await db.insert('orders', data);
|
|
625
|
-
await emailService.sendOrderConfirmation(order);
|
|
626
|
-
|
|
627
|
-
return order;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// Good: Easy to test
|
|
632
|
-
interface OrderRepository {
|
|
633
|
-
create(data: OrderData): Promise<Order>;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
interface EmailService {
|
|
637
|
-
sendOrderConfirmation(order: Order): Promise<void>;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
class OrderService {
|
|
641
|
-
constructor(
|
|
642
|
-
private orderRepository: OrderRepository,
|
|
643
|
-
private emailService: EmailService
|
|
644
|
-
) {}
|
|
645
|
-
|
|
646
|
-
async createOrder(data: OrderData): Promise<Order> {
|
|
647
|
-
const order = await this.orderRepository.create(data);
|
|
648
|
-
await this.emailService.sendOrderConfirmation(order);
|
|
649
|
-
return order;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// Test with mocks
|
|
654
|
-
describe('OrderService', () => {
|
|
655
|
-
it('should send confirmation email after creating order', async () => {
|
|
656
|
-
const mockRepository: OrderRepository = {
|
|
657
|
-
create: jest.fn().mockResolvedValue({ id: '123', ...orderData })
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
const mockEmailService: EmailService = {
|
|
661
|
-
sendOrderConfirmation: jest.fn().mockResolvedValue(undefined)
|
|
662
|
-
};
|
|
663
|
-
|
|
664
|
-
const service = new OrderService(mockRepository, mockEmailService);
|
|
665
|
-
await service.createOrder(orderData);
|
|
666
|
-
|
|
667
|
-
expect(mockEmailService.sendOrderConfirmation).toHaveBeenCalledWith(
|
|
668
|
-
expect.objectContaining({ id: '123' })
|
|
669
|
-
);
|
|
670
|
-
});
|
|
671
|
-
});
|
|
672
|
-
```
|
|
673
|
-
|
|
674
|
-
---
|
|
675
|
-
|
|
676
|
-
## Understanding
|
|
677
|
-
|
|
678
|
-
### Quality Attribute Workshops
|
|
679
|
-
|
|
680
|
-
**Steps to Identify Quality Attributes**
|
|
681
|
-
|
|
682
|
-
1. **Stakeholder Identification**
|
|
683
|
-
- Business stakeholders
|
|
684
|
-
- End users
|
|
685
|
-
- Developers and operators
|
|
686
|
-
- Security and compliance teams
|
|
687
|
-
|
|
688
|
-
2. **Scenario Elicitation**
|
|
689
|
-
- Brainstorm quality attribute scenarios
|
|
690
|
-
- Prioritize scenarios by importance
|
|
691
|
-
- Define measurable response measures
|
|
692
|
-
|
|
693
|
-
3. **Architecture Analysis**
|
|
694
|
-
- Identify architectural tactics for each scenario
|
|
695
|
-
- Analyze trade-offs
|
|
696
|
-
- Document decisions and rationale
|
|
697
|
-
|
|
698
|
-
4. **Validation**
|
|
699
|
-
- Prototype critical scenarios
|
|
700
|
-
- Performance testing
|
|
701
|
-
- Security audits
|
|
702
|
-
- Usability testing
|
|
703
|
-
|
|
704
|
-
### Architectural Tactics for Quality Attributes
|
|
705
|
-
|
|
706
|
-
**Performance Tactics**
|
|
707
|
-
- Resource management (pooling, caching)
|
|
708
|
-
- Concurrency (parallelism, async processing)
|
|
709
|
-
- Resource arbitration (scheduling, load balancing)
|
|
710
|
-
|
|
711
|
-
**Availability Tactics**
|
|
712
|
-
- Fault detection (ping/echo, heartbeat, monitoring)
|
|
713
|
-
- Fault recovery (retry, failover, rollback)
|
|
714
|
-
- Fault prevention (removal from service, transactions)
|
|
715
|
-
|
|
716
|
-
**Modifiability Tactics**
|
|
717
|
-
- Reduce coupling (encapsulation, intermediaries)
|
|
718
|
-
- Increase cohesion (split modules, abstract common services)
|
|
719
|
-
- Defer binding (configuration files, plugins, discovery)
|
|
720
|
-
|
|
721
|
-
**Security Tactics**
|
|
722
|
-
- Resist attacks (authentication, authorization, encryption)
|
|
723
|
-
- Detect attacks (intrusion detection, audit trails)
|
|
724
|
-
- Recover from attacks (backup, restore, incident response)
|
|
725
|
-
|
|
726
|
-
### Best Practices
|
|
727
|
-
|
|
728
|
-
1. **Define Quality Attributes Early**
|
|
729
|
-
- Include in requirements gathering
|
|
730
|
-
- Prioritize based on business value
|
|
731
|
-
- Make them measurable and testable
|
|
732
|
-
|
|
733
|
-
2. **Use Quality Attribute Scenarios**
|
|
734
|
-
- Concrete, testable scenarios
|
|
735
|
-
- Include source, stimulus, response, measure
|
|
736
|
-
- Prioritize and track throughout development
|
|
737
|
-
|
|
738
|
-
3. **Monitor and Measure**
|
|
739
|
-
- Implement observability (logging, metrics, tracing)
|
|
740
|
-
- Set up alerts for quality attribute violations
|
|
741
|
-
- Regular performance and security testing
|
|
742
|
-
|
|
743
|
-
4. **Document Trade-offs**
|
|
744
|
-
- Explicitly document quality attribute trade-offs
|
|
745
|
-
- Explain architectural decisions
|
|
746
|
-
- Revisit decisions as requirements change
|
|
747
|
-
|
|
748
|
-
5. **Automate Testing**
|
|
749
|
-
- Performance testing in CI/CD
|
|
750
|
-
- Security scanning (SAST, DAST)
|
|
751
|
-
- Accessibility testing
|
|
752
|
-
- Load testing
|
|
753
|
-
|
|
754
|
-
6. **Continuous Improvement**
|
|
755
|
-
- Regular architecture reviews
|
|
756
|
-
- Refactor to improve quality attributes
|
|
757
|
-
- Learn from incidents and outages
|
|
758
|
-
- Update quality attribute scenarios
|
|
759
|
-
|
|
760
|
-
### Common Pitfalls
|
|
761
|
-
|
|
762
|
-
1. **Ignoring Quality Attributes**
|
|
763
|
-
- Focusing only on functional requirements
|
|
764
|
-
- Discovering quality issues late in development
|
|
765
|
-
- Costly rework and refactoring
|
|
766
|
-
|
|
767
|
-
2. **Premature Optimization**
|
|
768
|
-
- Optimizing before measuring
|
|
769
|
-
- Adding complexity without justification
|
|
770
|
-
- Sacrificing maintainability for performance
|
|
771
|
-
|
|
772
|
-
3. **One-Size-Fits-All**
|
|
773
|
-
- Applying same quality attributes to all systems
|
|
774
|
-
- Not considering context and requirements
|
|
775
|
-
- Over-engineering simple systems
|
|
776
|
-
|
|
777
|
-
4. **Lack of Measurement**
|
|
778
|
-
- No metrics or monitoring
|
|
779
|
-
- Subjective quality assessments
|
|
780
|
-
- Unable to validate improvements
|
|
781
|
-
|
|
782
|
-
5. **Ignoring Trade-offs**
|
|
783
|
-
- Trying to maximize all quality attributes
|
|
784
|
-
- Not prioritizing based on business value
|
|
785
|
-
- Creating conflicting requirements
|
|
786
|
-
|
|
787
|
-
---
|
|
788
|
-
|
|
789
|
-
## References
|
|
790
|
-
|
|
791
|
-
- **ISO/IEC 25010**: Systems and software Quality Requirements and Evaluation (SQuaRE)
|
|
792
|
-
- **Software Architecture in Practice**: Len Bass, Paul Clements, Rick Kazman
|
|
793
|
-
- **Designing Data-Intensive Applications**: Martin Kleppmann
|
|
794
|
-
- **Site Reliability Engineering**: Google
|
|
795
|
-
- **OWASP Top 10**: Open Web Application Security Project
|
|
796
|
-
- **WCAG**: Web Content Accessibility Guidelines
|
|
797
|
-
|
|
1
|
+
# Quality Attributes
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document covers non-functional requirements (quality attributes) that define how a system performs its functions. Quality attributes are critical architectural drivers that shape system design and implementation.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Knowledge
|
|
10
|
+
|
|
11
|
+
### Performance
|
|
12
|
+
|
|
13
|
+
**Definition**
|
|
14
|
+
- System's responsiveness and throughput under specific workload
|
|
15
|
+
- Measured in response time, latency, throughput, resource utilization
|
|
16
|
+
- Critical for user experience and system efficiency
|
|
17
|
+
- Often involves trade-offs with other attributes
|
|
18
|
+
|
|
19
|
+
**Key Metrics**
|
|
20
|
+
- **Response Time**: Time to respond to a request
|
|
21
|
+
- **Latency**: Delay before transfer begins
|
|
22
|
+
- **Throughput**: Requests processed per unit time
|
|
23
|
+
- **Resource Utilization**: CPU, memory, network, disk usage
|
|
24
|
+
|
|
25
|
+
**Performance Tactics**
|
|
26
|
+
- Caching (in-memory, distributed, CDN)
|
|
27
|
+
- Load balancing (horizontal scaling)
|
|
28
|
+
- Asynchronous processing (queues, workers)
|
|
29
|
+
- Database optimization (indexing, query optimization)
|
|
30
|
+
- Code optimization (algorithms, data structures)
|
|
31
|
+
- Resource pooling (connection pools, thread pools)
|
|
32
|
+
|
|
33
|
+
**Performance Patterns**
|
|
34
|
+
- Cache-Aside Pattern
|
|
35
|
+
- Read-Through/Write-Through Cache
|
|
36
|
+
- Circuit Breaker (prevent cascading failures)
|
|
37
|
+
- Bulkhead (isolate resources)
|
|
38
|
+
- CQRS (separate read/write paths)
|
|
39
|
+
|
|
40
|
+
### Reliability
|
|
41
|
+
|
|
42
|
+
**Definition**
|
|
43
|
+
- System's ability to function correctly over time
|
|
44
|
+
- Measured in uptime, MTBF (Mean Time Between Failures), MTTR (Mean Time To Recovery)
|
|
45
|
+
- Includes fault tolerance and error handling
|
|
46
|
+
- Critical for mission-critical systems
|
|
47
|
+
|
|
48
|
+
**Key Metrics**
|
|
49
|
+
- **Availability**: Percentage of time system is operational (e.g., 99.9% = "three nines")
|
|
50
|
+
- **MTBF**: Average time between failures
|
|
51
|
+
- **MTTR**: Average time to recover from failure
|
|
52
|
+
- **Error Rate**: Percentage of failed requests
|
|
53
|
+
|
|
54
|
+
**Reliability Tactics**
|
|
55
|
+
- Redundancy (active-active, active-passive)
|
|
56
|
+
- Health checks and monitoring
|
|
57
|
+
- Graceful degradation
|
|
58
|
+
- Retry mechanisms (exponential backoff)
|
|
59
|
+
- Timeouts and circuit breakers
|
|
60
|
+
- Data replication and backup
|
|
61
|
+
|
|
62
|
+
**Reliability Patterns**
|
|
63
|
+
- Retry Pattern
|
|
64
|
+
- Circuit Breaker Pattern
|
|
65
|
+
- Bulkhead Pattern
|
|
66
|
+
- Health Endpoint Monitoring
|
|
67
|
+
- Compensating Transaction
|
|
68
|
+
|
|
69
|
+
### Maintainability
|
|
70
|
+
|
|
71
|
+
**Definition**
|
|
72
|
+
- Ease with which system can be modified, extended, and debugged
|
|
73
|
+
- Measured in time to fix bugs, add features, or refactor
|
|
74
|
+
- Includes code quality, documentation, and testability
|
|
75
|
+
- Critical for long-term system evolution
|
|
76
|
+
|
|
77
|
+
**Key Aspects**
|
|
78
|
+
- **Modularity**: Well-defined, independent modules
|
|
79
|
+
- **Readability**: Clear, self-documenting code
|
|
80
|
+
- **Testability**: Easy to write and run tests
|
|
81
|
+
- **Documentation**: Comprehensive, up-to-date docs
|
|
82
|
+
- **Debuggability**: Easy to diagnose and fix issues
|
|
83
|
+
|
|
84
|
+
**Maintainability Tactics**
|
|
85
|
+
- Clear separation of concerns
|
|
86
|
+
- Consistent coding standards
|
|
87
|
+
- Comprehensive testing (unit, integration, e2e)
|
|
88
|
+
- Automated builds and deployments
|
|
89
|
+
- Version control and code reviews
|
|
90
|
+
- Refactoring and technical debt management
|
|
91
|
+
|
|
92
|
+
**Maintainability Patterns**
|
|
93
|
+
- Dependency Injection
|
|
94
|
+
- Repository Pattern
|
|
95
|
+
- Factory Pattern
|
|
96
|
+
- Strategy Pattern
|
|
97
|
+
- Observer Pattern
|
|
98
|
+
|
|
99
|
+
### Scalability
|
|
100
|
+
|
|
101
|
+
**Definition**
|
|
102
|
+
- System's ability to handle increased load
|
|
103
|
+
- Measured in concurrent users, requests per second, data volume
|
|
104
|
+
- Includes horizontal (add servers) and vertical (add resources) scaling
|
|
105
|
+
- Critical for growing systems
|
|
106
|
+
|
|
107
|
+
**Scaling Dimensions**
|
|
108
|
+
- **Horizontal Scaling**: Add more servers/instances
|
|
109
|
+
- **Vertical Scaling**: Add more resources (CPU, RAM) to existing servers
|
|
110
|
+
- **Data Scaling**: Partition data across multiple databases
|
|
111
|
+
- **Functional Scaling**: Decompose into microservices
|
|
112
|
+
|
|
113
|
+
**Scalability Tactics**
|
|
114
|
+
- Stateless services (enable horizontal scaling)
|
|
115
|
+
- Database sharding and partitioning
|
|
116
|
+
- Caching layers (reduce database load)
|
|
117
|
+
- Asynchronous processing (decouple components)
|
|
118
|
+
- Load balancing (distribute traffic)
|
|
119
|
+
- Auto-scaling (dynamic resource allocation)
|
|
120
|
+
|
|
121
|
+
**Scalability Patterns**
|
|
122
|
+
- Sharding Pattern
|
|
123
|
+
- CQRS (Command Query Responsibility Segregation)
|
|
124
|
+
- Event Sourcing
|
|
125
|
+
- Saga Pattern (distributed transactions)
|
|
126
|
+
- Strangler Fig (incremental migration)
|
|
127
|
+
|
|
128
|
+
### Security
|
|
129
|
+
|
|
130
|
+
**Definition**
|
|
131
|
+
- System's ability to protect data and resist attacks
|
|
132
|
+
- Measured in vulnerabilities, incidents, compliance
|
|
133
|
+
- Includes authentication, authorization, encryption, auditing
|
|
134
|
+
- Critical for all systems handling sensitive data
|
|
135
|
+
|
|
136
|
+
**Security Principles**
|
|
137
|
+
- **Confidentiality**: Protect data from unauthorized access
|
|
138
|
+
- **Integrity**: Ensure data is not tampered with
|
|
139
|
+
- **Availability**: Ensure authorized access when needed
|
|
140
|
+
- **Non-repudiation**: Prove actions occurred
|
|
141
|
+
- **Authentication**: Verify identity
|
|
142
|
+
- **Authorization**: Control access to resources
|
|
143
|
+
|
|
144
|
+
**Security Tactics**
|
|
145
|
+
- Authentication (OAuth, JWT, SAML)
|
|
146
|
+
- Authorization (RBAC, ABAC)
|
|
147
|
+
- Encryption (at rest, in transit)
|
|
148
|
+
- Input validation and sanitization
|
|
149
|
+
- Security headers (CORS, CSP, HSTS)
|
|
150
|
+
- Rate limiting and throttling
|
|
151
|
+
- Audit logging
|
|
152
|
+
|
|
153
|
+
**Security Patterns**
|
|
154
|
+
- Zero Trust Architecture
|
|
155
|
+
- Defense in Depth
|
|
156
|
+
- Least Privilege
|
|
157
|
+
- Secure by Default
|
|
158
|
+
- Fail Securely
|
|
159
|
+
|
|
160
|
+
### Usability
|
|
161
|
+
|
|
162
|
+
**Definition**
|
|
163
|
+
- Ease with which users can accomplish tasks
|
|
164
|
+
- Measured in task completion time, error rate, user satisfaction
|
|
165
|
+
- Includes UI/UX design, accessibility, learnability
|
|
166
|
+
- Critical for user-facing systems
|
|
167
|
+
|
|
168
|
+
**Usability Aspects**
|
|
169
|
+
- **Learnability**: How quickly users learn the system
|
|
170
|
+
- **Efficiency**: How quickly users perform tasks
|
|
171
|
+
- **Memorability**: How easily users remember how to use it
|
|
172
|
+
- **Error Prevention**: How well system prevents errors
|
|
173
|
+
- **Satisfaction**: How pleasant the experience is
|
|
174
|
+
|
|
175
|
+
**Usability Tactics**
|
|
176
|
+
- Consistent UI patterns
|
|
177
|
+
- Clear feedback and error messages
|
|
178
|
+
- Progressive disclosure (show complexity gradually)
|
|
179
|
+
- Accessibility (WCAG compliance)
|
|
180
|
+
- Responsive design (mobile, tablet, desktop)
|
|
181
|
+
- User testing and feedback
|
|
182
|
+
|
|
183
|
+
### Testability
|
|
184
|
+
|
|
185
|
+
**Definition**
|
|
186
|
+
- Ease with which system can be tested
|
|
187
|
+
- Measured in test coverage, test execution time, test maintainability
|
|
188
|
+
- Includes unit, integration, and end-to-end testing
|
|
189
|
+
- Critical for quality assurance
|
|
190
|
+
|
|
191
|
+
**Testability Tactics**
|
|
192
|
+
- Dependency injection (mock dependencies)
|
|
193
|
+
- Interface-based design (test doubles)
|
|
194
|
+
- Separation of concerns (isolated testing)
|
|
195
|
+
- Test automation (CI/CD pipelines)
|
|
196
|
+
- Test data management
|
|
197
|
+
- Observability (logging, metrics, tracing)
|
|
198
|
+
|
|
199
|
+
### Interoperability
|
|
200
|
+
|
|
201
|
+
**Definition**
|
|
202
|
+
- System's ability to work with other systems
|
|
203
|
+
- Measured in integration points, data exchange formats, API compatibility
|
|
204
|
+
- Includes standards compliance and protocol support
|
|
205
|
+
- Critical for enterprise systems
|
|
206
|
+
|
|
207
|
+
**Interoperability Tactics**
|
|
208
|
+
- Standard protocols (HTTP, gRPC, AMQP)
|
|
209
|
+
- Standard data formats (JSON, XML, Protocol Buffers)
|
|
210
|
+
- API versioning and backward compatibility
|
|
211
|
+
- Service contracts and schemas
|
|
212
|
+
- Integration patterns (ESB, API Gateway)
|
|
213
|
+
|
|
214
|
+
### Portability
|
|
215
|
+
|
|
216
|
+
**Definition**
|
|
217
|
+
- Ease with which system can be moved to different environments
|
|
218
|
+
- Measured in deployment time, configuration complexity
|
|
219
|
+
- Includes platform independence and containerization
|
|
220
|
+
- Critical for cloud-native systems
|
|
221
|
+
|
|
222
|
+
**Portability Tactics**
|
|
223
|
+
- Containerization (Docker, Kubernetes)
|
|
224
|
+
- Infrastructure as Code (Terraform, CloudFormation)
|
|
225
|
+
- Environment-specific configuration
|
|
226
|
+
- Platform abstraction layers
|
|
227
|
+
- Cloud-agnostic design
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Skills
|
|
232
|
+
|
|
233
|
+
### Specifying Quality Attributes
|
|
234
|
+
|
|
235
|
+
**Quality Attribute Scenarios**
|
|
236
|
+
|
|
237
|
+
A quality attribute scenario consists of:
|
|
238
|
+
1. **Source**: Entity generating the stimulus
|
|
239
|
+
2. **Stimulus**: Condition affecting the system
|
|
240
|
+
3. **Environment**: System state when stimulus occurs
|
|
241
|
+
4. **Artifact**: Part of system affected
|
|
242
|
+
5. **Response**: Activity resulting from stimulus
|
|
243
|
+
6. **Response Measure**: Measurable outcome
|
|
244
|
+
|
|
245
|
+
**Example: Performance Scenario**
|
|
246
|
+
- **Source**: User
|
|
247
|
+
- **Stimulus**: Initiates transaction
|
|
248
|
+
- **Environment**: Normal operation
|
|
249
|
+
- **Artifact**: System
|
|
250
|
+
- **Response**: Process transaction
|
|
251
|
+
- **Response Measure**: Within 2 seconds for 95% of requests
|
|
252
|
+
|
|
253
|
+
**Example: Availability Scenario**
|
|
254
|
+
- **Source**: Internal fault
|
|
255
|
+
- **Stimulus**: Server crashes
|
|
256
|
+
- **Environment**: Normal operation
|
|
257
|
+
- **Artifact**: System
|
|
258
|
+
- **Response**: Failover to backup server
|
|
259
|
+
- **Response Measure**: Within 30 seconds, no data loss
|
|
260
|
+
|
|
261
|
+
### Measuring Quality Attributes
|
|
262
|
+
|
|
263
|
+
**Performance Metrics**
|
|
264
|
+
- Response time percentiles (p50, p95, p99)
|
|
265
|
+
- Throughput (requests/second)
|
|
266
|
+
- Resource utilization (CPU, memory, network)
|
|
267
|
+
- Apdex score (Application Performance Index)
|
|
268
|
+
|
|
269
|
+
**Reliability Metrics**
|
|
270
|
+
- Uptime percentage (99.9%, 99.99%, 99.999%)
|
|
271
|
+
- MTBF (Mean Time Between Failures)
|
|
272
|
+
- MTTR (Mean Time To Recovery)
|
|
273
|
+
- Error rate (errors per 1000 requests)
|
|
274
|
+
|
|
275
|
+
**Maintainability Metrics**
|
|
276
|
+
- Code coverage (unit, integration tests)
|
|
277
|
+
- Cyclomatic complexity
|
|
278
|
+
- Technical debt ratio
|
|
279
|
+
- Time to fix bugs
|
|
280
|
+
|
|
281
|
+
**Security Metrics**
|
|
282
|
+
- Vulnerability count (critical, high, medium, low)
|
|
283
|
+
- Time to patch vulnerabilities
|
|
284
|
+
- Failed authentication attempts
|
|
285
|
+
- Security incidents
|
|
286
|
+
|
|
287
|
+
### Trade-offs Between Quality Attributes
|
|
288
|
+
|
|
289
|
+
**Common Trade-offs**
|
|
290
|
+
|
|
291
|
+
**Performance vs. Security**
|
|
292
|
+
- Encryption adds latency
|
|
293
|
+
- Authentication/authorization adds overhead
|
|
294
|
+
- Balance: Use efficient algorithms, cache auth tokens
|
|
295
|
+
|
|
296
|
+
**Performance vs. Maintainability**
|
|
297
|
+
- Optimized code may be harder to read
|
|
298
|
+
- Caching adds complexity
|
|
299
|
+
- Balance: Optimize only bottlenecks, document optimizations
|
|
300
|
+
|
|
301
|
+
**Scalability vs. Consistency**
|
|
302
|
+
- Distributed systems face CAP theorem constraints
|
|
303
|
+
- Eventual consistency improves scalability
|
|
304
|
+
- Balance: Choose consistency model based on requirements
|
|
305
|
+
|
|
306
|
+
**Flexibility vs. Performance**
|
|
307
|
+
- Abstraction layers add overhead
|
|
308
|
+
- Dynamic dispatch slower than static
|
|
309
|
+
- Balance: Abstract only where needed, measure impact
|
|
310
|
+
|
|
311
|
+
**Security vs. Usability**
|
|
312
|
+
- Strong authentication may frustrate users
|
|
313
|
+
- Strict validation may reject valid input
|
|
314
|
+
- Balance: Risk-based authentication, clear error messages
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Examples
|
|
319
|
+
|
|
320
|
+
### Performance Optimization
|
|
321
|
+
|
|
322
|
+
**Caching Strategy**
|
|
323
|
+
```typescript
|
|
324
|
+
interface CacheService {
|
|
325
|
+
get<T>(key: string): Promise<T | null>;
|
|
326
|
+
set<T>(key: string, value: T, ttl?: number): Promise<void>;
|
|
327
|
+
delete(key: string): Promise<void>;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
class UserService {
|
|
331
|
+
constructor(
|
|
332
|
+
private userRepository: UserRepository,
|
|
333
|
+
private cache: CacheService
|
|
334
|
+
) {}
|
|
335
|
+
|
|
336
|
+
async getUser(id: string): Promise<User> {
|
|
337
|
+
// Try cache first
|
|
338
|
+
const cached = await this.cache.get<User>(`user:${id}`);
|
|
339
|
+
if (cached) {
|
|
340
|
+
return cached;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Cache miss - fetch from database
|
|
344
|
+
const user = await this.userRepository.findById(id);
|
|
345
|
+
if (user) {
|
|
346
|
+
// Cache for 5 minutes
|
|
347
|
+
await this.cache.set(`user:${id}`, user, 300);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return user;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async updateUser(id: string, data: Partial<User>): Promise<User> {
|
|
354
|
+
const user = await this.userRepository.update(id, data);
|
|
355
|
+
|
|
356
|
+
// Invalidate cache
|
|
357
|
+
await this.cache.delete(`user:${id}`);
|
|
358
|
+
|
|
359
|
+
return user;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Database Query Optimization**
|
|
365
|
+
```typescript
|
|
366
|
+
// Bad: N+1 query problem
|
|
367
|
+
async function getOrdersWithItems(userId: string): Promise<Order[]> {
|
|
368
|
+
const orders = await db.query('SELECT * FROM orders WHERE user_id = ?', [userId]);
|
|
369
|
+
|
|
370
|
+
for (const order of orders) {
|
|
371
|
+
// N additional queries!
|
|
372
|
+
order.items = await db.query('SELECT * FROM order_items WHERE order_id = ?', [order.id]);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return orders;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Good: Single query with JOIN
|
|
379
|
+
async function getOrdersWithItems(userId: string): Promise<Order[]> {
|
|
380
|
+
const rows = await db.query(`
|
|
381
|
+
SELECT
|
|
382
|
+
o.*,
|
|
383
|
+
oi.id as item_id,
|
|
384
|
+
oi.product_id,
|
|
385
|
+
oi.quantity,
|
|
386
|
+
oi.price
|
|
387
|
+
FROM orders o
|
|
388
|
+
LEFT JOIN order_items oi ON o.id = oi.order_id
|
|
389
|
+
WHERE o.user_id = ?
|
|
390
|
+
`, [userId]);
|
|
391
|
+
|
|
392
|
+
// Group items by order
|
|
393
|
+
const ordersMap = new Map<string, Order>();
|
|
394
|
+
for (const row of rows) {
|
|
395
|
+
if (!ordersMap.has(row.id)) {
|
|
396
|
+
ordersMap.set(row.id, {
|
|
397
|
+
id: row.id,
|
|
398
|
+
userId: row.user_id,
|
|
399
|
+
items: []
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (row.item_id) {
|
|
404
|
+
ordersMap.get(row.id)!.items.push({
|
|
405
|
+
id: row.item_id,
|
|
406
|
+
productId: row.product_id,
|
|
407
|
+
quantity: row.quantity,
|
|
408
|
+
price: row.price
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return Array.from(ordersMap.values());
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Reliability Patterns
|
|
418
|
+
|
|
419
|
+
**Circuit Breaker**
|
|
420
|
+
```typescript
|
|
421
|
+
enum CircuitState {
|
|
422
|
+
CLOSED, // Normal operation
|
|
423
|
+
OPEN, // Failing, reject requests
|
|
424
|
+
HALF_OPEN // Testing if service recovered
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
class CircuitBreaker {
|
|
428
|
+
private state: CircuitState = CircuitState.CLOSED;
|
|
429
|
+
private failureCount = 0;
|
|
430
|
+
private lastFailureTime?: Date;
|
|
431
|
+
|
|
432
|
+
constructor(
|
|
433
|
+
private failureThreshold: number = 5,
|
|
434
|
+
private timeout: number = 60000, // 1 minute
|
|
435
|
+
private successThreshold: number = 2
|
|
436
|
+
) {}
|
|
437
|
+
|
|
438
|
+
async execute<T>(operation: () => Promise<T>): Promise<T> {
|
|
439
|
+
if (this.state === CircuitState.OPEN) {
|
|
440
|
+
if (this.shouldAttemptReset()) {
|
|
441
|
+
this.state = CircuitState.HALF_OPEN;
|
|
442
|
+
} else {
|
|
443
|
+
throw new Error('Circuit breaker is OPEN');
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
try {
|
|
448
|
+
const result = await operation();
|
|
449
|
+
this.onSuccess();
|
|
450
|
+
return result;
|
|
451
|
+
} catch (error) {
|
|
452
|
+
this.onFailure();
|
|
453
|
+
throw error;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private onSuccess(): void {
|
|
458
|
+
this.failureCount = 0;
|
|
459
|
+
this.state = CircuitState.CLOSED;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
private onFailure(): void {
|
|
463
|
+
this.failureCount++;
|
|
464
|
+
this.lastFailureTime = new Date();
|
|
465
|
+
|
|
466
|
+
if (this.failureCount >= this.failureThreshold) {
|
|
467
|
+
this.state = CircuitState.OPEN;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private shouldAttemptReset(): boolean {
|
|
472
|
+
return this.lastFailureTime &&
|
|
473
|
+
Date.now() - this.lastFailureTime.getTime() >= this.timeout;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Usage
|
|
478
|
+
const breaker = new CircuitBreaker();
|
|
479
|
+
const paymentService = {
|
|
480
|
+
async processPayment(amount: number): Promise<PaymentResult> {
|
|
481
|
+
return breaker.execute(async () => {
|
|
482
|
+
// Call external payment API
|
|
483
|
+
const response = await fetch('https://api.payment.com/charge', {
|
|
484
|
+
method: 'POST',
|
|
485
|
+
body: JSON.stringify({ amount })
|
|
486
|
+
});
|
|
487
|
+
return response.json();
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**Retry with Exponential Backoff**
|
|
494
|
+
```typescript
|
|
495
|
+
async function retryWithBackoff<T>(
|
|
496
|
+
operation: () => Promise<T>,
|
|
497
|
+
maxRetries: number = 3,
|
|
498
|
+
baseDelay: number = 1000
|
|
499
|
+
): Promise<T> {
|
|
500
|
+
let lastError: Error;
|
|
501
|
+
|
|
502
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
503
|
+
try {
|
|
504
|
+
return await operation();
|
|
505
|
+
} catch (error) {
|
|
506
|
+
lastError = error as Error;
|
|
507
|
+
|
|
508
|
+
if (attempt < maxRetries) {
|
|
509
|
+
// Exponential backoff: 1s, 2s, 4s, 8s...
|
|
510
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
511
|
+
// Add jitter to prevent thundering herd
|
|
512
|
+
const jitter = Math.random() * 1000;
|
|
513
|
+
await new Promise(resolve => setTimeout(resolve, delay + jitter));
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
throw lastError!;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Usage
|
|
522
|
+
const data = await retryWithBackoff(
|
|
523
|
+
() => fetch('https://api.example.com/data').then(r => r.json()),
|
|
524
|
+
3,
|
|
525
|
+
1000
|
|
526
|
+
);
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### Security Implementation
|
|
530
|
+
|
|
531
|
+
**Authentication and Authorization**
|
|
532
|
+
```typescript
|
|
533
|
+
interface User {
|
|
534
|
+
id: string;
|
|
535
|
+
email: string;
|
|
536
|
+
roles: string[];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
interface AuthService {
|
|
540
|
+
authenticate(email: string, password: string): Promise<string>; // Returns JWT
|
|
541
|
+
verifyToken(token: string): Promise<User>;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Role-Based Access Control (RBAC)
|
|
545
|
+
function requireRole(...roles: string[]) {
|
|
546
|
+
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
547
|
+
const originalMethod = descriptor.value;
|
|
548
|
+
|
|
549
|
+
descriptor.value = async function (...args: any[]) {
|
|
550
|
+
const user = (this as any).currentUser as User;
|
|
551
|
+
|
|
552
|
+
if (!user) {
|
|
553
|
+
throw new Error('Unauthorized');
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const hasRole = roles.some(role => user.roles.includes(role));
|
|
557
|
+
if (!hasRole) {
|
|
558
|
+
throw new Error('Forbidden');
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return originalMethod.apply(this, args);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
return descriptor;
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
class OrderController {
|
|
569
|
+
constructor(private currentUser: User) {}
|
|
570
|
+
|
|
571
|
+
@requireRole('admin', 'manager')
|
|
572
|
+
async deleteOrder(orderId: string): Promise<void> {
|
|
573
|
+
// Only admins and managers can delete orders
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
@requireRole('user')
|
|
577
|
+
async viewOrder(orderId: string): Promise<Order> {
|
|
578
|
+
// Any authenticated user can view orders
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
**Input Validation and Sanitization**
|
|
584
|
+
```typescript
|
|
585
|
+
import { z } from 'zod';
|
|
586
|
+
|
|
587
|
+
// Define schema
|
|
588
|
+
const CreateUserSchema = z.object({
|
|
589
|
+
email: z.string().email(),
|
|
590
|
+
password: z.string().min(8).max(100),
|
|
591
|
+
name: z.string().min(1).max(100),
|
|
592
|
+
age: z.number().int().min(18).max(120).optional()
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
type CreateUserInput = z.infer<typeof CreateUserSchema>;
|
|
596
|
+
|
|
597
|
+
class UserController {
|
|
598
|
+
async createUser(input: unknown): Promise<User> {
|
|
599
|
+
// Validate and sanitize input
|
|
600
|
+
const validatedInput = CreateUserSchema.parse(input);
|
|
601
|
+
|
|
602
|
+
// Hash password
|
|
603
|
+
const hashedPassword = await bcrypt.hash(validatedInput.password, 10);
|
|
604
|
+
|
|
605
|
+
// Create user
|
|
606
|
+
return this.userRepository.create({
|
|
607
|
+
...validatedInput,
|
|
608
|
+
password: hashedPassword
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
### Maintainability Practices
|
|
615
|
+
|
|
616
|
+
**Dependency Injection for Testability**
|
|
617
|
+
```typescript
|
|
618
|
+
// Bad: Hard to test
|
|
619
|
+
class OrderService {
|
|
620
|
+
async createOrder(data: OrderData): Promise<Order> {
|
|
621
|
+
const db = new Database(); // Hard-coded dependency
|
|
622
|
+
const emailService = new EmailService(); // Hard-coded dependency
|
|
623
|
+
|
|
624
|
+
const order = await db.insert('orders', data);
|
|
625
|
+
await emailService.sendOrderConfirmation(order);
|
|
626
|
+
|
|
627
|
+
return order;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Good: Easy to test
|
|
632
|
+
interface OrderRepository {
|
|
633
|
+
create(data: OrderData): Promise<Order>;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
interface EmailService {
|
|
637
|
+
sendOrderConfirmation(order: Order): Promise<void>;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
class OrderService {
|
|
641
|
+
constructor(
|
|
642
|
+
private orderRepository: OrderRepository,
|
|
643
|
+
private emailService: EmailService
|
|
644
|
+
) {}
|
|
645
|
+
|
|
646
|
+
async createOrder(data: OrderData): Promise<Order> {
|
|
647
|
+
const order = await this.orderRepository.create(data);
|
|
648
|
+
await this.emailService.sendOrderConfirmation(order);
|
|
649
|
+
return order;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Test with mocks
|
|
654
|
+
describe('OrderService', () => {
|
|
655
|
+
it('should send confirmation email after creating order', async () => {
|
|
656
|
+
const mockRepository: OrderRepository = {
|
|
657
|
+
create: jest.fn().mockResolvedValue({ id: '123', ...orderData })
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
const mockEmailService: EmailService = {
|
|
661
|
+
sendOrderConfirmation: jest.fn().mockResolvedValue(undefined)
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
const service = new OrderService(mockRepository, mockEmailService);
|
|
665
|
+
await service.createOrder(orderData);
|
|
666
|
+
|
|
667
|
+
expect(mockEmailService.sendOrderConfirmation).toHaveBeenCalledWith(
|
|
668
|
+
expect.objectContaining({ id: '123' })
|
|
669
|
+
);
|
|
670
|
+
});
|
|
671
|
+
});
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## Understanding
|
|
677
|
+
|
|
678
|
+
### Quality Attribute Workshops
|
|
679
|
+
|
|
680
|
+
**Steps to Identify Quality Attributes**
|
|
681
|
+
|
|
682
|
+
1. **Stakeholder Identification**
|
|
683
|
+
- Business stakeholders
|
|
684
|
+
- End users
|
|
685
|
+
- Developers and operators
|
|
686
|
+
- Security and compliance teams
|
|
687
|
+
|
|
688
|
+
2. **Scenario Elicitation**
|
|
689
|
+
- Brainstorm quality attribute scenarios
|
|
690
|
+
- Prioritize scenarios by importance
|
|
691
|
+
- Define measurable response measures
|
|
692
|
+
|
|
693
|
+
3. **Architecture Analysis**
|
|
694
|
+
- Identify architectural tactics for each scenario
|
|
695
|
+
- Analyze trade-offs
|
|
696
|
+
- Document decisions and rationale
|
|
697
|
+
|
|
698
|
+
4. **Validation**
|
|
699
|
+
- Prototype critical scenarios
|
|
700
|
+
- Performance testing
|
|
701
|
+
- Security audits
|
|
702
|
+
- Usability testing
|
|
703
|
+
|
|
704
|
+
### Architectural Tactics for Quality Attributes
|
|
705
|
+
|
|
706
|
+
**Performance Tactics**
|
|
707
|
+
- Resource management (pooling, caching)
|
|
708
|
+
- Concurrency (parallelism, async processing)
|
|
709
|
+
- Resource arbitration (scheduling, load balancing)
|
|
710
|
+
|
|
711
|
+
**Availability Tactics**
|
|
712
|
+
- Fault detection (ping/echo, heartbeat, monitoring)
|
|
713
|
+
- Fault recovery (retry, failover, rollback)
|
|
714
|
+
- Fault prevention (removal from service, transactions)
|
|
715
|
+
|
|
716
|
+
**Modifiability Tactics**
|
|
717
|
+
- Reduce coupling (encapsulation, intermediaries)
|
|
718
|
+
- Increase cohesion (split modules, abstract common services)
|
|
719
|
+
- Defer binding (configuration files, plugins, discovery)
|
|
720
|
+
|
|
721
|
+
**Security Tactics**
|
|
722
|
+
- Resist attacks (authentication, authorization, encryption)
|
|
723
|
+
- Detect attacks (intrusion detection, audit trails)
|
|
724
|
+
- Recover from attacks (backup, restore, incident response)
|
|
725
|
+
|
|
726
|
+
### Best Practices
|
|
727
|
+
|
|
728
|
+
1. **Define Quality Attributes Early**
|
|
729
|
+
- Include in requirements gathering
|
|
730
|
+
- Prioritize based on business value
|
|
731
|
+
- Make them measurable and testable
|
|
732
|
+
|
|
733
|
+
2. **Use Quality Attribute Scenarios**
|
|
734
|
+
- Concrete, testable scenarios
|
|
735
|
+
- Include source, stimulus, response, measure
|
|
736
|
+
- Prioritize and track throughout development
|
|
737
|
+
|
|
738
|
+
3. **Monitor and Measure**
|
|
739
|
+
- Implement observability (logging, metrics, tracing)
|
|
740
|
+
- Set up alerts for quality attribute violations
|
|
741
|
+
- Regular performance and security testing
|
|
742
|
+
|
|
743
|
+
4. **Document Trade-offs**
|
|
744
|
+
- Explicitly document quality attribute trade-offs
|
|
745
|
+
- Explain architectural decisions
|
|
746
|
+
- Revisit decisions as requirements change
|
|
747
|
+
|
|
748
|
+
5. **Automate Testing**
|
|
749
|
+
- Performance testing in CI/CD
|
|
750
|
+
- Security scanning (SAST, DAST)
|
|
751
|
+
- Accessibility testing
|
|
752
|
+
- Load testing
|
|
753
|
+
|
|
754
|
+
6. **Continuous Improvement**
|
|
755
|
+
- Regular architecture reviews
|
|
756
|
+
- Refactor to improve quality attributes
|
|
757
|
+
- Learn from incidents and outages
|
|
758
|
+
- Update quality attribute scenarios
|
|
759
|
+
|
|
760
|
+
### Common Pitfalls
|
|
761
|
+
|
|
762
|
+
1. **Ignoring Quality Attributes**
|
|
763
|
+
- Focusing only on functional requirements
|
|
764
|
+
- Discovering quality issues late in development
|
|
765
|
+
- Costly rework and refactoring
|
|
766
|
+
|
|
767
|
+
2. **Premature Optimization**
|
|
768
|
+
- Optimizing before measuring
|
|
769
|
+
- Adding complexity without justification
|
|
770
|
+
- Sacrificing maintainability for performance
|
|
771
|
+
|
|
772
|
+
3. **One-Size-Fits-All**
|
|
773
|
+
- Applying same quality attributes to all systems
|
|
774
|
+
- Not considering context and requirements
|
|
775
|
+
- Over-engineering simple systems
|
|
776
|
+
|
|
777
|
+
4. **Lack of Measurement**
|
|
778
|
+
- No metrics or monitoring
|
|
779
|
+
- Subjective quality assessments
|
|
780
|
+
- Unable to validate improvements
|
|
781
|
+
|
|
782
|
+
5. **Ignoring Trade-offs**
|
|
783
|
+
- Trying to maximize all quality attributes
|
|
784
|
+
- Not prioritizing based on business value
|
|
785
|
+
- Creating conflicting requirements
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## References
|
|
790
|
+
|
|
791
|
+
- **ISO/IEC 25010**: Systems and software Quality Requirements and Evaluation (SQuaRE)
|
|
792
|
+
- **Software Architecture in Practice**: Len Bass, Paul Clements, Rick Kazman
|
|
793
|
+
- **Designing Data-Intensive Applications**: Martin Kleppmann
|
|
794
|
+
- **Site Reliability Engineering**: Google
|
|
795
|
+
- **OWASP Top 10**: Open Web Application Security Project
|
|
796
|
+
- **WCAG**: Web Content Accessibility Guidelines
|
|
797
|
+
|