0% found this document useful (0 votes)
20 views19 pages

Chapter3 DevOps Arch

Chapter 3 discusses the impact of DevOps on software architecture, emphasizing the importance of modularity, rapid deployment, and the separation of concerns. It highlights the challenges of monolithic architectures and advocates for microservices and the Twelve-Factor App principles to enhance deployment speed and reliability. The chapter also addresses database management and the need for careful versioning and compatibility in a DevOps environment.

Uploaded by

pendemmahesh2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views19 pages

Chapter3 DevOps Arch

Chapter 3 discusses the impact of DevOps on software architecture, emphasizing the importance of modularity, rapid deployment, and the separation of concerns. It highlights the challenges of monolithic architectures and advocates for microservices and the Twelve-Factor App principles to enhance deployment speed and reliability. The chapter also addresses database management and the need for careful versioning and compatibility in a DevOps environment.

Uploaded by

pendemmahesh2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Chapter 3 – How DevOps Affects

Architecture

1. What is Software Architecture?

Software architecture is about how a system is structured:

●​ What parts it has


●​ How those parts talk to each other
●​ How easy it is to change, deploy, and scale
In DevOps, we care less about what the software does and more about:

●​ How fast we can deploy changes


●​ How safely we can deploy changes

Example

●​ Functional requirement: “The system should process credit card payments.”


●​ Non-functional requirement: “The system should process 1,000 payments per
second.”
👉 DevOps mainly influences non-functional requirements.
2. DevOps Requirements on Architecture

DevOps and Continuous Delivery (CD) demand two things:

1.​ Small changes should be deployable frequently


2.​ Deployments should be safe and predictable
👉 Ideally:
●​ A developer fixes a small issue
●​ The fix goes to production quickly
●​ Rollbacks are rare, not normal

3. The Monolithic Architecture Problem

What is a Monolith?

A monolith is a system where:

●​ Everything is bundled into


●​ one big application
●​ Frontend, backend, static pages, and logic are all together

Example Problem

You want to fix one spelling mistake on a website But the whole application is packed as one
big Java archive

So you must:

●​ Rebuild everything
●​ Redeploy everything
●​ Risk breaking the whole system

Why this is bad for DevOps?

●​ A tiny change feels dangerous


●​ You must test and verify the entire system
●​ High stress, slow deployments, higher risk
👉 Monoliths slow down Continuous Delivery
4. Key Design Rule: Separation of Concerns
Proposed by Edsger Dijkstra

Different responsibilities should be kept separate.

Related Concepts

●​ Cohesion : Things inside a module should belong together


●​ Coupling : Modules should depend on each other as little as possible
✔ High cohesion

✔ Low coupling

👉 This makes systems:


●​ Easier to understand
●​ Easier to change
●​ Easier to deploy

5. Why the Monolith Fails This Rule

In the spelling-mistake example:

●​ Frontend + backend + database were tightly bound


●​ No separation
●​ One small change affected everything
If the frontend was separately deployable, the change would be:

●​ Clear
●​ Safe
●​ Fast

The Twelve-Factor App


The Twelve-Factor App is a set of best practices for building modern, cloud-ready, and
DevOps-friendly applications. It was created by developers at Heroku after observing patterns
from building and deploying hundreds of real-world applications.

Many of these principles are not new. They reflect ideas from classic software engineering
wisdom, such as The Mythical Man-Month, but adapted to modern environments involving cloud
computing, containers, and Continuous Delivery (CD).

The goal of the Twelve-Factor methodology is to make applications:

●​ Easy to deploy
●​ Easy to scale
●​ Reliable in production
●​ Portable across environments

Factor 1 – Codebase

One source, many environments

An application should have one codebase tracked in a version control system such as Git.
This single codebase can be deployed to multiple environments such as development,
testing, staging, and production.

Having multiple codebases for the same application leads to confusion, duplication, and
errors.

Example: One Git repository deployed as dev, test, and prod with different
configurations.
Factor 2 – Dependencies

Clearly list what the app needs

All application dependencies should be explicitly declared and isolated. The application
must not rely on software being pre-installed on the system.

This ensures that the application behaves the same way everywhere.

Example: Using Maven, npm, pip, or Docker to package dependencies.

Factor 3 – Configuration

Keep settings outside code

Configuration should be stored outside the application code, usually in environment


variables or external configuration files.

This allows the same application binary to be used across environments without
modification.

Example: Database passwords stored as environment variables, not hard-coded.

Factor 4 – Backing Services

Databases/services are replaceable

Backing services such as databases, message queues, or caches should be treated as


attached resources that can be easily replaced.
The application should not assume a specific backing service instance.

Example: Switching from a local database to a cloud database by changing a URL.

Factor 5 – Build, Release, Run

Don’t change code at runtime

The application lifecycle must be divided into three strictly separated stages:

●​ Build: Compile and package the code


●​ Release: Combine build with configuration
●​ Run: Execute the application
Code must never be modified at runtime.

Factor 6 – Processes

No user state inside app

Applications should run as stateless processes. Any data that needs to persist must be
stored in backing services such as databases.

Statelessness enables easy scaling and recovery.

