Microservices
- High Overview
- Monolithic
- Microservices
- Architecture
Category | Monolithic architecture | Microservices architecture |
---|---|---|
Design | Single code base with multiple interdependent functions | Independent software components with autonomous functionality that communicate with each other using APIs |
Development | Requires less planning at the start, but gets increasingly complex to understand and maintain | Requires more planning and infrastructure at the start, but gets easier to manage and maintain over time |
Deployment | Entire application deployed as a single entity | Every microservice is an independent software entity that requires individual containerized deployment |
Debugging | Trace the code path in the same environment | Requires advanced debugging tools to trace the data exchange between multiple microservices |
Modification | Small changes introduce greater risks as they impact the entire code base | You can modify individual microservices without impacting the entire application |
Scale | You have to scale the entire application, even if only certain functional areas experience an increase in demand | You can scale individual microservices as required, which saves overall scaling costs |
Investment | Low upfront investment at the cost of increased ongoing and maintenance efforts | Additional time and cost investment to set up the required infrastructure and build team competency. However, long-term cost savings, maintenance, and adaptability |
Use Cases |
|
|
- Overview
- Modular Monolith
Monolithic architecture is a single application that is built as a single unit. Is a singular, large computing network with one code base that couples all of the business concerns together. To make a change to this sort of application requires updating the entire stack by accessing the code base and building and deploying an updated version of the complete application.
- Monolithic applications initially offer advantages such as ease of development and deployment
- Challenges arise as teams grow, leading to blocked deploys, cross-team functionality issues, and difficulties with updates
As a result, monolithic applications are often difficult to scale and maintain and often migrate to a microservices architecture. This involves identifying and modifying tightly coupled entities, which is complex.
Monolithic applications can be transformed into modular monolith by starting with a single repository and clear boundaries between business contexts. Which will allow for easier transition to microservices architecture.
Advantages of Modular Monolith
- Bounded contexts in a modular monolith encompass independent business functions
- Isolating business contexts within a single codebase and database prevents future issues and facilitates changes
- Changes within a modular monolith are less costly compared to traditional monoliths, as data migration isn't necessary
- Communication between modules in a modular monolith should utilize events instead of direct method calls
- Techniques for maintaining data consistency and event management include emitting events, using databases, or employing message queues
Segregation by Feature
- Overview
- Advantages
- Principles
- Best Practices
Microservices are independent, and loosely coupled software components that perform specific tasks within a larger application, facilitating scalability, flexibility, and maintainability in software development. They organize the subdomains into one or more deployable/executable components.
Golden Rule
- we need to ensure that our microservices are independently deployable
- if we needed to update our country codes library, and have all services pick up the new data immediately, we'd need to redeploy all services at the moment the new library is available
- this is a classic lock-step release, and exactly what we're trying to avoid with microservice architectures
- Simple Components: Small, focused components, simplifying development and maintenance
- Team Autonomy: Teams should have the independence to develop, test, and deploy their software autonomously, enabling faster iterations and reducing dependencies on other teams
- Fast Deployment Pipeline: A rapid deployment pipeline facilitates quick feedback and frequent deployments
- Support for Multiple Technology Stacks: Applications may utilize various technologies within different subdomains, requiring developers to update the technology stack to maintain compatibility with current languages and frameworks
- Segregation by Characteristics: Segregating components based on characteristics like resource requirements, availability, and security enhances scalability, availability, and security, respectively
- Simple Interactions: Operations that involve local or straightforward interactions between components are easier to troubleshoot
- Efficient Interactions: Distributed operations involving numerous network round trips and large data transfers can be inefficient and should be minimized for optimal performance
- Prefer ACID over BASE: Implementing operations as ACID transactions rather than eventually consistent sagas simplifies development and maintenance
- Minimize Runtime Coupling: Reducing runtime coupling maximizes availability and minimizes latency for operations, improving overall system performance
- Minimize Design Time Coupling: Decreasing design time coupling reduces the likelihood of services needing to be changed simultaneously, enhancing productivity and flexibility in development
-
Organized around Business Capabilities
- Traditional division based on technology layers leads to cross-team projects for even simple changes due to Conway's Law (the way people within an organization communicate influences the structure of the systems they build)
- Microservice approach focuses on organizing services around business capabilities
- Cross-functional teams with skills for entire development process
-
Size of Microservices
- Varies, often sized around Amazon's "Two Pizza Team" concept (organizing teams small enough that they can be fed with just two pizzas)
- Ranges from a dozen people supporting several services to a smaller team per service
-
Product Ownership
- Microservice teams own products over their full lifetime
- Inspired by Amazon's "you build, you run it" philosophy
- Emphasizes ongoing relationship and enhancing business capabilities
-
Communication Structure
- Smart endpoints and dumb pipes approach
- Microservices use simple protocols like HTTP request-response and lightweight messaging
-
Comparison with SOA
- Microservices similar to some aspects of Service Oriented Architecture (SOA) but with distinct differences by focusing on avoiding pitfalls of traditional SOA implementations
-
Decentralized Governance
- Encourages using right tools for the job rather than standardizing on single technology platforms
- Promotes producing useful tools shared within teams, similar to internal open source model
-
Infrastructure Automation
- Utilizes extensive automation techniques for building, deploying, and operating microservices
- Enables teams to manage infrastructure efficiently and deploy software frequently
-
Design Considerations
- Emphasis on failure tolerance, real-time monitoring, and asynchronous communication
- Supports evolutionary design, modular decomposition, and granular release planning
- Prefers tolerant services over heavy versioning for managing changes
- Use separate data storage for each microservice
- Keep code at a similar level of maturity
- Separate build for each microservice
- Assign each microservice with a single responsibility
- Deploy into containers
- Design stateless services
- Adopt Domain-Driven Design (DDD)
- Design micro frontend
- Orchestrating microservices with Kubernetes
Aspect | On-Premises | Infrastructure-as-a-Service (IaaS) | Platform-as-a-Service (PaaS) | Software-as-a-Service (SaaS) |
---|---|---|---|---|
Application | π’ | π’ | π’ | π£ |
Data | π’ | π’ | π’ | π£ |
Runtime | π’ | π’ | π£ | π£ |
Middleware | π’ | π’ | π£ | π£ |
O/S | π’ | π’ | π£ | π£ |
Virtualization | π’ | π£ | π£ | π£ |
Servers | π’ | π£ | π£ | π£ |
Storage | π’ | π£ | π£ | π£ |
Networking | π’ | π£ | π£ | π£ |
|
Architecture Overviewβ
- Overview
- Common Setup
- Architectural Layers
- Repos
Visualization | Specs |
---|---|
|
Pre-Production | Production |
---|---|
|
|
Aspect | Micro Frontends | Microservices | Data Mesh |
---|---|---|---|
Visualization | |||
Definition | Architectural style for frontend development, breaking down a frontend app into smaller, manageable pieces | Architectural style for backend development, breaking down a monolithic app into smaller, independent services | Architectural approach for data management, decentralizing data ownership to domain-specific teams |
Focus | User interface components | Business capabilities | Data ownership |
Purpose | Enable multiple teams to work on different parts of a frontend application independently | Enable independent development, deployment, and scaling of backend services | Address challenges in centralized data architectures by decentralizing data ownership and governance |
Key Principles |
|
|
|
Benefits |
|
|
|
Challenges |
|
|
|
Deployment | Independent deployments | ||
Collaboration | Requires cross-team collaboration and communication |
Aspect | Monorepo | Multi-Repo |
---|---|---|
Repository Structure | Single repository containing multiple projects/packages | Separate repositories for each project/package |
Dependency Management | Shared dependencies managed centrally | Each repository manages its own dependencies |
Build & CI/CD | Unified build and CI/CD pipelines | Separate pipelines for each repository |
Code Ownership | Clear ownership and responsibility | Ownership can be more fragmented and decentralized |
Deployment | Single deployment process | Each repository may have its own deployment process |
Performance | Can lead to larger repository size and slower operations | Smaller repositories can have faster operations |
Testing | Easier integration testing across projects/packages | Testing is more isolated, might require more integration efforts |
Scaling | Might face scalability challenges with a very large codebase | Easier to scale by adding more repositories |
Overhead | Potentially higher overhead due to managing a large codebase | Lower overhead for smaller repositories |
Project Structureβ
- Frontend
- Backend
- Overview
- File Type Based
- Module / Feature Based
- Atomic Design
- Clean Architecture
Aspect | File Type Based | Module/Feature Based | Atomic Design | Clean Architecture |
---|---|---|---|---|
Focus | File types (JSX, CSS, tests) | Functional modules, features | UI component hierarchy | Business logic separation (layers) |
Scalability | Small to medium projects | Medium to large projects | Scalable for complex UIs | Very scalable, promotes separation of concerns |
Use Cases | Simple apps, prototypes | Complex features, e-commerce applications | Component libraries, design systems | Large-scale enterprise applications with strict separation |
src/
βββ components/
β βββ Avatar/
β β βββ Avatar.jsx
β β βββ Avatar.test.js
β βββ Button/
β β βββ Button.jsx
β β βββ Button.test.js
β βββ TextField/
β βββ TextField.jsx
β βββ TextField.test.js
βββ contexts/
β βββ UserContext/
β βββ UserContext.js
βββ hooks/
β βββ useMediaQuery/
β βββ useMediaQuery.js
βββ pages/
β βββ UserProfile/
β β βββ components/
β β β βββ UserProfileComponent/
β β β βββ UserProfileComponent.jsx
β β β βββ UserProfileComponent.test.js
β β βββ UserProfile.jsx
β β βββ UserProfile.test.js
β βββ index.js
βββ routes/
β βββ routes.jsx
β βββ routes.test.js
βββ utils/
β βββ custom-util/
β βββ index.js
β βββ customUtil.js
β βββ index.test.js
βββ services/
β βββ custom-service/
β βββ index.js/
β βββ customService.js/
β βββ index.test.js
βββ App.jsx
βββ index.js
src/
βββ components/
β βββ Avatar/
β β βββ Avatar.jsx
β β βββ Avatar.test.js
β βββ Button/
β β βββ Button.jsx
β β βββ Button.test.js
β βββ TextField/
β βββ TextField.jsx
β βββ TextField.test.js
βββ contexts/
β βββ UserContext/
β βββ UserContext.js
βββ hooks/
β βββ useMediaQuery/
β βββ useMediaQuery.js
βββ features/
β βββ Home/
β β βββ components/
β β β βββ UserProfileComponent/
β β β βββ UserProfileComponent.jsx
β β β βββ UserProfileComponent.test.js
β β βββ utils/
β β βββ services/
β β βββ hooks/
β β βββ contexts/
β β βββ views/
β β β βββ HomeView.jsx
β β βββ pages/
β β βββ HomePage.jsx
β βββ index.js
βββ utils/
β βββ custom-common-util/
β βββ index.js/
β βββ index.test.js
βββ services/
β βββ custom-common-service/
β βββ index.js/
β βββ custom-common-service.js/
β βββ index.test.js
βββ App.jsx
βββ index.js
src/
βββ components/
β βββ atoms/ β Single UI elements
β β βββ Button/
β β βββ Button.js
β β βββ Button.css
β βββ molecules/ β Groups of atoms with a function
β β βββ SearchBar/
β β βββ SearchBar.js
β β βββ SearchBar.css
β βββ organisms/ β Complex components from molecules/atoms
β β βββ Header/
β β β βββ Header.js
β β β βββ Header.css
β β βββ ProductList/
β β βββ ProductList.js
β β βββ ProductList.css
β βββ templates/ β Layouts for arranging UI on a page
β βββ DefaultTemplate/
β βββ DefaultTemplate.js
β βββ DefaultTemplate.css
βββ pages/ β Final product with real content in templates
β βββ HomePage/
β β βββ HomePage.js
β β βββ HomePage.css
β βββ AboutPage/
β βββ AboutPage.js
β βββ AboutPage.css
βββ shared/
βββ public/
src/
βββ domain/
β βββ models/
β β βββ User.js/
β βββ services/
β βββ User.service.js/
βββ infrastructure/
β βββ components/
β β βββ Avatar/
β β β βββ Avatar.jsx
β β β βββ Avatar.test.js
β β βββ UserProfile/
β β βββ UserProfile.jsx
β β βββ UserProfile.test.js
β βββ http/
β β βββ dto/
β β β βββ userDto.js/
β β βββ http.js
β βββ repositories/
β βββ user.repository.js/
βββ App.jsx
βββ index.js
- Overview
- Layered Architecture
- Feature Based Architecture
- Clean / Hexagonal Architecture (DDD)
Aspect | Layered Architecture | Feature-Based Architecture | Clean / Hexagonal Architecture (DDD) |
---|---|---|---|
Core Concept | Segregation into layers such as Presentation, Business Logic, Data Access | Organization around features/modules with self-contained folders | Focus on domain-driven design, with clear boundaries between domain and application layers |
Dependencies | Layer dependencies are hierarchical | Feature modules are more independent but may share utilities | Dependent on use cases, but typically focuses on domain logic being independent of infrastructure |
Scalability | Can become rigid and hard to scale with increasing complexity | Scales well with the growth of features, easier to manage | Provides a scalable structure, but may require careful management of dependencies |
Domain-Centric Focus | Less emphasis on domain modeling, more on technical layers | Features encapsulate domain logic but may not focus solely on it | Central focus on domain modeling, with application logic structured around it |
Ease of Maintenance | Changes may require modifications across multiple layers | Easier maintenance due to encapsulation within features | Maintenance focused on the domain model, with changes reflected through adapters |
project_name/
βββ src/
β βββ config/
β β βββ database
β β βββ app
β βββ controllers/
β β βββ UserController
β β βββ ProductController
β βββ models/
β β βββ User
β β βββ Product
β βββ repositories/
β β βββ UserRepository
β β βββ ProductRepository
β βββ services/
β β βββ UserService
β β βββ ProductService
β βββ middlewares/
β β βββ AuthenticationMiddleware
β β βββ AuthorizationMiddleware
β βββ exceptions/
β β βββ CustomException
β β βββ HttpException
β βββ utils/
β β βββ Validation
β β βββ HelperFunctions
β βββ routes/
β β βββ web
β β βββ api
β βββ views/
β βββ user/
β β βββ profileView
β βββ product/
β βββ listView
βββ tests/
β βββ Unit/
β β βββ UserControllerTest
β β βββ ProductControllerTest
β βββ Feature/
β βββ UserFeatureTest
β βββ ProductFeatureTest
βββ database/
β βββ migrations/
β β βββ 20240101000000_create_users_table
β β βββ 20240102000000_create_products_table
β βββ seeds/
β βββ UsersTableSeeder
β βββ ProductsTableSeeder
βββ vendor/
βββ storage/
βββ config/
βββ app
βββ database
project_name/
βββ src/
β βββ Features/
β β βββ User/
β β β βββ Controllers/
β β β β βββ UserController
β β β βββ Models/
β β β β βββ User
β β β βββ Repositories/
β β β β βββ UserRepository
β β β βββ Services/
β β β β βββ UserService
β β β βββ Routes/
β β β β βββ web
β β β β βββ api
β β β ββββViews
β β β βββ profileView
β β βββ Product/
β β βββ Controllers/
β β β βββ ProductController
β β βββ Models/
β β β βββ Product
β β βββ Repositories/
β β β βββ ProductRepository
β β βββ Services/
β β β βββ ProductService
β β βββ Routes/
β β β βββ web
β β β βββ api
β β ββββViews/
β β βββ listView
β βββ Shared/
β β βββ Helpers/
β β β βββ Validation
β β βββ Exceptions/
β β β βββ CustomException
β β βββ Middleware/
β β β βββ AuthenticationMiddleware
β β βββ Services/
β β β βββ AuthService
β β βββ Models/
β β β βββ BaseModel
β β βββ Repositories/
β β βββ BaseRepository
β βββ Routes/
β βββ web
β βββ api
βββ tests/
β βββ Unit/
β β βββ User/
β β β βββ UserControllerTest
β β βββ Product/
β β βββ ProductControllerTest
β ββββFeature/
β βββ User/
β β βββ UserFeatureTest
β βββ Product/
β βββ ProductFeatureTest
βββ database/
β βββ migrations/
β β βββ 20240101000000_create_users_table
β β βββ 20240102000000_create_products_table
β ββββseeds/
β βββ UsersTableSeeder
β βββ ProductsTableSeeder
βββ vendor/
βββ config/
βββ app
βββ database
project_name/
βββ src/
β βββ Application/
β β βββ Services/
β β β βββ UserService
β β β βββ ProductService
β β βββ UseCases/
β β βββ User/
β β β βββ CreateUserUseCase
β β β βββ GetUserUseCase
β β βββ Product/
β β βββ CreateProductUseCase
β β βββ GetProductUseCase
β βββ Domain/
β β βββ Entities/
β β β βββ User
β β β βββ Product
β β βββ Repositories/
β β βββ UserRepositoryInterface
β β βββ ProductRepositoryInterface
β βββ Infrastructure/
β βββ Persistence/
β βββ Repositories/
β βββ EloquentUserRepository
β βββ EloquentProductRepository
βββ tests/
β βββ Unit/
β β βββ Application/
β β β βββ Services/
β β β β βββ UserServiceTest
β β β β βββ ProductServiceTest
β β β βββ UseCases/
β β β βββ User/
β β β β βββ CreateUserUseCaseTest
β β β β βββ GetUserUseCaseTest
β β β βββ Product/
β β β βββ CreateProductUseCaseTest
β β β βββ GetProductUseCaseTest
β β βββ Domain/
β β β βββ Entities/
β β β β βββ UserTest
β β β β βββ ProductTest
β β β βββ Repositories/
β β β βββ UserRepositoryTest
β β β βββ ProductRepositoryTest
β β βββ Infrastructure/
β β βββ Persistence/
β β βββ Repositories/
β β βββ EloquentUserRepositoryTest
β β βββ EloquentProductRepositoryTest
β βββ Feature/
β βββ User/
β β βββ UserFeatureTest
β βββ Product/
β βββ ProductFeatureTest
βββ database/
β βββ migrations/
β β βββ 20240101000000_create_users_table
β β βββ 20240102000000_create_products_table
β βββ seeds/
β βββ UsersTableSeeder
β βββ ProductsTableSeeder
βββ vendor/
βββ config/
βββ app
βββ database
Migrationβ
- Process
- Service Decomposition
- Scale
-
Discovering system operations
- Analyzing existing monolithic architecture
- Identifying functionalities and dependencies
- Documenting system components, interactions, and data flows
- Conducting interviews with stakeholders to understand business requirements
- Profiling system performance and resource utilization
- Assessing scalability and maintainability issues in the current architecture
- Generating system documentation and diagrams (e.g., entity-relationship diagrams, flowcharts)
-
Defining subdomains
- Use domain-driven design approach
- Identifying business capabilities and boundaries
- Decomposing the monolithic system into cohesive subdomains
- Prioritizing subdomains based on business impact and complexity
- Defining bounded contexts for each subdomain
- Documenting subdomain boundaries, responsibilities, and contexts
-
Designing services and their collaborations
- Selecting appropriate communication protocols (e.g., REST, gRPC, GraphQL, Publish-Subscribe messaging)
- Defining service interfaces and contracts
- Choosing technology stacks for individual services
- Designing fault-tolerant and resilient services
- Implementing event-driven architectures or choreographed workflows
- Establishing service discovery and registry mechanisms
- Developing API gateways for routing and security
- Implementing circuit breakers and retries for robustness
- Designing data consistency strategies (e.g., eventual consistency, transactional boundaries)
- Defining service versioning and backward compatibility policies
-
Evaluating a microservice architecture
- Performing architectural reviews and inspections
- Conducting proof-of-concept implementations
- Analyzing trade-offs between microservices and monolithic architectures
- Evaluating scalability, performance, and latency requirements
- Assessing operational overhead and deployment complexities
- Conducting cost-benefit analysis of microservices adoption
- Benchmarking against key performance indicators (KPIs) and service level objectives (SLOs)
- Considering organizational readiness and cultural implications
-
Refactoring a microservice architecture
- Identifying code smells and anti-patterns in the existing architecture
- Decomposing monolithic codebase into microservices
- Applying domain-driven design principles for service boundaries
- Implementing continuous integration and continuous deployment (CI/CD) pipelines
- Automating testing, deployment, and monitoring processes
- Establishing DevOps practices for collaboration and feedback loops
- Implementing distributed tracing and logging for observability
- Refactoring data storage and access patterns
- Ensuring backward compatibility and data migration strategies
- Documenting refactoring decisions and outcomes
- Overview
- Decompose by Subdomain / Business Capability
- Self-Contained Service
- Service per Team
- Strangler Pattern
- Branch by Abstraction
- Parallel Run
- Decorating Collaborator
- Change Data Capture
Aspect | Decompose by Business Capability | Decompose by Subdomain | Self-contained Service | Service per Team | Strangler Application | Anti-corruption Layer |
---|---|---|---|---|---|---|
Definition | Breaks down the application into services based on business capabilities or functions | Splits services based on different subdomains or components of the business | Each service is independent and complete in itself, reducing dependencies | Each team is responsible for one or more services, allowing for ownership and autonomy | A new system slowly replaces the old one by gradually taking over its functionalities | Creates a layer between two services to ensure that changes in one do not affect the other |
Complexity | Medium. Requires a good understanding of business capabilities | High. Requires a deep understanding of the domain and its subdomains | High. Each service must be self-sufficient | Low. Teams have full control over their services | Medium. Requires careful planning and incremental implementation | Medium. Requires understanding of both services involved |
Use Cases | Large applications with distinct business functions | Complex domains with distinct subdomains | Applications where each service can operate independently | Teams with specific domain knowledge or skills | Legacy systems that need to be replaced | Preventing unwanted dependencies between services |
- Stable Architecture: Ensure the architecture is robust and consistent, minimizing disruptions and failures
- Cohesive Services: Services should focus on a specific set of closely related functions, enhancing clarity and maintainability
- Common Closure Principle: Group together components that are likely to change together, reducing the ripple effect of modifications across the system
- Loose Coupling: Services should expose clear APIs to interact with, allowing for flexibility in implementation changes without impacting clients
- Testability: Each service should be designed to be easily testable, facilitating quality assurance and reliability
- Scalable Team Size: Services should be small enough that they can be developed and managed effectively by a team of 6-10 people, promoting efficiency and communication
- Autonomous Teams: Teams responsible for services should have the autonomy to develop, deploy, and maintain their services independently, minimizing dependencies and streamlining workflows
Pros
- Improved availability and response time
Cons
- Increased cost and complexity of using CQRS
- Increased complexity of using sagas
- Less straightforward API when using sagas
Pros
- Facilitates autonomous team work with minimal coordination
- Promotes loose coupling between teams
- Achieves autonomy and loose coupling with fewer services
- Enhances code quality through long-term ownership
Cons
- Teams may not always align with end user features
- Implementing cross-service features becomes more complex and requires collaboration between teams
-
Identify the system boundary you want to re-architect
-
Create a facade
- During system re-architecture, it's crucial that clients remain unaffected. To achieve this, the facade should align with the existing system API, providing a seamless transition for users
- API of the new service needs to be meticulously crafted to maintain backward compatibility with the legacy API. Any potential breaking changes to the new service's API should only be implemented after the re-architecture process is complete
- Re-architect
- Implement the new service and integrate it with the strangler facade
- Dark launch the new service by diverting traffic between the new and legacy implementations
- Initially, return responses from the legacy implementation while monitoring the behavior of the new implementation
- Optionally, employ continuous deployment to deploy partial implementations of the new service to gain confidence and reduce risk
- Cutover
- Once confident in the new implementation, switch production traffic to be served from the new implementation
- Retain the legacy implementation for easy rollback if necessary
- Clean up
- Delete the legacy code that has been replaced once the new system is established
- Migrate clients to the new API and remove the strangler facade
- Manage the transition to the new API, potentially requiring breaking changes to clients
- Expose the new API while maintaining the strangler facade for large client bases
- Monitor usage of the strangler facade and assist clients in migrating to the new API
- Remove the strangler facade once it's no longer in use
Steps
- Create an abstraction for the functionality that needs to be replaced
- Modify clients of the existing functionality to use the new abstraction
- Develop a new implementation of the abstraction with the reworked functionality
- Switch over to using the new implementation by adapting the abstraction
- Once the transition is complete and the new implementation is proven, clean up the abstraction
- Remove the old implementation once it's no longer needed
- Instead of solely calling either the old or new implementation, both are called simultaneously
- This enables comparison of results to ensure equivalence
- Despite calling both, only one implementation is regarded as the "source of truth" at any moment
- Initially, the old implementation serves as the source of truth until ongoing verification validates the reliability of the new implementation
- This technique verifies not only the equivalence of results but also ensures that the new implementation operates within acceptable nonfunctional parameters
- It enables attaching new functionality to an object without the object being aware of it
- By using a decorator, it seems as if the monolith is directly communicating with services, without altering the monolith itself
- Instead of intercepting calls before reaching the monolith, the calls proceed normally
- After the call, based on the result, external microservices can be invoked through any chosen collaboration mechanism
- It involves reacting to changes made within a datastore rather than intercepting and acting on calls made into the monolith
- The effectiveness of change data capture relies on coupling the underlying capture system to the monolith's datastore
- Change data capture serves as a useful, versatile pattern, particularly for scenarios involving data replication
- In the context of microservices migration, this approach is most beneficial when there's a need to respond to data changes within the monolith, but it's not feasible to intercept them at the system's perimeter using techniques like strangler or decorator, nor is it possible to modify the underlying codebase