A breakdown of eight software engineering areas—from product decisions to production—that become more important as AI agents take on more implementation work.
Adapted from @bibryam# 8 Software Books AI Has Made More Relevant ## AI can now write much of the source code. Which software engineering books still matter? AI can generate a service, its tests, and deployment files. Along the way, it makes decisions about business rules, data, dependencies, and failure handling. Some of those decisions will fit your system. Others will be assumptions that nobody agreed to. This is why I think understanding these eight areas is essential when working with coding agents. The more implementation you delegate, the more you need to recognize which decisions are sound and which need another look. Knowing what good software looks like becomes more valuable when you can generate so much of it. The roadmap below follows those areas from product decisions to production and delivery. These books explain the ideas behind them, even though their foundations predate today’s coding agents. ## Decide what is worth building Escaping the Build Trap challenges the habit of treating shipped features as progress. Melissa Perri’s distinction between outputs and outcomes gives engineers a reason to question a feature before discussing how to build it. The work starts with what should change for the customer or business, followed by evidence that the change happened. (https://www.amazon.com/dp/149197379X) AI makes this distinction harder to ignore. An agent can turn a request into a convincing prototype before anyone knows whether people need it. Once the demo exists, it is tempting to keep improving it. The risk is becoming very efficient at building something nobody asked for, while treating each generated feature as another sign of progress. ## Agree on what correct means Specification by Example addresses a familiar problem: people can agree on a requirement while imagining different behavior. It brings product managers, domain experts, and engineers together to work through concrete cases. “Customers can cancel orders” becomes a discussion about orders already shipped, partial shipments, and payments already collected. (https://www.amazon.com/dp/1617290084) With a coding agent, an unresolved interpretation can become both the implementation and the tests that supposedly verify it. Everything passes because both share the same assumption. Examples agreed independently of the generated code give the agent a reference that can challenge its work. That makes the collaboration behind this book especially relevant, even as the tools for implementing and testing the examples change. ## Make business meaning explicit Learning Domain-Driven Design helps teams turn business knowledge into software models. A ubiquitous language gives people shared terms, while bounded contexts define where a particular meaning applies. Billing and fulfillment can have different rules for an order without forcing both into one model. (https://www.amazon.com/dp/1098100131) An LLM may know the language of your industry without knowing the exceptions inside your organization. When an agent copies code between services with similar schemas, it can carry the wrong business rules with it. Domain terminology, clear boundaries, types, and tests help make those differences visible. They give the agent more useful context than a collection of files whose business meaning it has to guess. ## Choose architectural trade-offs that fit the system Software Architecture: The Hard Parts examines the consequences of splitting systems apart and putting them back together. Service boundaries, coupling, data ownership, and distributed transactions affect one another. A choice that makes deployment easier can make consistency or recovery harder, so the answer depends on the constraints of the system. (https://www.amazon.com/dp/1492086894) Coding agents reduce the effort of creating another service, but the network calls, coordination, and failure modes still come with it. That can make a distributed design look cheaper than it really is. The same problem appears during later changes, when an agent removes a boundary that looks unnecessary locally. Understanding the trade-offs helps explain why that boundary exists and whether a proposed change is actually an improvement. ## Understand your data guarantees Designing Data-Intensive Applications, Second Edition explains the decisions hidden behind database and messaging APIs. Replication, transactions, consistency, ordering, and schema evolution determine what an application can promise its users. Those guarantees matter whenever data is copied, processed, or read while the system is changing. (https://www.amazon.com/dp/1098119061) An agent may change a schema and update every consumer it can see, while older clients, stored events, and derived indexes still depend on the previous structure. The repository can look consistent while the wider system is already incompatible. This is where understanding data systems becomes more important: generating the integration code does not establish which state is authoritative, how fresh it must be, or what happens when an update arrives twice. ## Identify threats and trust boundaries Threat Modeling: Designing for Security provides a structured way to understand what can go wrong in a system. Mapping data flows and trust boundaries, identifying threats, and checking the proposed controls makes security part of the design discussion. It also exposes assumptions about who can access what and which actions they can perform. (https://www.amazon.com/dp/1118809998) A coding agent may read an untrusted README or tool response while also having shell access and credentials. Prompt injection can influence how it uses that authority. The book predates these attacks, so it needs newer security guidance alongside it, but the underlying questions still apply. A prompt can steer the model’s behavior, while enforced permissions limit the actions available when that behavior goes wrong. ## Design for production failures Release It!, Second Edition explains how local problems spread through a running system. Blocked threads, slow dependencies, and mismatched capacity can turn one failure into an outage. Patterns such as timeouts, circuit breakers, bulkheads, and back pressure help contain the damage, provided their behavior fits the system. (https://www.amazon.com/dp/1680502395) An agent asked to fix a failing API call may add a retry loop without noticing that the client library already retries. The code looks more resilient while multiplying requests against a struggling dependency. This is why familiarity with a pattern’s implementation is only part of the job. We also need to understand its assumptions about load, timing, and recovery before accepting the generated fix. ## Improve the whole delivery flow Accelerate looks at the practices and conditions behind effective software delivery. Small batches, continuous integration, deployment automation, loosely coupled architecture, and a culture of learning help changes move safely into production. Throughput and stability belong in the same discussion. (https://www.amazon.com/dp/1942788339) Several coding agents can work in parallel while the team still has one review queue. More generated code can mean more work waiting for review, larger changes, and harder integration. I would judge AI adoption by whether changes reach users sooner and how reliably they run once deployed. Generated lines and accepted suggestions can describe tool usage, but they cannot tell us whether delivery improved. ## Where to start Start with the area where your team has the least clarity. These books are useful because they give you a way to reason about the decisions that generated code can hide. Which software engineering book would you add to this list, and why has AI made it more relevant? Read the full post here https://generativeprogrammer.com/p/8-software-books-ai-has-made-more