Example: User sessions stored in Redis instead of application memory.


Factor 7 – Port Binding

App exposes itself via a port

Applications should expose their services by binding to a port, rather than relying on
external web servers.

This makes applications self-contained and portable.

Example: A Spring Boot or [Link] app listening on port 8080.

Factor 8 – Concurrency

Scale using multiple processes

Applications should scale by running multiple process instances rather than using complex
threading models.

This approach is simpler and more reliable in distributed systems.

Example: Running multiple Docker containers behind a load balancer.

Factor 9 – Disposability

Apps should start/stop quickly

Applications should start quickly and shut down gracefully. This improves system
robustness and enables fast scaling and recovery.

Processes should be treated as disposable.


Factor 10 – Dev/Prod Parity

Dev and prod should look alike

Development, testing, staging, and production environments should be as similar as


possible.

This reduces bugs that appear only in production.

Example: Using Docker locally and in production.

Factor 11 – Logs

Logs are streams, not files

Logs should be treated as event streams. The application should simply write logs to
standard output.

Log storage and analysis should be handled by the execution environment.

Example: Docker logs collected by ELK stack or cloud logging tools.

Factor 12 – Admin Processes

Run admin jobs like normal apps

Administrative tasks such as database migrations or cleanup jobs should be run as one-off
processes using the same codebase and environment as the application.

This ensures consistency and avoids version mismatch issues.

Example: Running a database migration script using the same Docker image.

👉 All these help fast, safe deployments


Conclusion

The Twelve-Factor App principles strongly support DevOps and Continuous Delivery by
promoting modularity, automation, portability, and reliability. Applications built following these
principles are easier to deploy, scale, monitor, and maintain.

For official documentation, visit: [Link]

7. Three-Tier Architecture

This splits the system into three layers:

1️⃣ Presentation Tier

●​ UI layer
●​ Example: React / Angular
●​ Handles what users see

2️⃣ Logic Tier

●​ Business logic
●​ Example: Java, Python
●​ Processes requests

3️⃣ Data Tier

●​ Database
●​ Example: PostgreSQL

Why DevOps Likes This?

●​ Each layer can be deployed separately


●​ Smaller, safer changes
⚠ But:

●​ If layers are tightly coupled, it becomes a hidden monolith

8. Handling Database Migrations

Databases are different from application binaries because they store both structure (schema)
and data (state).

While application code can usually be stopped, replaced, and restarted, a database cannot be
casually replaced because it contains valuable and persistent data.

Key Points

●​ Database = Structure + State


○​ Structure: tables, columns, constraints
○​ State: actual business data (customers, orders, transactions)
●​ Schema changes = version changes
○​ Each schema modification creates a new database version
○​ Versions must be tracked carefully
●​ Database migration tools
○​ Used to manage schema evolution safely

Common tools:

○​ Liquibase (Java)
○​ Flyway (Java)
○​ Migratus (Clojure)
○​ Alembic (Python)

How Migration Tools Work (Common Pattern)

1.​ A metadata table is added to track schema versions


2.​ Schema changes are written as versioned change sets
3.​ Tool checks which changes are already applied
4.​ Only missing migrations are executed

Rolling Upgrades (Zero / Low Downtime)

●​ Used when downtime is unacceptable


●​ Upgrade database incrementally
●​ Keep schema backward compatible
●​ Upgrade application servers one by one
●​ Remove old schema only after all servers are updated

Liquibase Example (Hello World)

●​ Changelog file defines ordered change sets


●​ Example:
●​ ChangeSet 1 → create table
●​ ChangeSet 2 → add column
Integrated into build using Maven

Supports XML, YAML, JSON, SQL

Suitable for CI/CD pipelines

Key Takeaway

●​ Database changes must be planned, versioned, and backward-compatible


●​ They cannot be treated like normal application updates.

Why You Cannot Just Replace a Database Like an App


Binary

Simple Explanation

When you update an application binary:

●​ You stop the application


●​ Replace the old version with a new one
●​ Start the application again
The application usually works immediately because its state (data) is stored elsewhere,
typically in a database.

A database is fundamentally different.

1. Databases Contain State (Important Data)

An application binary:

●​ Contains only code


●​ Is stateless
A database:

●​ Contains years of business data


●​ Losing or corrupting it can destroy the business
👉 You cannot simply “delete and redeploy” a database.
2. Schema Changes Affect Existing Data

Changing a database schema:

●​ Directly impacts stored data


●​ May break existing applications
●​ Often cannot be reversed easily
Example:

name → first_name + last_name​

If done incorrectly, data can become:

●​ Lost
●​ Misinterpreted
●​ Inconsistent

---

3. Databases Are Shared Resources

●​ Multiple services may depend on the same database


●​ Updating the schema for one service can inadvertently break others
●​ Careful coordination and backward/forward compatibility planning are required

4. Downtime Is Expensive

●​ Stopping a database means:


○​ Entire system outage
○​ User impact
○​ Revenue loss
Hence:

●​ Rolling upgrades
●​ Backward-compatible changes
●​ Careful sequencing
5. Rollback Is Hard

●​ Rolling back app code = easy


