29,99 €
Domain-Driven Design (DDD) makes available a set of techniques and patterns that enable domain experts, architects, and developers to work together to decompose complex business problems into a set of well-factored, collaborating, and loosely coupled subsystems.
This practical guide will help you as a developer and architect to put your knowledge to work in order to create elegant software designs that are enjoyable to work with and easy to reason about. You'll begin with an introduction to the concepts of domain-driven design and discover various ways to apply them in real-world scenarios. You'll also appreciate how DDD is extremely relevant when creating cloud native solutions that employ modern techniques such as event-driven microservices and fine-grained architectures. As you advance through the chapters, you'll get acquainted with core DDD’s strategic design concepts such as the ubiquitous language, context maps, bounded contexts, and tactical design elements like aggregates and domain models and events. You'll understand how to apply modern, lightweight modeling techniques such as business value canvas, Wardley mapping, domain storytelling, and event storming, while also learning how to test-drive the system to create solutions that exhibit high degrees of internal quality.
By the end of this software design book, you'll be able to architect, design, and implement robust, resilient, and performant distributed software solutions.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 321
Veröffentlichungsjahr: 2022
Create simple, elegant, and valuable software solutions for complex business problems
Premanand Chandrasekaran
Karthik Krishnan
BIRMINGHAM—MUMBAI
Copyright © 2022 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the authors, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Associate Group Product Manager: Gebin George
Publishing Product Manager: Kushal Dave
Senior Editor: Rohit Singh
Content Development Editor: Kinnari Chohan
Technical Editor: Pradeep Sahu
Copy Editor: Safis Editing
Project Coordinator: Manisha Singh
Proofreader: Safis Editing
Indexer: Sejal Dsilva
Production Designer: Nilesh Mohite
Marketing Coordinator: Sonakshi Bubbar
First published: July 2022
Production reference: 2100822
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.
ISBN 978-1-80056-073-4
www.packt.com
To my mother, Bhanumathy, for all her sacrifices and for exemplifying the power of determination. To my wife, Vidya, for being my loving partner throughout our joint life journey and to our son, Siddharth, for being a constant source of joy and pride.
– Prem
To my late mother, Visalam, and my father, Krishnan, for inculcating the value of hard work and perseverance. To my loving wife, Suja, for being the patient partner and providing a lot of encouragement, and to my daughter, Ananya, for being the source of cheer and happiness in our family.
– Karthik
The ideas behind Domain-driven Design (DDD) have an outsized influence on software architecture and the way we think about software projects. Ubiquitous Language is a term defined by DDD, describing the practice of creating a more precise language when discussing design in software projects. However, DDD itself has provided a ubiquitous language for software architecture: most discussions around microservices touch on terms originating in the DDD world.
However, the book that started it all, Domain-driven Design by Eric Evans, falls into the category of what Mark Twain called a classic: “a book that everyone wants to have read.” The truth of the matter is that, while the book is packed full of influential ideas, it is quite abstract for readers looking for advice on how to build software. That doesn’t indicate a deficiency in the source–it is designed to cover broad concepts, which encompasses many different facets of design, including but not limited to software development.
However, when developers need to utilize these ideas in a practical sense, such as in a concrete project, the abstract doesn’t help–they need a practitioner’s guide, which readers now hold in their hands. This book does an excellent job translating the concepts of DDD into useful overviews and concrete advice on how to implement the ideas. For example, a pertinent question that developers have that is unanswered in the DDD book: which is better to implement a project, imperative or functional programming style? Each has trade-offs; this book helps teams make those kinds of implementation decisions. This book covers multiple perspectives on applying DDD to Java projects, including foundational material about how DDD and agile engineering practices intersect in modern projects.
While many books exist that cover DDD and software architecture independently, this book does an excellent job mapping one to another, describing how the design influence of DDD maps to a number of different architecture topologies. For example, it describes how teams can reconcile bounded contexts with layered and other architecture styles.
Part one of this book covers many foundational details of the book, including technical and design details. Part two covers Real World DDD, covering how to apply the abstract ideas in a more concrete realm. It covers everything from how to discover and document the domain, to how to map real-world concepts into DDD concepts. For example, it does an excellent job describing aggregates, their design, and relationships.
Part three covers a topic dear to my heart as the author of Building Evolutionary Architectures, which is the evolution of software. Software products constantly evolve, including new features and capabilities. Therefore, software development isn’t a static process–it must evolve along multiple dimensions to remain successful. This book contains a number of useful evolution patterns, covering both the domain and architecture characteristics.
Towards the ideal of creating a practitioner’s guide, the book also covers engineering practicalities such as logging, testing, versioning, and a host of other practical considerations. Though these areas may fall outside the scope of the DDD book, teams need them.
DDD offers a host of conceptual ideas but lacks implementation details. This book serves as an excellent bridge between abstract and implementation. While the focus is on Java, the content is broad enough for any practitioner to get a good overview of the many important considerations for DDD projects. In fact, each specific technology stack would benefit from having a practitioner’s guide such as this one.
- Neal Ford
Director/Software Architect / Meme Wrangler
Thoughtworks, Inc.
The early 2000s were a dynamic time in the software industry. A number of luminaries were exploring lightweight “agile” processes that had the effect of converting software engineering from a paint-by-numbers activity into first-class knowledge work. Agile methodologies such as eXtreme Programming were natural extensions of arguments put forth by Jack Reeves in his 1992 C++ Journal article What is Software Design, which claimed that source code – not design docs or architecture diagrams – was the only equivalent to design specifications found in other engineering disciplines. The split between design and manufacturing still exists, of course, but with software, we don’t need people for manufacturing. The compiler does it for us, which means that all work the people do is design work, and agile processes pushed the new generation of software engineers into messy design conversations with “the business.”
The turn of the century also corresponded with the dotcom boom (and subsequent bust) as user interactions shifted from desktop applications to the web, creating technical scaling problems that were orders of magnitude beyond what the industry had faced up to that point. Distributed technologies weren’t exactly new, but the ever-increasing technical complexity needed to solve problems of scale required new architectural approaches and created a demand for software engineering talent.
It was in that environment that Eric Evans published his famous “blue book,” introducing the concept of Domain-driven Design (DDD) in 2003. In it, Evans gave us a set of techniques that directly mapped the design aspects of software development onto the way we wrote source code and patterns that helped us manage technical complexity at scale.
It is precisely because DDD has aged so well that we forget how much the world has changed since it was first published. User behavior changes triggered by the introduction of smartphones pushed organizations to externalize integration interfaces that had previously been hidden inside an internal network, previously accessed perhaps by a public website hosted in a DMZ, but not by external users directly. Continuous delivery accelerated the pace of software change and, as a consequence, the pace of the design process. Microservices and modern event-driven architectures created architectural patterns that enabled more software design activities to happen in parallel as organizations looked to scale the throughput of delivery. Prem and Karthik have been on the leading edge of many of these changes, well-networked in the innovation crucible of Thoughtworks that helped name and evangelize some of these techniques, and directly applying them in large organizations eager to modernize.
DDD remains as relevant today as it did when Evans published his blue book because it directly confronts the root causes of why software design is hard: creating a shared understanding of the problem and modularizing the architecture in a way that communicates that understanding in code. Karthik and Prem share important updates on both fronts: techniques like Wardley mapping, EventStorming, and domain storytelling to create a shared understanding, and an updated view of how DDD patterns apply with modern architectural approaches. This is a book full of lessons learned in the trenches from experienced practitioners, with practical lessons for us all. I’ve personally sharpened my own understanding while reviewing the book, and I’m confident you will too.
- Brandon Byars
Head of Technology, Thoughtworks
Creator of Mountebank
Ever since my first encounter with Domain-Driven Design (DDD) in 2008, I have been convinced that this is how to approach the design of complex systems or systems in complex environments. While DDD gives an excellent foundation, I have found that the combination with Command-Query Responsibility Separation (CQRS) can be even more powerful, albeit challenging to implement.
The library of examples that I started to publish in 2009 evolved into Axon Framework, as early adopters began sharing their experiences using it. One of those early adopters was Prem, using it in a large and complex project at a financial institution.
With the rising popularity of microservices, DDD and CQRS have shown to be essential design principles. Someone once jokingly said: “there are three types of developers implementing microservices. Those who use DDD, those who don’t realize they do, and those who fail.” With the demand for more real-time systems and the rise in popularity of event-driven systems, Event Sourcing also gained more traction. This push for event-driven systems has led to several interesting design techniques that take these events as the very starting point for exploring a system’s behavior.
While I consider the famous Blue Book by Eric Evans a masterpiece that aged very well, it also stays very much in the abstract. Over the years, concepts and practices have been refined and adapted to changes in how we use technology. These concepts and practices are described in numerous resources scattered across the internet, making them hard to find and distill for those venturing into these realms for the first time. Prem and Karthik do an outstanding job of taking you on the journey from the essential concepts of Domain-Driven Design, via the design practices, to the actual implementation of a system. Their complete and pragmatic approach makes this book an excellent starting point for anyone exploring new approaches to complex system design. It’s the book I wish I had when I started my journey.
- Allard Buijze
CTO and Founder of AxonIQ
Creator of Axon Framework
Premanand Chandrasekaran is a technology leader and change agent, with a solid track record of leading large technology teams and helping businesses deliver mission-critical problems while exhibiting high internal and external quality. In the past two decades, he has had the pleasure of helping a variety of clients and domains, including financial services, online retailers, education, and healthcare startups. His specialties include technical innovation, architecture, continuous delivery, agile/iterative transformation, and employee development. When not fiddling with his trusty laptop, he spends time cutting vegetables, cooking, playing video games, and analyzing the nuances of the game of cricket.
“I would like to first and foremost thank my loving and patient wife, Vidya, and son, Siddharth, for their continued support, patience, and encouragement throughout the long process of writing this book. I would also like to thank my colleague and mentor, Gagan Madan, for constantly challenging me, pushing my limits, and inspiring me to achieve greater heights. Finally, my co-author, Karthik – without his perseverance and gentle prodding, it would have been very hard to finish this project. Lastly, my employer, Thoughtworks, for encouraging me to undertake this project and all my fellow Thoughtworkers for being a constant source of inspiration!”
Karthik Krishnan is a technology leader with over 25 years of experience in designing and building large-scale enterprise solutions across financial and retail domains. He has played numerous technical roles in leading product development for major financial institutions. He is currently serving the role of technical principal at Thoughtworks. He is passionate about platform thinking, solution architecture, and application security and strives to be known as a coding architect. His most recent assignment entailed leading a large technology team, helping their clients in their legacy modernization journey with the cloud. When not working, he spends time practicing playing tunes on his musical keyboard.
“I would like to thank my wife, Suja, and daughter, Ananya, for being my pillar of support, providing all the necessary encouragement, and, more importantly, for being very understanding, patient, and accommodating of my long book-writing sessions eating into their weekend plans. This book would not have been possible without them. And I would like to thank my friend, colleague, and co-author, Prem, for providing the energy and bringing in new ideas for discussion and collaborating with me, encouraging healthy debates and discussions throughout the creative process of this book. Lastly, my employer, Thoughtworks, for providing me with the space and encouraging me to write this book, and all my colleagues at Thoughtworks for providing their valuable feedback throughout the course of this book-writing journey.”
Viktor Daróczi is a software engineer and programming enthusiast. His journey as a developer started in the 1990s when he managed to get his hands on a used Commodore 64. From then on, he couldn’t stop and been developing e-commerce platforms, crowd-testing solutions, an IoT platform, and interactive mobile ads, and ended up in fintech at PagoNxt (a Santander company).
Viktor lives in Munich, from where he initiates his explorations of the blue planet in the company of three beloved girls, his wife and two daughters, whom he tends to bore with talking about programming, math, and ancient human languages.
Domain-driven design (DDD) makes available a set of principles, patterns, and techniques that subject-matter experts, architects, developers, and other team members can adopt to work together and decompose complex systems into well-factored, collaborative, and loosely coupled subsystems. When Eric Evans introduced these concepts in the early 2000s, in a lot of ways, these principles were way ahead of their time. We were firmly in the age of the monolith, service-oriented architectures (SOAs) as a concept were just starting to take root, and the cloud, microservices, continuous delivery, and so on didn’t even exist yet! While it was relatively easy to adopt some of its tactical aspects, the strategic side of DDD was still seen as an unjustifiable overhead for the most part.
Fast-forwarding to today, we are building our most complex software solutions ever, with even more complex organization and team structures to cope. Also, the use of the public cloud is almost a given. This has given rise to a situation where distributed teams and applications are almost a norm. Also, we are also in an age where applications from an earlier generation need to be modernized. All this has resulted in the principles of DDD, specifically the strategic elements, gaining a lot of prominence.
We have been practitioners of these concepts and have gained valuable insights from our experiences. Over the years, we have seen a number of advancements that have made the adoption of DDD at scale a viable option. This book is a distillation of all our collective experiences. While we have drawn a lot of inspiration from earlier works on the subject, we have been very conscious to apply a practitioner’s mindset so that we lower the barrier for teams looking to sustain and thrive in their journey of building complex, distributed software.
This book was written with a diverse set of roles and skills in mind. While the concepts of DDD have been in existence for a long time, practical application and scaling have been a challenge, arguably due to a dearth of practical techniques, tools, and real-world examples that bring all these concepts together as a cohesive whole. Successful application of these principles requires strong collaboration from a varied set of roles and disciplines across an organization, including executives, business experts, product owners, business analysts, architects, developers, testers, and operators.
Here is a quick summary of reader personas and what they will gain from reading this book:
Executives and business experts should read this book so that they can articulate their vision and the core concepts that justify the need for the solution. Techniques will allow them to do this in an expedient manner and also gain empathy toward what it takes to implement changes quickly and reliably.
Product owners should read this book so that they can act as effective facilitators when communicating with both business and technical team members, making sure that there is no loss in translation.
Architects should read this book so that they gain an appreciation of the fact that it is of utmost importance to understand the problem before thinking of a solution. They will also gain an appreciation of various architecture patterns and how they play in conjunction with DDD principles.
Developers and testers will be able to put their knowledge to work with this practical guide to create elegant software designs that are easy and pleasant to work with and reason about.
The book provides a hands-on approach to gathering requirements effectively, promoting a shared understanding among all team members in order to implement solutions that will be able to withstand the test of a dynamically evolving business ecosystem.
Chapter 1, The Rationale for Domain-Driven Design, examines how the practice of DDD provides a set of guidelines and techniques to improve the odds of success in our favor. We will look at how Eric Evans’ classic book on the subject from 2003 is extremely relevant today. We will also introduce the elements of strategic and tactical DDD.
Chapter 2, Where and How Does DDD Fit?, examines how DDD compares with several of these architecture styles and how/where it fits in the overall scheme of things when crafting a software solution.
Chapter 3, Understanding the Domain, introduces the sample domain (International Trade) at a fictitious KP bank. We also examine how we can get started with strategic design using techniques like business model canvas, impact maps, and Wardley maps.
Chapter 4, Domain Analysis and Modeling, continues the analysis and modeling of the sample problem domain – Letter of Credit (LC) application, by using techniques like domain storytelling and eventstorming to arrive at a shared understanding of the problem and brainstorm ideas to arrive at a solution.
Chapter 5, Implementing Domain Logic, implements the command-side API for the sample application. We will look at how we can employ an event-driven architecture to build loosely coupled components. We will also look at how to implement structural and business validations and persistence options by contrasting state-stored and event-sourced aggregates.
Chapter 6, Implementing the User Interface – Task-Based, designs the user interace (UI) for the sample application. We will also express expectations of the UI to the service implementation.
Chapter 7, Implementing Queries, dives deeper into how we can construct read-optimized representations of data by listening to domain events. We will also look at persistence options for these read models.
Chapter 8, Implementing Long-Running Workflows, looks at implementing both long-running user operations (sagas) and deadlines. We will also look at how we can keep track of the overall flow using log aggregation and distributed tracing. We will round off by looking at when/whether to choose explicit orchestration components of implicit choreography.
Chapter 9, Integrating with External Systems, looks at integrating with other systems and bounded contexts. We will present the various styles of integration and the implications of choosing each of these.
Chapter 10, Beginning the Decomposition Journey, decomposes the command and the query side of the sample-bounded context into distinct components. We will look at the trade-offs involved when making these choices.
Chapter 11, Decomposing into Finer-Grained Components, looks at finer-grained decomposition and the trade-offs involved beyond the technical implications. We will decompose our application into distinct functions and discuss where it might be appropriate to draw the line.
Chapter 12, Beyond Functional Requirements, looks at factors beyond business requirements that can play a significant role in how applications are decomposed. Specifically, we will examine the effect that cross-functional requirements play when applying DDD.
This book is aimed at a wide range of software team member personas. Some amount of prior experience building software solutions is assumed. Code examples in the book use the Java programming language. Familiarity with OO and frameworks such as Spring will be very helpful.
If you are using the digital version of this book, we advise you to type the code yourself or access the code from the book’s GitHub repository (a link is available in the next section). Doing so will help you avoid any potential errors related to the copying and pasting of code.
You can download the example code files for this book from GitHub at https://github.com/PacktPublishing/Domain-Driven-Design-with-Java-A-Practitioner-s-Guide. If there’s an update to the code, it will be updated in the GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
We also provide a PDF file that has color images of the screenshots and diagrams used in this book. You can download it here:
https://packt.link/TwzEB.
There are a number of text conventions used throughout this book.
Code in text: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: “As shown in the event storming artifact, the LC Application aggregate is able to handle ApproveLCApplicationCommand, which results in LCApplicationApprovedEvent.”
A block of code is set as follows:
Tips or Important Notes
Appear like this.
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, email us at [email protected] and mention the book title in the subject of your message.
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata and fill in the form.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Once you’ve read Domain-Driven Design with Java - A Practitioner’s Guide, we’d love to hear your thoughts! Please click here to go straight to the Amazon review page for this book and share your feedback.
Your review is important to us and the tech community and will help us make sure we’re delivering excellent quality content.
While the IT industry prides itself on being at the very bleeding edge of technology, it also oversees a relatively high proportion of projects that fail outright or do not meet their originally intended goals for one reason or another. In Part 1, we will look at the reasons for software projects not achieving their intended objectives and how practicing Domain-Driven Design (DDD) can significantly help improve the odds of achieving success. We will do a quick tour of the main concepts that Eric Evans elaborated on in his seminal book of the same name and examine why/how it is extremely relevant in the age of distributed systems. We will also look at several popular architecture styles and programming paradigms and explore how DDD fits in the scheme of things.
This part contains the following chapters:
Chapter 1, The Rationale for Domain-Driven DesignChapter 2, Where and How Does DDD Fit?The being cannot be termed rational or virtuous, who obeys any authority, but that of reason.
— Mary Wollstonecraft
According to the Project Management Institute’s (PMI’s) Pulse of the Profession report published in February 2020, only 77% of all projects meet their intended goals—and even this is true only in the most mature organizations. For less mature organizations, this number falls to just 56%; that is, approximately one in every two projects does not meet its intended goals. Furthermore, approximately one in every five projects is declared an outright failure. At the same time, we also seem to be embarking on our most ambitious and complex projects.
In this chapter, we will examine the main causes of project failure and look at how applying domain-driven design (DDD) provides a set of guidelines and techniques to improve the odds of success in our favor. While Eric Evans wrote his classic book on the subject way back in 2003, we look at why that work is still extremely relevant in today’s times.
In this chapter, we will cover the following topics:
Understanding why software projects failCharacteristics of modern systems and dealing with complexityIntroduction to DDDReviewing why DDD is relevant todayBy the end of this chapter, you will have gained a basic understanding of DDD and why you should strongly consider applying the tenets of DDD when architecting/implementing modern software applications, especially the more complex ones.
Failure is simply the opportunity to begin again, this time more intelligently.
— Henry Ford
According to the project success report published in the Project Management Journal of the PMI, the following six factors need to be true for a project to be deemed successful:
Table 1.1 – Project success factors
With all of these criteria being applied to assess project success, a large percentage of projects fail for one reason or another. Let’s examine some of the top reasons in more detail.
PMI’s Pulse of the Profession report from 2017 highlights a very stark fact—a vast majority of projects fail due to inaccurate or misinterpreted requirements. It follows that it is impossible to build something that clients can use, they are happy with, and that makes them more effective at their jobs if the wrong thing gets built—even much less for the project to be built on time and within budget.
IT teams, especially in large organizations, are staffed with mono-skilled roles, such as UX designer, developer, tester, architect, business analyst, project manager, product owner, and business sponsor. In a lot of cases, these people are parts of distinct organization units/departments—each with its own set of priorities and motivations. To make matters even worse, the geographical separation between these people only keeps increasing. The need to keep costs down and the recent COVID-19 ecosystem does not help matters either.
Figure 1.1 – Silo mentality and the loss of information fidelity
All this results in a loss in fidelity of information at every stage in the assembly line, which then results in misconceptions, inaccuracies, delays, and eventually failure!
Writing complex software is quite a task. You cannot just hope to sit down and start typing code—although that approach might work in some trivial cases. Before translating business ideas into working software, a thorough understanding of the problem at hand is necessary. For example, it is not possible (or is at least extremely hard) to build credit card software without understanding how credit cards work in the first place. To communicate your understanding of a problem, it is not uncommon to create software models of the problem before writing code. This model or collection of models represents the understanding of the problem and the architecture of the solution.
Efforts to create a perfect model of the problem—one that is accurate in a very broad context—are not dissimilar to the proverbial holy grail quest. Those accountable for producing the architecture can get stuck in analysis paralysis and/or big design upfront, producing artifacts that are one or more of too high level, wishful, gold-plated, buzzword-driven, or disconnected from the real world—while not solving any real business problems. This kind of lock-in can be especially detrimental during the early phases of the project when the knowledge levels of team members are still up and coming. Needless to say, projects adopting such approaches find it hard to reach success consistently.
Tip
For a more comprehensive list of modeling anti-patterns, refer to Scott W. Ambler’s website (http://agilemodeling.com/essays/enterpriseModelingAntiPatterns.htm) and book, Agile Modeling: Effective Practices for eXtreme Programming and the Unified Process, dedicated to the subject.
Agile software delivery methods manifested themselves in the late 90s and early 2000s in response to heavyweight processes collectively known as waterfall. These processes seemed to favor big design upfront and abstract ivory tower thinking based on wishful, ideal-world scenarios. This was based on the premise that thinking things out well in advance ends up saving serious development headaches later on as the project progresses.
In contrast, agile methods seem to favor a much more nimble and iterative approach to software development with a high focus on working software over other artifacts, such as documentation. Most teams these days claim to practice some form of iterative software development. However, with this obsession to claim conformance to a specific family of agile methodologies as opposed to the underlying principles, a lot of teams misconstrue having just enough architecture with having no perceptible architecture. This results in a situation where adding new features or enhancing existing ones takes a lot longer than what it previously used to—which then accelerates the devolution of the solution to become the dreaded big ball of mud (http://www.laputan.org/mud/mud.html#BigBallOfMud).
Mike Cohn popularized the notion of the test pyramid, where he talks about how a large number of unit tests should form the foundation of a sound testing strategy—with numbers decreasing significantly as you move up the pyramid. The rationale here is that as you move up the pyramid, the cost of upkeep goes up copiously while the speed of execution slows down manifold. In reality, though, a lot of teams seem to adopt a strategy that is the exact opposite of this—known as the testing ice cream cone, as depicted here:
Figure 1.2 – Testing strategy: expectation versus reality
The testing ice cream cone is a classic case of what Fred Brooks calls incidental complexity in his seminal paper titled No Silver Bullet—Essence and Accident in Software Engineering (http://worrydream.com/refs/Brooks-NoSilverBullet.pdf). All software has some amount of essential complexity that is inherent to the problem being solved. This is especially true when creating solutions for non-trivial problems. However, incidental or accidental complexity is not directly attributable to the problem itself—but is caused by the limitations of the people involved, their skill levels, the tools, and/or abstractions being used. Not keeping tabs on incidental complexity causes teams to veer away from focusing on the real problems, solving which provide the most value. It naturally follows that such teams minimize their odds of success appreciably.
Financial debt is the act of borrowing money from an outside party to quickly finance the operations of a business—with the promise to repay the principal plus the agreed-upon rate of interest in a timely manner. Under the right circumstances, this can accelerate the growth of a business considerably while allowing the owner to retain ownership, reduced taxes, and lower interest rates. On the other hand, the inability to pay back this debt on time can adversely affect credit rating, result in higher interest rates, cash flow difficulties, and other restrictions.
Technical debt is what results when development teams take arguably suboptimal actions to expedite the delivery of a set of features or projects. For a period of time, just like borrowed money allows you to do things sooner than you could otherwise, technical debt can result in short-term speed. In the long term, however, software teams will have to dedicate a lot more time and effort toward simply managing complexity as opposed to thinking about producing architecturally sound solutions. This can result in a vicious negative cycle, as illustrated in the following diagram:
Figure 1.3 – Technical debt: implications
In a recent McKinsey survey (https://www.mckinsey.com/business-functions/mckinsey-digital/our-insights/tech-debt-reclaiming-tech-equity) sent out to CIOs, around 60% reported that the amount of technical debt increased over the past 3 years. At the same time, over 90% of CIOs allocated less than a fifth of their tech budget toward paying it off. Martin Fowler explores (https://martinfowler.com/articles/is-quality-worth-cost.html#WeAreUsedToATrade-offBetweenQualityAndCost) the deep correlation between high software quality (or the lack thereof) and the ability to enhance software predictably. While carrying a certain amount of technical debt is inevitable and part of doing business, not having a plan to systematically pay off this debt can have significantly detrimental effects on team productivity and the ability to deliver value.
Stakeholders often want software teams to spend the majority (if not all) of their time working on features that provide enhanced functionality. This is understandable given that such features provide the highest ROI. These features are called functional requirements.
Non-functional requirements (also sometimes known as cross-functional requirements), on the other hand, are those aspects of the system that do not affect functionality directly but have a profound effect on the efficacy of those using and maintaining these systems. There are many kinds of NFRs. A partial list of common NFRs is depicted in the following figure:
Figure 1.4 – NFRs
Very rarely do users explicitly request NFRs, but they almost always expect these features to be part of any system they use. Oftentimes, systems may continue to function without NFRs being met, but not without having an adverse impact on the quality of the user experience. For example, the home page of a website that loads in under 1 second under low load and takes upward of 30 seconds under higher loads may not be usable during those times of stress. Needless to say, not treating NFRs with the same amount of rigor as explicit, value-adding functional features can lead to unusable systems—and subsequently failure.
In this section, we examined some common reasons why software projects to fail. Is it possible to improve our odds? Before we do that, let’s look at the nature of modern software systems and how we can deal with the ensuing complexity.