0%

Apply business requirements to IT infrastructure and deliver a high-quality product by understanding architectures such as microservices, DevOps, and cloud-native using modern C++ standards and features

Key Features

  • Design scalable large-scale applications with the C++ programming language
  • Architect software solutions in a cloud-based environment with continuous integration and continuous delivery (CI/CD)
  • Achieve architectural goals by leveraging design patterns, language features, and useful tools

Book Description

Software architecture refers to the high-level design of complex applications. It is evolving just like the languages we use. Modern C++ allows developers to write high-performance apps in a high-level language without sacrificing readability and maintainability. If you're working with modern C++, this practical guide will help you put your knowledge to work and design distributed, large-scale apps. You'll start by getting up to speed with architectural concepts, including established patterns and rising trends. The book will then explain what software architecture is and help you explore its components. Next, you'll discover the design concepts involved in application architecture and the patterns in software development, before going on to learn how to build, package, integrate, and deploy your components. In the concluding chapters, you'll explore different architectural qualities, such as maintainability, reusability, testability, performance, scalability, and security. Finally, you will get an overview of distributed systems, such as service-oriented architecture, microservices, and cloud-native, and understand how to apply them in application development.

By the end of this book, you'll be able to build distributed services using modern C++ and associated tools to deliver solutions as per your clients' requirements.

What you will learn

  • Understand how to apply the principles of software architecture
  • Apply design patterns and best practices to meet your architectural goals
  • Write elegant, safe, and performant code using the latest C++ features
  • Build applications that are easy to maintain and deploy
  • Explore the different architectural approaches and learn to apply them as per your requirement
  • Simplify development and operations using application containers
  • Discover various techniques to solve common problems in software design and development

Who this book is for

This software architecture C++ programming book is for experienced C++ developers who are looking to become software architects or are interested in developing enterprise-grade applications.

