Software Design Methodologies
Agile is not a software design methodology. It’s actually a project management methodology. It has little to do with software itself, which is why it’s gaining popularity outside of the industry as a means of managing many different kinds of workflows.
Actual Software Design Methodologies are processes that are used to approach software specifications by reducing implementation overhead, sharpening focus, and removing ambiguities in requirements. Some good examples are Behavior-Driven Design, Test-Driven Design, and Domain-Driven Design.
Behavior Driven Design (BDD) is a methodology that is specifically meant to ease the burden of understanding when it comes to user requirements. The term “behavior” is meant to refer to the behavior of the software system itself (as opposed to some Freudian-Jungian gestalt philosophy of getting better code out of software engineers by modifying their behavior – please don’t go whacking devs’ hands with a ruler when they make mistakes).
BDD seeks to define user requirements in the form of “acceptance criteria” that explicitly state the desired behaviors, as opposed to an obtuse bullet-point of nondescript features. The most common BDD practice is “Gherkin”, a style of Agile story writing that uses the formula “Given-When-Then” to describe the expected business logic flow. An example story written in the Gherkin style would be, “Given a user is logged into the website, when that user completes an order, then the order is processed and an order confirmation page is displayed to the user.”
Adopting BDD can help to simplify how engineers and developers approach a software specification. By spelling out direct causal connections between some starting state, an action, and a particular desired outcome, the specification becomes considerably easier to understand and thus to implement. In the above example, the meaning of “the order is processed” itself is not spelled out – it is likely specified in another story or epic for order processing. An implementer can handle this part of the acceptance criteria by calling an empty method named ProcessOrder, to be filled in later. Approaching software specifications this way can reduce back and forth churn with customers, and can also help the software implementer stay focused and not try to account for scenarios that aren’t explicitly laid out.
Test Driven Design (TDD) is exactly what it sounds like: writing tests first, and then making the code pass the tests. The idea is that the test isn’t necessarily supposed to pass on the first try, and the implementer should only ever write just as much code as is needed to make the test pass.
“But,” say some developers, “how will test test compile if the class or method it’s testing hasn’t been written yet?”
The answer is simple: that test should not compile. It’s actually a significant part of the point. An implementer shouldn’t start creating a class – or a method on that class – until they know how it’s intended to be consumed. And to do that, one has to design a test that emulates a consumer. That test won’t compile if the objects it references don’t exist yet, and that’s fine. Once that class or method has been created, the test will compile. The next step is making the test pass. And once that’s done, the development for the feature is done. Combined with BDD, TDD can help create a customer-centered development cycle by always starting and ending with end-user expectations.
Domain Driven Design (DDD) is considerably more complex. It’s a methodology for designing entire software systems by using information and activities surrounding specific scenarios to help inform a software model that’s meant to represent those scenarios. The idea is to research what a user expects to do in a given circumstance, and let that research explicitly define concepts within the software system.
DDD has a lot of components to it: a “Context” which is the scenario or situation to which the design pertains; a “Domain” which is the knowledge and activities associated with that context; a “Model”, which is the software system meant to represent the domain and context; and an established set of specific, immutable definitions called a “ubiquitous language” that must be agreed upon in order to reduce ambiguity about the domain (the goal should be to remove ambiguity, but that only happens when all parties involved actually pay attention which, in practice, is less often than it should be). In larger and more complicated systems, the overall system model may also be broken down into sub-models, each with its own domain, context, and language.
Within DDD, a model is comprised of different types of elements: entities and value-objects. Entities are first-class objects that the model treats as unique, whereas value-objects are non-unique sets of attributes or properties that can be shared by entities. Entities and value-objects don’t necessarily retain status across sub-models: one sub-model’s entities can be treated as value-objects by a different sub-model.
For example, in an online store model, one might expect to see a customer management sub-model and an order management sub-model. In the customer model, a customer would be a top-level entity and each customer would be treated as unique. But in for order management, the orders are unique, and the customer who placed the order would become a value-object on the order itself. The order model might then request information on the ordering customer from the customer model in order to validate users and fill in billing and shipping information. This helps to create bounded contexts between the different models in play, and ensures that a particular sub-model does not venture beyond its particular domain.
These methodologies, and others like them, are just a few of the high-level processes that can be used to approach software specifications. They are sharply focused on the specification aspect of software development, and as such they are not specific coding practices or policies. That’s what a principle is.