●​ Rolling back database changes = risky or impossible
Once data is migrated:

●​ Old structure may no longer exist


●​ Data transformations may not be reversible
An application binary is stateless and replaceable, but a database is stateful and
persistent—therefore database upgrades must be carefully versioned, migrated, and
coordinated rather than simply replaced.

9. Microservices

What are Microservices?

Microservices is an architectural style where an application is built as a collection of small,


independent services. Each service focuses on a single business capability and runs as a
separate process.

●​ Each service has its own codebase and often its own database
●​ Services communicate using lightweight protocols such as HTTP/JSON
●​ Each service can be developed, tested, deployed, and scaled independently

Why DevOps Loves Microservices

Microservices align well with DevOps principles because they reduce coupling and increase
delivery speed.

●​ Faster deployments: Small services mean smaller code changes, enabling frequent
and safer releases.
●​ Smaller failures: A failure in one service usually does not bring down the entire
system.
●​ Easier rollback: Only the affected service needs to be rolled back instead of the
whole application.

⚠ Challenges of Microservices

While microservices offer flexibility, they also introduce operational complexity.

●​ More services → more failures possible: A distributed system has many moving
parts, increasing the chances of network issues, partial failures, and latency problems.
●​ Needs monitoring and automation: Effective logging, monitoring, alerting, and
automated deployment pipelines are essential to manage and operate microservices
reliably.
In practice, microservices succeed only when combined with strong DevOps practices such as
CI/CD, containerization, orchestration, and observability.

10. Conway’s Law (Very Important)

Software structure reflects team structure

Conway’s Law states that the way an organization is structured will inevitably be reflected in the
software systems it builds. Communication paths between teams strongly influence system
architecture.

Example

In a traditional organization, teams are often divided by function:

●​ Database team
●​ Backend team
●​ Frontend team
Because each team works in isolation and communicates through formal handoffs, the resulting
software usually mirrors this separation, leading to a rigid three-tier architecture:

●​ Presentation layer (Frontend)


●​ Business logic layer (Backend)
●​ Data layer (Database)
While this structure is clear, it often causes:

●​ Slow delivery due to inter-team dependencies


●​ Blame shifting instead of shared responsibility
●​ Difficult troubleshooting across layers

DevOps Goal

DevOps challenges this model by promoting cross-functional teams that can deliver features
end-to-end without heavy coordination overhead.

Each team owns:

●​ Code – design, development, and testing


●​ Deployment – CI/CD pipelines and releases
●​ Operations – monitoring, scaling, and incident response
This ownership creates faster feedback loops, better accountability, and more resilient systems.

👉 Microservices architecture fits this model well because each service can be owned,
developed, deployed, and operated by a single team independently.

In short: If you want loosely coupled, scalable systems, you must first build loosely coupled,
well-communicating teams.

11. Service Compatibility (Tolerant Reader Pattern)

Problem

In distributed systems, services are developed and deployed independently. Over time,
requirements change and services must evolve by adding or modifying data fields. This creates
a challenge when different versions of services need to communicate with each other.

If a service consumer expects an exact data structure, even small changes in the response can
cause failures and break compatibility.

Solution: Tolerant Reader Pattern

The Tolerant Reader Pattern solves this problem by making service consumers flexible in how
they read data.

●​ Consumers ignore unknown fields in incoming messages


●​ Consumers only process the fields they actually need
At the same time:

●​ Producers can safely add new fields to responses


●​ Older consumers continue to work without changes

Why This Matters

This approach enables:

●​ Independent service evolution


●​ Backward compatibility
●​ Zero-downtime deployments
●​ Reduced coordination between teams

Best Fit Technologies

This pattern works best with:

●​ REST + JSON
JSON is naturally flexible:

●​ Extra fields can be added without breaking existing clients


●​ Most JSON parsers ignore unknown attributes by default
SOAP Comparison

SOAP services are typically defined using strict schemas (WSDL and XSD). Any change in the
message structure often requires:

●​ Regenerating client code


●​ Coordinated deployments
●​ Versioned endpoints
As a result, SOAP-based systems are:

●​ Stricter
●​ Slower to evolve
●​ Less suitable for rapid, independent service changes
In summary: The Tolerant Reader Pattern allows services to evolve safely by making
consumers flexible, enabling faster development and more resilient distributed systems.

12. Microservices and Databases

Two options:

1.​ Each service has its own database


○​ Better isolation
○​ Easier independent deployment
2.​ Shared database
○​ Easier data modeling
○​ Harder to evolve safely

👉 No single correct answer


13. DevOps, Architecture & Resilience

●​ Speed
●​ Flexibility
But also Challenges:

●​ Monitoring
●​ Health-check APIs
●​ Load balancers
●​ Automation
Example:

●​ If a service fails → remove it automatically

Big Picture Summary

DevOps changes architecture by:

●​ Encouraging modularity
●​ Avoiding monoliths
●​ Making systems easy to deploy
●​ Treating databases as versioned code
●​ Promoting microservices
●​ Emphasizing monitoring and resilience
●​ 👉 Good architecture makes DevOps possible
●​ 👉 Bad architecture makes DevOps painful

You might also like