Cover....1
Copyright Page....3
Contributors....5
Table of Contents....8
Preface....26
Part 1: Concepts and Components of Software Architecture....32
Chapter 1: Importance of Software Architecture and Principles of Great Design....34
Getting the most out of this book – get to know your free benefits....34
Technical requirements....36
Understanding software architecture....36
Different ways to look at architecture....37
Communication and culture....38
The importance of proper architecture....38
Technical debt....38
Accidental architecture....39
The fundamentals of good architecture....39
Architecture context....39
Stakeholders....39
Business and technical environments....40
Developing architecture using Agile principles....40
Domain-driven design....41
The philosophy of C....43
Following the SOLID and DRY principles....46
SOLID principles....46
Single responsibility principle....47
Open–closed principle....48
Liskov substitution principle....49
Interface segregation principle....51
Dependency inversion principle....53
The DRY rule....57
Coupling and cohesion....58
Coupling....58
Cohesion....60
Summary....62
Questions....62
Further reading....62
Chapter 2: Architectural Styles....64
Technical requirements....64
Deciding between stateful and stateless approaches....64
Stateless and stateful services....68
Understanding monoliths....70
Understanding services and microservices....71
Service-oriented architecture....71
Microservices....71
Characteristics of microservices....72
Benefits and disadvantages of microservices....74
Scaling microservices....75
Transitioning to microservices....76
Exploring event-based architecture....76
Exploring the event sourcing pattern....78
Understanding layered architecture....79
Backends for frontends....81
Learning module-based architecture....82
Introducing hexagonal architecture....83
Summary....85
Questions....85
Further reading....85
Chapter 3: Functional and Non-Functional Requirements....88
Technical requirements....88
Understanding the types of requirements....89
Functional requirements....89
Non-functional requirements....90
Quality attributes....90
Constraints....90
Recognizing architecturally significant requirements (ASRs)....91
Indicators of architectural significance....92
Hindrances in recognizing ASRs and how to deal with them....93
Gathering requirements....94
Knowing the context....94
Knowing existing documentation....94
Knowing your stakeholders....95
Gathering requirements from stakeholders....95
Documenting requirements....96
Documenting the context....96
Documenting the scope....97
Documenting functional requirements....97
Documenting NFRs....98
Managing the version history of your documentation....98
Documenting requirements in Agile projects....99
Other sections....100
Documenting architecture....100
Understanding the 41 model....101
Understanding the C4 model....106
Documenting architecture in Agile projects....112
Choosing the right views to document....112
Functional view....113
Information view....113
Concurrency view....114
Development view....114
Deployment and operational views....115
Generating documentation....116
Generating requirements documentation....116
Generating diagrams from code....116
Generating (API) documentation from code....117
Summary....123
Questions....124
Further reading....124
Part 2: The Design and Development of C Software....126
Chapter 4: Architectural and System Design Patterns....128
Technical requirements....129
Understanding the peculiarities of distributed systems....129
Different service models and when to use them....129
On-premises model....130
Infrastructure as a Service model....130
Platform as a Service model....131
Software as a Service model....131
Function as a Service model and serverless architecture....132
Avoiding the fallacies of distributed computing....133
The network is reliable....133
Latency is zero....133
Bandwidth is infinite....134
The network is secure....135
Topology doesnt change....135
There is one administrator....136
Transport cost is zero....136
The network is homogeneous....137
CAP theorem and eventual consistency....137
Saga and compensating transaction patterns....139
Making your system fault-tolerant and available....141
Calculating your systems availability....141
Building fault-tolerant systems....142
Redundancy patterns....142
Replication patterns....144
Queue-based load leveling pattern....145
Back pressure pattern....146
Detecting faults....146
Sidecar design pattern....146
Heartbeat mechanism pattern....147
Leaky bucket counter pattern....147
Minimizing the impact of faults....147
Retrying the call (retry pattern)....148
Avoiding cascading failures....148
Geodes pattern....149
Integrating your system....149
Pipes and filters pattern....149
Competing consumers pattern....150
Transitioning from legacy systems....151
Anti-corruption layer pattern....151
Strangler pattern....152
Achieving performance at scale....152
CQRS and event-sourcing patterns....152
CQRS....153
Command-query separation....155
Event sourcing....155
Caching patterns....156
Updating caches....156
Designing data storage....159
Which NoSQL technology should I use?....160
Deploying your system....161
The sidecar pattern....161
Deploying a service with tracing and a reverse proxy using Envoy....162
Zero-downtime deployments....166
Blue–green deployment pattern....166
Canary release pattern....167
External configuration store pattern....169
Managing your APIs....169
API management tools....169
API gateways....170
Summary....171
Questions....172
Further reading....172
Chapter 5: Leveraging C Language Features....174
Technical requirements....175
Using RAII....175
Specifying the interfaces of containers in C....177
Using raw and smart pointers in interfaces....183
Specifying preconditions and postconditions....190
Employing inline namespaces....191
Applying std::optional....192
Optional function parameters....193
Optional function return values....193
Optional class members....194
Using monadic interfaces....195
Writing declarative code....199
Showcasing a featured items gallery....200
Applying standard ranges....206
Moving computations to compile time....208
Helping the compiler help you by using const....210
Leveraging the power of safe types....210
Constraining template parameters....211
Summary....214
Questions....215
Further reading....215
Chapter 6: Design Patterns and C Idioms....218
Technical requirements....218
Writing idiomatic C....219
Automating scope exit actions using RAII guards....219
Managing copyability and movability....220
Implementing non-copyable types....220
Adhering to the rules of three and five....221
Adhering to the rule of zero....221
Using hidden friends....222
Providing exception safety using the copy-and-swap idiom....224
Writing niebloids....226
Using the policy-based design idiom....228
Applying the curiously recurring template pattern....229
Knowing when to use dynamic versus static polymorphism....229
Implementing static polymorphism....230
Interlude: using type erasure....233
Implementing deducing this....235
Creating objects....238
Using factories....238
Using factory methods....238
Using factory functions....240
Choosing the return type of a factory....241
Using factory classes....241
Using builders....243
Using prototypes....246
Tracking state and visiting objects in C....247
Dealing with memory efficiently....251
Reducing dynamic allocations using SSOSBOSOO....252
Saving memory by herding COWs....255
Leveraging polymorphic allocators....256
Using memory arenas....256
Using the monotonic memory resource....260
Using pool resources....260
Writing your own memory resource....261
Ensuring there are no unexpected allocations....262
Winking out memory....262
Summary....264
Questions....264
Further reading....264
Chapter 7: Building and Packaging....266
Technical requirements....266
Getting the most out of compilers....266
Using multiple compilers....267
Reducing build times....268
Using a fast compiler....269
Rethinking templates....269
Leveraging tools....270
Finding potential code issues....272
Using compiler-centric tools....274
Abstracting the build process....274
Getting started with CMake....275
Creating CMake projects....276
Distinguishing between CMake directory variables....276
Specifying CMake targets....277
Specifying the output directories....278
Using generator expressions....279
Using external modules....280
Fetching dependencies....280
Using find scripts....282
Writing find scripts....283
Adding tests....286
Reusing quality code....289
Installing....289
Exporting....292
Using CPack....293
Summary....297
Questions....297
Further reading....297
Chapter 8: Package Management....300
Technical requirements....300
Introduction to package management....301
Using the Conan package manager....302
Preparing Conan profiles....302
Specifying Conan dependencies....304
Installing Conan dependencies....306
Using Conan targets from CMake....307
Packaging using Conan....308
Testing our Conan package....308
Creating and publishing our Conan package....309
Summary....312
Questions....312
Further reading....312
Chapter 9: The Future of C Code Reuse: Using Modules....314
Technical requirements....316
Introduction to C modules....316
Consuming modules....318
Creating your own modules....319
Migrating existing code bases to modules....323
Using modules with CMake....324
Using modules with Conan....326
Summary....328
Questions....328
Further reading....329
Part 3: Architectural Quality Attributes....330
Chapter 10: Writing Testable Code....332
Technical requirements....332
Why do you test code?....333
The testing pyramid....333
Non-functional testing....335
Regression testing....336
Root cause analysis....336
The groundwork for further improvement....337
Runtime testing frameworks....338
GTest example....339
Catch2 example....340
CppUTest example....340
Doctest example....341
Boost.Test example....342
DrogonTest example....342
[Boost].UT example....343
Compile-time testing techniques....344
Understanding test doubles....345
Different test doubles....345
Writing test doubles....346
gMock example....346
Trompeloeil example....350
CppUMock example....352
Test-driven class design....355
When tests and class design clash....355
The boring refrain: write your tests first....355
Defensive programming....355
Automating application tests for CICD....357
Automating infrastructure validation for CICD....358
Testing with Serverspec....359
Testing with Testinfra....359
Testing with Goss....360
Summary....360
Questions....361
Further reading....361
Chapter 11: Continuous Integration and Continuous Deployment....362
Technical requirements....363
Understanding and implementing CI....363
Release early, release often....363
Merits of CI....364
Implementing the pipeline with GitLab....364
Exploring gating mechanisms....367
Reviewing code changes....368
Different approaches to a code review....369
Using pull requests (merge requests) for a code review....370
Exploring test-driven automation....370
Behavior-driven development....371
Writing tests for CI....373
Continuous testing....373
Managing deployment as code....374
Using Ansible....375
How Ansible fits with the CICD pipeline....375
Using reusable components (roles) and playbooks in Ansible....376
Building deployment code....376
Understanding and implementing CD....377
Building an example CD pipeline with GitLab....378
Implementing a pre-commit workflow with GitHub Actions....379
Implementing the pipeline with GitHub Actions....381
Using immutable infrastructure....386
What is immutable infrastructure?....386
Benefits and practical considerations of immutable infrastructure....387
Building instance images with Packer....387
Orchestrating the infrastructure with Terraform....389
Summary....391
Questions....392
Further reading....392
Chapter 12: Security in Code and Deployment....394
Technical requirements....394
Security-conscious design....395
Making interfaces easy to use and hard to misuse....395
Enabling automatic resource management....399
Dealing with the drawbacks of concurrency....401
Secure coding guidelines and GSL....404
Defensive coding and validating everything....405
The most common vulnerabilities....409
Checking whether the dependencies are secure....410
Using the CVE list....410
Using automated scanners....411
Automated dependency upgrade management....411
Hardening your code....412
Security-oriented memory allocator....412
Automated checks....413
Compiler warnings....413
Static analysis....414
Dynamic analysis....416
Process isolation and sandboxing....418
Hardening your environment....422
Linking strategies and their security implications....423
Address space layout randomization....424
DevSecOps....424
Summary....426
Questions....426
Further reading....426
Chapter 13: Performance....428
Technical requirements....428
Measuring performance....429
Preparing for accurate and repeatable performance measurements....429
Leveraging different types of measuring tools....429
Using microbenchmarks....430
Setting up Google Benchmark....431
Writing your first microbenchmark....432
Reusing microbenchmark logic via argument capture....435
Varying input sizes using microbenchmark arguments....435
Benchmarking with Catch2....439
Benchmarking with nanobench....441
Choosing what to microbenchmark and optimize....444
Creating performance tests using benchmarks....444
Performance profiling....445
Choosing the type of performance profiler to use....445
Preparing the environment and processing the results....450
Analyzing the results....450
Tracing....451
Helping the compiler generate performant code....452
Optimizing whole programs....452
Optimizing based on real-world usage patterns....453
Writing cache-friendly code....453
Designing your code with data in mind....455
Parallelizing computations....457
Choosing between threads and processes....461
Using the standard parallel algorithms....461
Using OpenMP and MPI....462
Other platforms and tools for parallel programming....463
Using coroutines....464
Distinguishing between libcoro utilities....467
Looking under the hood of awaitables and coroutines....468
A practical example using libcoro....469
A practical example using coost....472
A practical example using Boost.Cobalt....474
Implementing efficient algorithms....477
Summary....486
Questions....486
Further reading....487
Part 4: Cloud-Native Design Principles....490
Chapter 14: Architecture of Distributed Systems....492
Technical requirements....492
Understanding SOA....493
Architectural implementations....493
ESB....493
Web services....496
Messaging and streaming....496
Cloud computing....499
Microservices....500
Benefits of SOA....500
Challenges with SOA....501
Diving into microservices....502
The benefits of microservices....502
Modularity....502
Scalability....504
Flexibility....505
Integration with legacy systems....505
Distributed development....505
Disadvantages of microservices....506
Reliance on a mature DevOps approach....506
Harder to debug....506
Additional overhead....506
Design patterns for microservices....507
Decomposition patterns....507
Database per service pattern....507
Deployment strategies....508
Design considerations for scalable microservices....508
Addressing scalability bottlenecks....509
Outsourcing memory management....509
Outsourcing storage....513
Outsourcing computing....513
Scaling microservices....514
Scaling a single service per host deployment....514
Scaling multiple services per host deployment....515
Leveraging managed services and cloud providers....515
Cloud computing as an extension of SOA....516
Accessing the cloud API....516
Using cloud provider APIs....517
Using API calls directly....517
Using API calls through a CLI tool....520
Using third-party tools that interact with the cloud API....521
Using the cloud CLI....522
Using tools that interact with the cloud API....522
Summary....523
Questions....523
Further reading....523
Chapter 15: Interservice Communication....526
Technical requirements....526
Introduction to interservice communication....526
Interaction styles....527
Messaging systems....529
Low-overhead messaging systems....530
MQTT....530
ZeroMQ....535
Brokered messaging systems....538
Apache Kafka....538
RabbitMQ....542
Using web services....546
Tools for working with web services....546
Web API payload formats....547
XML-based web services....547
SOAP libraries....550
JSON-based web services....550
Web API design approaches....552
REST....552
GraphQL....563
API description languages....568
OpenAPI....569
AsyncAPI....573
Remote procedure calls....576
Apache Thrift....577
RPC with RabbitMQ....579
gRPC....580
Summary....584
Questions....584
Further reading....584
Chapter 16: Containers....588
Technical requirements....588
Reintroducing containers....589
Exploring the container types....590
The parallel rise of microservices and containers....592
Choosing when to use containers....594
The benefits of containers....594
The disadvantages of containers....596
Building container images....597
Container images explained....598
Building container images with Dockerfiles....599
Naming and distributing images....600
Compiled applications and containers....601
Targeting multiple architectures....604
Alternative tools to build application containers....606
Buildah....606
ansible-bender....608
Integrating containers with CMake....609
Configuring the Dockerfile with CMake....609
Building container images with CMake....610
Practical runtime considerations for containers....611
Runtime libraries inside containers....612
Alternative container runtimes....613
Understanding container orchestration....614
Self-hosted solutions....614
Kubernetes....614
Docker Swarm....617
Nomad....618
OpenShift....621
Managed services....621
AWS ECS....621
AWS Fargate....622
Azure Service Fabric....622
Summary....622
Questions....623
Further reading....623
Chapter 17: Observability....626
Technical requirements....626
Logging....627
Logging with microservices....627
Logging in C with spdlog....627
Unified logging....629
Logstash....630
Filebeat....630
Fluentd....631
Fluent Bit....631
Vector....632
Log aggregation....633
Elasticsearch....633
Loki....633
Log visualization....633
Kibana....634
Grafana....634
Monitoring....636
Implementing application metrics....636
Monitoring health checks....641
Tracing....642
Jaeger and OpenTracing....643
Zipkin....644
OpenTelemetry....645
Summary....646
Questions....646
Further reading....646
Chapter 18: Cloud-Native Design....648
Technical requirements....649
Understanding cloud-native....649
Cloud Native Computing Foundation....649
Cloud as an operating system....650
Load balancing....651
Reverse and forward proxies....651
Service discovery....653
Using Kubernetes to orchestrate cloud-native workloads....654
Kubernetes structure....655
Control plane....656
Worker nodes....657
Possible approaches to deploying Kubernetes....657
Understanding the Kubernetes concepts....658
Managing Kubernetes declaratively....659
Kubernetes networking....668
Container-to-container communication....668
Pod-to-Pod communication....669
Pod-to-Service communication....669
External-to-internal communication....670
What to consider before adopting Kubernetes....670
Observability in cloud-native distributed systems....670
Instrumenting an application with OpenTelemetry....671
Connecting services with a service mesh....681
Introducing a service mesh....682
Service mesh solutions....683
Istio....683
Linkerd....684
Consul service mesh....685
Going GitOps....687
The principles of GitOps....687
Declarative description....687
System state versioned in Git....688
Auditability....688
Integrated with established components....688
Configuration drift prevention....689
The benefits of GitOps....689
Increased productivity....689
Better developer experience....689
Higher stability and reliability....690
Improved security....690
GitOps tools....690
FluxCD....691
ArgoCD....691
Jenkins X....691
Summary....691
Questions....692
Further reading....692
Chapter 19: Unlock Your Books Exclusive Benefits....694
Assessments....696
Other Books You May Enjoy....712
Index....718
Architect high-quality software systems using modern C++ and architectural practices, with expanded coverage and practical new examples throughout the book.
Designing scalable and maintainable software requires more than language expertise—it demands strong architectural thinking. This practical guide explores software architecture through the lens of modern C++, equipping you with the skills to design and build robust, distributed systems.
Starting with fundamental architectural principles and design philosophies, the book walks you through practical approaches to designing and deploying reliable systems. This edition contains significant updates across the book, including new chapters on observability, package management, and C++ modules to address real-world software challenges. You will explore software decomposition strategies, design and system patterns, fault tolerance, API management, and testability, with practical examples in modern C++.
Additionally, the book covers modern CI/CD pipelines, cloud-native design, microservices, and modular development, helping developers navigate today's fast-evolving software landscape. With updated examples and a renewed emphasis on maintainable and observable architectures, this edition equips C++ professionals to architect modern systems. By the end of the book, you will be able to design, build, test, and deploy well-architected software solutions using modern C++ and proven architectural techniques.
*Email sign-up and proof of purchase required
This book is intended for experienced C++ developers and software engineers aiming to expand their architectural knowledge, lead software projects, or build scalable systems. It assumes readers are comfortable with modern C++ (C++11 onwards) and familiar with basic design principles and patterns.