Table of Contents

Open all
Close all
1 Introduction
15
1.1 Programming Paradigms
17
1.1.1 Structured Programming
18
1.1.2 Object-Oriented Programming
20
1.1.3 Functional Programming
22
1.1.4 Reactive Programming
25
1.2 What Are Design Patterns and How Did They Come About?
27
1.3 What Are Software Architecture and Software Design?
31
1.3.1 Tasks of a Software Architecture
33
1.3.2 Architectural Styles and Architectural Patterns
35
1.4 The Evolution of Software Development and Architecture
38
1.4.1 Class-Responsibility-Collaboration Cards
38
1.4.2 The “Gang of Four” Patterns and Their Structure
39
1.4.3 Clean Code
43
1.4.4 Component-Based Development
45
1.4.5 Core J2EE Patterns
50
1.4.6 Enterprise Integration Patterns
54
1.4.7 Well-Architected Cloud
60
2 Principles of Good Software Design
63
2.1 Basic Concepts of Object-Oriented Programming
64
2.1.1 Objects and Classes
65
2.1.2 Encapsulation
66
2.1.3 Abstraction
68
2.1.4 Inheritance
72
2.1.5 Polymorphism
73
2.2 Clean Code Principles
75
2.2.1 Identifier Names and Conventions in the Code
77
2.2.2 Defining Functions and Methods
89
2.2.3 Don’t Repeat Yourself
104
2.2.4 Establishing Clear Boundaries Between Components
105
2.2.5 The Broken Windows Theory and the Boy Scout Rule in Software
107
2.3 SOLID Principles
108
2.3.1 The Single Responsibility Principle
109
2.3.2 The Open-Closed Principle
113
2.3.3 The Liskov Substitution Principle
119
2.3.4 The Interface Segregation Principle
123
2.3.5 The Dependency Inversion Principle and the Inversion of Control
128
2.4 Information Hiding
131
2.5 Inversion of Control and Dependency Injection
132
2.6 Separation of Concerns and Aspect Orientation
134
2.7 Quality Assurance with Unit Tests
137
3 Source Code and Documenting the Software Development
143
3.1 Comments in the Source Code
143
3.1.1 Documenting Interfaces Using Comments
145
3.1.2 Creating Expressive Code
149
3.1.3 Necessary and Meaningful Comments
150
3.1.4 Comments Not Needed
154
3.2 Documenting the Software Architecture
157
3.2.1 Documenting Quality Features
158
3.2.2 Rules for Good Software Architecture Documentation
159
3.2.3 arc42 for the Complete Documentation
162
3.3 Representing Software in Unified Modeling Language
169
3.3.1 Use Case Diagram
170
3.3.2 Class Diagram
171
3.3.3 Sequence Diagram
174
3.3.4 State Diagram
175
3.3.5 Component Diagram
177
3.4 C4 Model for Representing Software Architecture
180
3.4.1 System Context (Level 1 or C1)
184
3.4.2 Container (Level 2 or C2)
186
3.4.3 Component (Level 3 or C3)
187
3.4.4 Code (Level 4 or C4)
188
3.5 Doc-as-Code
188
3.5.1 AsciiDoc
189
3.5.2 PlantUML
191
3.5.3 Structurizr
194
4 Software Patterns
197
4.1 Factory Method
198
4.1.1 Problem and Motivation
198
4.1.2 Solution
200
4.1.3 Sample Solution
201
4.1.4 When To Use the Pattern
203
4.1.5 Consequences
204
4.1.6 Real-World Example in Open-Source Software
205
4.2 Builder
206
4.2.1 Problem and Motivation
206
4.2.2 Solution
208
4.2.3 Sample Solution
209
4.2.4 When To Use the Pattern
213
4.2.5 Consequence
214
4.2.6 Real-World Example in Open-Source Software
214
4.3 Strategy
216
4.3.1 Problem and Motivation
216
4.3.2 Solution
216
4.3.3 Sample Solution
217
4.3.4 When To Use the Pattern
220
4.3.5 Consequences
221
4.3.6 Real-World Example
222
4.4 Chain of Responsibility
223
4.4.1 Problem and Motivation
224
4.4.2 Solution
224
4.4.3 Sample Solution
226
4.4.4 When To Use the Pattern
228
4.4.5 Consequences
228
4.4.6 Real-World Example
229
4.5 Command
232
4.5.1 Problem and Motivation
232
4.5.2 Solution
233
4.5.3 Sample Solution
235
4.5.4 When To Use the Pattern
238
4.5.5 Consequences
239
4.5.6 Real-World Example
239
4.6 Observer
243
4.6.1 Problem and Motivation
243
4.6.2 Solution
244
4.6.3 Sample Solution
245
4.6.4 When To Use the Pattern
248
4.6.5 Consequences
249
4.6.6 Real-World Example
249
4.7 Singleton
251
4.7.1 Problem and Motivation
251
4.7.2 Solution
252
4.7.3 Sample Solution
253
4.7.4 When To Use the Pattern
255
4.7.5 Consequences
256
4.7.6 Real-World Example
258
4.8 Adapter/Wrapper
259
4.8.1 Problem and Motivation
259
4.8.2 Solution
260
4.8.3 Sample Solution
261
4.8.4 When To Use the Pattern
264
4.8.5 Consequences
265
4.8.6 Real-World Example
265
4.9 Iterator
268
4.9.1 Problem and Motivation
269
4.9.2 Solution
269
4.9.3 Sample Solution
271
4.9.4 When To Use the Pattern
273
4.9.5 Consequences
274
4.9.6 Real-World Example
274
4.10 Composite
276
4.10.1 Problem and Motivation
276
4.10.2 Solution
277
4.10.3 Sample Solution
278
4.10.4 When To Use the Pattern
281
4.10.5 Consequences
281
4.10.6 Real-World Example
281
4.11 The Concept of Anti-Patterns
283
4.11.1 Big Ball of Mud
283
4.11.2 God Object
284
4.11.3 Spaghetti Code
285
4.11.4 Reinventing the Wheel
286
4.11.5 Cargo Cult Programming
287
5 Software Architecture, Styles, and Patterns
289
5.1 The Role of the Software Architect
290
5.2 Software Architecture Styles
292
5.2.1 Client-Server Architecture
293
5.2.2 Layered Architecture and Service Layers
294
5.2.3 Event-Driven Architecture
299
5.2.4 Microkernel Architecture or Plugin Architecture
304
5.2.5 Microservices
307
5.3 Styles for Application Organization and Code Structure
310
5.3.1 Domain-Driven Design
311
5.3.2 Strategic and Tactical Designs
315
5.3.3 Hexagonal Architecture/Ports and Adapters
315
5.3.4 Clean Architecture
320
5.4 Patterns for the Support of Architectural Styles
324
5.4.1 Model View Controller Pattern
324
5.4.2 Model View ViewModel Pattern
329
5.4.3 Data Transfer Objects
335
5.4.4 Remote Facade Pattern
339
6 Communication Between Services
347
6.1 Styles of Application Communication
349
6.1.1 Synchronous Communication
350
6.1.2 Asynchronous Communication and Messaging
351
6.1.3 Streaming
353
6.2 Resilience Patterns
356
6.2.1 Error Propagation
357
6.2.2 Subdivision of the Resilience Patterns
358
6.2.3 Timeout Pattern
361
6.2.4 Retry Pattern
366
6.2.5 Circuit Breaker Pattern
372
6.2.6 Bulkhead Pattern
378
6.2.7 Steady State Pattern
383
6.3 Messaging Patterns
388
6.3.1 Messaging Concepts
388
6.3.2 Messaging Channel Patterns
389
6.3.3 Message Construction Patterns
395
6.3.4 Messaging Endpoint Pattern
402
6.4 Patterns for Interface Versioning
411
6.4.1 Endpoint for Version Pattern
415
6.4.2 Referencing Message Pattern
415
6.4.3 Self-Contained Message Pattern
417
6.4.4 Message with Referencing Metadata
418
6.4.5 Message with Self-Describing Metadata
420
7 Patterns and Concepts for Distributed Applications
421
7.1 Consistency
422
7.2 The CAP Theorem
423
7.3 The PACELC Theorem
424
7.4 Eventual Consistency
425
7.5 Stateless Architecture Pattern
428
7.5.1 Problem and Motivation
428
7.5.2 Solution
429
7.5.3 Sample Solution
431
7.5.4 When To Use the Pattern
433
7.5.5 Consequences
433
7.6 Database per Service Pattern
434
7.6.1 Problem and Motivation
434
7.6.2 Solution
434
7.6.3 Sample Solution
435
7.6.4 When To Use the Pattern
436
7.6.5 Consequences
436
7.7 Optimistic Locking Pattern
437
7.7.1 Problem and Motivation
437
7.7.2 Solution
438
7.7.3 Sample Solution
441
7.7.4 When To Use the Pattern
443
7.7.5 Consequences
443
7.7.6 Pessimistic Locking
444
7.8 Saga Pattern: The Distributed Transactions Pattern
446
7.8.1 Problem and Motivation
446
7.8.2 Solution
447
7.8.3 Sample Solution
447
7.8.4 When To Use the Pattern
449
7.8.5 Consequences
449
7.9 Transactional Outbox Pattern
450
7.9.1 Problem and Motivation
450
7.9.2 Solution
451
7.9.3 Sample Solution
452
7.9.4 When To Use the Pattern
454
7.9.5 Consequences
455
7.10 Event Sourcing Pattern
455
7.10.1 Problem and Motivation
455
7.10.2 Solution
456
7.10.3 Sample Solution
457
7.10.4 When To Use the Pattern
460
7.10.5 Consequences
461
7.11 Command Query Responsibility Segregation Pattern
461
7.11.1 Problem and Motivation
461
7.11.2 Solution
463
7.11.3 Sample Solution
464
7.11.4 When To Use the Pattern
467
7.11.5 Consequences
467
7.12 Distributed Tracing Pattern
467
7.12.1 Problem and Motivation
468
7.12.2 Solution
468
7.12.3 Sample Solution
470
7.12.4 When To Use the Pattern
476
7.12.5 Consequences
476
The Author
479
Index
481