Table of Contents

  1. Title Page
  2. Copyrights
    1. Software Architecture with C++
  3. Dedication
  4. Contributors
    1. About the authors
    2. About the reviewer
  5. Preface
    1. Who this book is for
    2. What this book covers
    3. To get the most out of this book
    4. Download the example code files
    5. Download the color images
    6. Conventions used
    7. Get in touch
    8. Reviews
  6. Section 1: Concepts and Components of Software Architecture
  7. Importance of Software Architecture and Principles of Great Design
    1. Technical requirements
    2. Understanding software architecture
    3. Different ways to look at architecture
    4. Learning the importance of proper architecture
    5. Software decay
    6. Accidental architecture
    7. Exploring the fundamentals of good architecture
    8. Architecture context
    9. Stakeholders
    10. Business and technical environments
    11. Developing architecture using Agile principles
    12. Domain-driven design
    13. The philosophy of C++
    14. Following the SOLID and DRY principles
    15. Single responsibility principle
    16. Open-closed principle
    17. Liskov substitution principle
    18. Interface segregation principle
    19. Dependency inversion principle
    20. The DRY rule
    21. Coupling and cohesion
    22. Coupling
    23. Cohesion
    24. Summary
    25. Questions
    26. Further reading
  8. Architectural Styles
    1. Technical requirements
    2. Deciding between stateful and stateless approaches
    3. Stateless and stateful services
    4. Understanding monoliths—why they should be avoided, and recognizing exceptions
    5. Understanding services and microservices
    6. Microservices
    7. Benefits and disadvantages of microservices
    8. Characteristics of microservices
    9. Microservices and other architectural styles
    10. Scaling microservices
    11. Transitioning to microservices
    12. Exploring event-based architecture
    13. Common event-based topologies
    14. Event sourcing
    15. Understanding layered architecture
    16. Backends for Frontends
    17. Learning module-based architecture
    18. Summary
    19. Questions
    20. Further reading
  9. Functional and Nonfunctional Requirements
    1. Technical requirements documentation from sources, you must have
    2. Understanding the types of requirements
    3. Functional requirements
    4. Nonfunctional requirements
    5. Quality attributes
    6. Constraints
    7. Recognizing architecturally significant requirements
    8. Indicators of architectural significance
    9. Hindrances in recognizing ASRs and how to deal with them
    10. Gathering requirements from various sources
    11. Knowing the context
    12. Knowing existing documentation
    13. Knowing your stakeholders
    14. Gathering requirements from stakeholders
    15. Documenting requirements
    16. Documenting the context
    17. Documenting the scope
    18. Documenting functional requirements
    19. Documenting nonfunctional requirements
    20. Managing the version history of your documentation
    21. Documenting requirements in Agile projects 
    22. Other sections
    23. Documenting architecture
    24. Understanding the 4+1 model
    25. Understanding the C4 model
    26. Documenting architecture in Agile projects
    27. Choosing the right views to document
    28. Functional view
    29. Information view
    30. Concurrency view
    31. Development view
    32. Deployment and operational views
    33. Generating documentation
    34. Generating requirements documentation
    35. Generating diagrams from code
    36. Generating (API) documentation from code
    37. Summary
    38. Questions
    39. Further reading
  10. Section 2: The Design and Development of C++ Software
  11. Architectural and System Design
    1. Technical requirements
    2. Understanding the peculiarities of distributed systems
    3. Different service models and when to use them
    4. On-premises model
    5. Infrastructure as a Service (IaaS) model
    6. Platform as a Service (PaaS) model
    7. Software as a Service (SaaS) model
    8. Function as a Service (FaaS) model and serverless architecture 
    9. Avoiding the fallacies of distributed computing
    10. The network is reliable
    11. Latency is zero
    12. Bandwidth is infinite
    13. The network is secure
    14. Topology doesn't change
    15. There is one administrator
    16. Transport cost is zero
    17. The network is homogeneous
    18. CAP theorem and eventual consistency
    19. Sagas and compensating transactions
    20. Choreography-based sagas
    21. Orchestration-based sagas
    22. Making your system fault tolerant and available
    23. Calculating your system's availability
    24. Building fault-tolerant systems
    25. Redundancy
    26. Leader election
    27. Consensus
    28. Replication
    29. Master-slave replication
    30. Multi-master replication
    31. Queue-based load leveling
    32. Back pressure
    33. Detecting faults
    34. Sidecar design pattern
    35. Heartbeat mechanism
    36. Leaky bucket counter
    37. Minimizing the impact of faults
    38. Retrying the call
    39. Avoiding cascading failures
    40. Circuit breaker
    41. Bulkhead
    42. Geodes
    43. Integrating your system
    44. Pipes and filters pattern
    45. Competing consumers
    46. Transitioning from legacy systems
    47. Anti-corruption layer
    48. Strangler pattern
    49. Achieving performance at scale
    50. CQRS and event sourcing
    51. Command-query responsibility segregation
    52. Command-query separation
    53. Event sourcing
    54. Caching
    55. Updating caches
    56. Write-through approach
    57. Write-behind approach
    58. Cache-aside
    59. Deploying your system
    60. The sidecar pattern
    61. Deploying a service with tracing and a reverse proxy using Envoy
    62. Zero-downtime deployments
    63. Blue-green deployments
    64. Canary releases
    65. External configuration store
    66. Managing your APIs
    67. API gateways
    68. Summary
    69. Questions
    70. Further reading
  12. Leveraging C++ Language Features
    1. Technical requirements
    2. Designing great APIs
    3. Leveraging RAII
    4. Specifying the interfaces of containers in C++
    5. Using pointers in interfaces
    6. Specifying preconditions and postconditions
    7. Leveraging inline namespaces
    8. Leveraging std::optional
    9. Optional function parameters
    10. Optional function return values
    11. Optional class members
    12. Writing declarative code
    13. Showcasing a featured items gallery
    14. Introducing standard ranges
    15. Reducing memory overhead and increasing performance using ranges
    16. Moving computations at compile time
    17. Helping the compiler help you by using const
    18. Leveraging the power of safe types
    19. Constraining template parameters
    20. Writing modular C++
    21. Summary
    22. Questions
    23. Further reading
  13. Design Patterns and C++
    1. Technical requirements
    2. Writing idiomatic C++
    3. Automating scope exit actions using RAII guards
    4. Managing copyability and movability
    5. Implementing non-copyable types
    6. Adhering to the rules of three and five
    7. Adhering to the rule of zero
    8. Using hidden friends
    9. Providing exception safety using the copy-and-swap idiom
    10. Writing niebloids
    11. Policy-based design idiom
    12. Curiously recurring template pattern
    13. Knowing when to use dynamic versus static polymorphism
    14. Implementing static polymorphism
    15. Interlude – using type erasure
    16. Creating objects
    17. Using factories
    18. Using factory methods
    19. Using factory functions
    20. Choosing the return type of a factory
    21. Using factory classes
    22. Using builders
    23. Building with composites and prototypes
    24. Tracking state and visiting objects in C++
    25. Dealing with memory efficiently
    26. Reducing dynamic allocations using SSO/SOO
    27. Saving memory by herding COWs
    28. Leveraging polymorphic allocators
    29. Using memory arenas
    30. Using the monotonic memory resource
    31. Using pool resources
    32. Writing your own memory resource
    33. Ensuring there are no unexpected allocations
    34. Winking out memory
    35. Summary
    36. Questions
    37. Further reading
  14. Building and Packaging
    1. Technical requirements
    2. Getting the most out of compilers
    3. Using multiple compilers
    4. Reducing build times
    5. Using a fast compiler
    6. Rethinking templates
    7. Leveraging tools
    8. Finding potential code issues
    9. Using compiler-centric tools
    10. Abstracting the build process
    11. Introducing CMake
    12. Creating CMake projects
    13. Distinguishing between CMake directory variables
    14. Specifying CMake targets
    15. Specifying the output directories
    16. Using generator expressions
    17. Using external modules
    18. Fetching dependencies
    19. Using find scripts
    20. Writing find scripts
    21. Using the Conan package manager
    22. Preparing Conan profiles
    23. Specifying Conan dependencies
    24. Installing Conan dependencies
    25. Using Conan targets from CMake
    26. Adding tests
    27. Reusing quality code
    28. Installing
    29. Exporting
    30. Using CPack
    31. Packaging using Conan
    32. Creating the conanfile.py script
    33. Testing our Conan package
    34. Adding Conan packaging code to our CMakeLists
    35. Summary
    36. Questions
    37. Further reading
  15. Section 3: Architectural Quality Attributes
  16. Writing Testable Code
    1. Technical requirements
    2. Why do you test code?
    3. The testing pyramid
    4. Non-functional testing
    5. Regression testing
    6. Root cause analysis
    7. The groundwork for further improvement
    8. Introducing testing frameworks
    9. GTest examples
    10. Catch2 examples
    11. CppUnit examples
    12. Doctest examples
    13. Testing compile-time code
    14. Understanding mocks and fakes
    15. Different test doubles
    16. Other uses for test doubles
    17. Writing test doubles
    18. GoogleMock example
    19. Trompeloeil example
    20. Test-driven class design
    21. When tests and class design clash
    22. Defensive programming
    23. The boring refrain – write your tests first
    24. Automating tests for continuous integration/continuous deployment
    25. Testing the infrastructure
    26. Testing with Serverspec
    27. Testing with Testinfra
    28. Testing with Goss
    29. Summary
    30. Questions
    31. Further reading
  17. Continuous Integration and Continuous Deployment
    1. Technical requirements
    2. Understanding CI
    3. Release early, release often
    4. Merits of CI
    5. Gating mechanism
    6. Implementing the pipeline with GitLab
    7. Reviewing code changes
    8. Automated gating mechanisms
    9. Code review – the manual gating mechanism
    10. Different approaches to a code review
    11. Using pull requests (merge requests) for a code review
    12. Exploring test-driven automation
    13. Behavior-driven development
    14. Writing tests for CI
    15. Continuous testing
    16. Managing deployment as code
    17. Using Ansible
    18. How Ansible fits with the CI/CD pipeline
    19. Using components to create deployment code
    20. Building deployment code
    21. Building a CD pipeline
    22. Continuous deployment and continuous delivery
    23. Building an example CD pipeline
    24. Using immutable infrastructure
    25. What is immutable infrastructure?
    26. The benefits of immutable infrastructure
    27. Building instance images with Packer
    28. Orchestrating the infrastructure with Terraform
    29. Summary
    30. Questions
    31. Further reading
  18. Security in Code and Deployment
    1. Technical requirements
    2. Checking the code security
    3. Security-conscious design
    4. Making interfaces easy to use and hard to misuse
    5. Enabling automatic resource management
    6. Drawbacks of concurrency and how to deal with it
    7. Secure coding, the guidelines, and GSL
    8. Defensive coding, validating everything
    9. The most common vulnerabilities
    10. Checking whether the dependencies are secure
    11. Common Vulnerabilities and Exposures
    12. Automated scanners
    13. Automated dependency upgrade management
    14. Hardening your code
    15. Security-oriented memory allocator
    16. Automated checks
    17. Compiler warnings
    18. Static analysis
    19. Dynamic analysis
    20. Valgrind and Application Verifier
    21. Sanitizers
    22. Fuzz-testing
    23. Process isolation and sandboxing
    24. Hardening your environment
    25. Static versus dynamic linking
    26. Address space layout randomization
    27. DevSecOps
    28. Summary
    29. Questions
    30. Further reading
  19. Performance
    1. Technical requirements
    2. Measuring performance
    3. Performing accurate and meaningful measurements
    4. Leveraging different types of measuring tools
    5. Using microbenchmarks
    6. Setting up Google Benchmark
    7. Writing your first microbenchmark
    8. Passing arbitrary arguments to a microbenchmark
    9. Passing numeric arguments to a microbenchmark
    10. Generating the passed arguments programmatically
    11. Choosing what to microbenchmark and optimize
    12. Creating performance tests using benchmarks
    13. Profiling
    14. Choosing the type of profiler to use
    15. Preparing the profiler and processing the results
    16. Analyzing the results
    17. Tracing
    18. Correlation IDs
    19. Helping the compiler generate performant code
    20. Optimizing whole programs
    21. Optimizing based on real-world usage patterns
    22. Writing cache-friendly code
    23. Designing your code with data in mind
    24. Parallelizing computations
    25. Understanding the differences between threads and processes
    26. Using the standard parallel algorithms
    27. Parallelizing computations using OpenMP and MPI
    28. Using coroutines
    29. Distinguishing between cppcoro utilities
    30. Looking under the hood of awaitables and coroutines
    31. Summary
    32. Questions
    33. Further reading
  20. Section 4: Cloud-Native Design Principles
  21. Service-Oriented Architecture
    1. Technical requirements
    2. Understanding Service-Oriented Arcitecture
    3. Implementation approaches
    4. Enterprise Service Bus
    5. Web services
    6. Benefits and disadvantages of web services
    7. Messaging and streaming
    8. Message queues
    9. Message brokers
    10. Cloud computing
    11. Microservices
    12. Benefits of Service-Oriented Architecture
    13. Challenges with SOA
    14. Adopting messaging principles
    15. Low-overhead messaging systems
    16. MQTT
    17. ZeroMQ
    18. Brokered messaging systems
    19. Using web services
    20. Tools for debugging web services
    21. XML-based web services
    22. XML-RPC
    23. Relationship to SOAP
    24. SOAP
    25. WSDL
    26. UDDI
    27. SOAP libraries
    28. JSON-based web services
    29. JSON-RPC
    30. REpresentational State Transfer (REST)
    31. Description languages
    32. OpenAPI
    33. RAML
    34. API Blueprint
    35. RSDL
    36. Hypermedia as the Engine of Application State
    37. REST in C++
    38. GraphQL
    39. Leveraging managed services and cloud providers
    40. Cloud computing as an extension of SOA
    41. Using API calls directly
    42. Using API calls through a CLI tool
    43. Using third-party tools that interact with the Cloud API
    44. Accessing the cloud API
    45. Using the cloud CLI
    46. Using tools that interact with the Cloud API
    47. Cloud-native architecture
    48. Summary
    49. Questions
    50. Further reading
  22. Designing Microservices
    1. Technical requirements
    2. Diving into microservices
    3. The benefits of microservices
    4. Modularity
    5. Scalability
    6. Flexibility
    7. Integration with legacy systems
    8. Distributed development
    9. Disadvantages of microservices
    10. Reliance on a mature DevOps approach
    11. Harder to debug
    12. Additional overhead
    13. Design patterns for microservices
    14. Decomposition patterns
    15. Decomposition by business capability
    16. Decomposition by subdomain
    17. Database per service pattern
    18. Deployment strategies
    19. Single service per host
    20. Multiple services per host
    21. Observability patterns
    22. Log aggregation
    23. Application metrics
    24. Distributed tracing
    25. Health check APIs
    26. Building microservices
    27. Outsourcing memory management
    28. Memcached
    29. Redis
    30. Which in-memory cache is better?
    31. Outsourcing storage
    32. Outsourcing computing
    33. Observing microservices
    34. Logging
    35. Logging with microservices
    36. Logging in C++ with spdlog
    37. Unified logging layer
    38. Logstash
    39. Filebeat
    40. Fluentd
    41. Fluent Bit
    42. Vector
    43. Log aggregation
    44. Elasticsearch
    45. Loki
    46. Log visualization
    47. Kibana
    48. Grafana
    49. Monitoring
    50. Tracing
    51. OpenTracing
    52. Jaeger
    53. OpenZipkin
    54. Integrated observability solutions
    55. Connecting microservices
    56. Application programming interfaces (APIs)
    57. Remote procedure calls
    58. Apache Thrift
    59. gRPC
    60. Scaling microservices
    61. Scaling a single service per host deployment
    62. Scaling multiple services per host deployment
    63. Summary
    64. Questions
    65. Further reading
  23. Containers
    1. Technical requirements
    2. Reintroducing containers
    3. Exploring the container types
    4. The rise of microservices
    5. Choosing when to use containers
    6. The benefits of containers
    7. The disadvantages of containers
    8. Building containers
    9. Container images explained
    10. Using Dockerfiles to build an application
    11. Naming and distributing images
    12. Compiled applications and containers
    13. Targeting multiple architectures with manifests
    14. Alternative ways to build application containers
    15. Buildah
    16. Ansible-bender
    17. Others
    18. Integrating containers with CMake
    19. Configuring the Dockerfile with CMake
    20. Integrating containers with CMake
    21. Testing and integrating containers
    22. Runtime libraries inside containers
    23. Alternative container runtimes
    24. Understanding container orchestration
    25. Self-hosted solutions
    26. Kubernetes
    27. Docker Swarm
    28. Nomad
    29. OpenShift
    30. Managed services
    31. AWS ECS
    32. AWS Fargate
    33. Azure Service Fabric
    34. Summary
    35. Questions
    36. Further reading
  24. Cloud-Native Design
    1. Technical requirements
    2. Understanding cloud-native
    3. Cloud-Native Computing Foundation
    4. Cloud as an operating system
    5. Load balancing and service discovery
    6. Reverse proxies
    7. Service Discovery
    8. Using Kubernetes to orchestrate cloud-native workloads
    9. Kubernetes structure
    10. Control plane
    11. Worker nodes
    12. Possible approaches to deploying Kubernetes
    13. Understanding the Kubernetes concepts
    14. Declarative approach
    15. Kubernetes networking
    16. Container-to-container communication
    17. Pod-to-pod communication
    18. Pod-to-service communication
    19. External-to-internal communication
    20. When is using Kubernetes a good idea?
    21. Observability in distributed systems
    22. How tracing differs from logging
    23. Choosing a tracing solution
    24. Jaeger and OpenTracing
    25. Zipkin
    26. Instrumenting an application with OpenTracing
    27. Connecting services with a service mesh
    28. Introducing a service mesh
    29. Service mesh solutions
    30. Istio
    31. Envoy
    32. Linkerd
    33. Consul service mesh
    34. Going GitOps
    35. The principles of GitOps
    36. Declarative description
    37. The system's state versioned in Git
    38. Auditable
    39. Integrated with established components
    40. Configuration drift prevention
    41. The benefits of GitOps
    42. Increased productivity
    43. Better developer experience
    44. Higher stability and reliability
    45. Improved security
    46. GitOps tools
    47. FluxCD
    48. ArgoCD
    49. Jenkins X
    50. Summary
    51. Questions
    52. Further reading
  25. Appendix A
    1. Designing data storage
    2. Which NoSQL technology should I use?
    3. Serverless architecture
    4. Communication and culture
    5. DevOps
  26. Assessments
    1. Chapter 1
    2. Chapter 2
    3. Chapter 3
    4. Chapter 4
    5. Chapter 5
    6. Chapter 6
    7. Chapter 7
    8. Chapter 8
    9. Chapter 9
    10. Chapter 10
    11. Chapter 11
    12. Chapter 12
    13. Chapter 13
    14. Chapter 14
    15. Chapter 15
  27. About Packt
    1. Why subscribe?
  28. Other Books You May Enjoy
    1. Packt is searching for authors like you
    2. Leave a review - let other readers know what you think
3.139.104.214