Response Article: In response to “Startups and Development Methodologies” by s0969755

# Introduction

This article is a response to “Startups and Development Methodologies” by s0969755 [1], which explores aspects of software development in early stage technology start-up companies. The article discusses challenges which face small start-up organisations when attempting to implement best practice methodologies or software engineering techniques which result from the limited resources available to the company, drawing on personal experience and anecdotal data gathered from examining large successful start-ups Google and Facebook.

The author presents the idea that start-ups which eschew a development methodology (or adopt an unstructured, laissez faire approach to development) are likely to suffer from a lack of discipline or rigour in software engineering. The author suggests that such organisations may be prone to making ad-hoc additions or modifications to their software without proper regard to the sustainability of the development, and that this may ultimately undermine the goals of the organisation. The author concludes that the adoption of Agile processes (with some exceptions due to pragmatism, such as working week restrictions) may cause the organisations software development to incur some short term costs, but that in the long term will lead to more sustainable engineering practices.

# I Agree With Most of the Article

I broadly agree with most of the ideas presented in the article, and think that some of the concepts explored would benefit from additional context about the role of software engineering in a technology based start-up environment. By drawing from the ideas presented in the Lean Startup [2] methodology, I will consider what the ultimate purpose of a start-up is and how by working backwards from this, best practice solutions can be derived. In this response I will expound on the ideas presented by the original author, augmenting them by examining software development in the specific context of what separates a start-up from a regular software project, and justifying why Agile and Lean practices are appropriate given these contextual constraints.

Specifically, I intend to examine the increased emphasis on gathering metrics and implementing analytics support in software, and examining the role these metrics play in validated learning, (which may lead to pivots), and consequently how to sustainably develop when aiming for a moving target. Additionally, I will briefly present an argument that a start-up need not diverge from established Agile practices such as the 40-hour week merely as a reaction to its constrained resources; it should instead ruthlessly focus on how to meet its current in the most effective (i.e., globally efficient) manner possible. Similarly to the author of the original article, I will conclude that automated testing, continuous deployment and a disciplined approach to development is crucial to give a technology based start-up the best chance of success.

# What Is A Start-Up?

A start-up, as defined by Steve Blank [3], is a “temporary organisation designed to search for a repeatable and scalable business model”. This is a useful definition as it illustrates that a start-up is not simply a small version of a large and established company, it is instead a transient state an organisation goes through when attempting to determine what the organisation is going to do (i.e., what value or service will it provide and monetize). The Lean Startup is a methodology advocated by Eric Ries for helping a start-up organisation to reduce risk by increasing the rate at which the search for a business model can progress, by emphasising the principles of rapid iteration cycles, minimum viable products and “validated learning”.

For technology companies, this will typically result in engagement with potential customers in the marketplace, which will result in the formation of hypotheses about problems these customers face and what viable solutions may be. The organisation will then engage in rapid development of prototypes designed to prove or disprove the hypothesis. Depending on the result, the hypothesis may be reformulated or refined (or discarded entirely) to optimise the produce for different categories of customer engagement. These types of engagement may include activation (did the customer use the product long enough to sign up for an account, or some similar definition?), retention (did the customer come back to the product the next hour/day/week?), virality (did the customer directly or indirectly refer another customer?) or monetization (did the customer pay us?). Depending on the performance of the product in these key metrics, the organisation may choose to persist (further develop the original hypothesis and product) or pivot (change the initial hypothesis in response to lessons learned). The decision to pivot may necessarily result in substantial changes to the implementation of the software.

# Special Requirements For Software Development In A Start-Up

The author of the original article describes the requirement for short release cycles and the frequent phenomenon of changing requirements, but does not go into detail explaining what the purpose of short release cycles are or why rapid requirement changes occur (and the technical implications of both of these). This section will consider in more detail the special requirements placed on the software engineering team in a technology start-up.

It follows from the previous section that the software in a start-up must be developed with a focus on implementing mechanisms for collecting metrics on customer behaviour such that conclusions can be drawn on the hypothesis. The software should ideally be delivered to customers in a format such that it can be rapidly modified and redeployed in response to lessons learned from the metrics gathered. The software should be engineered to be flexible and malleable, such that in the highly likely event of software changes necessitated by either a decision to pivot or persist, the software architecture does not present an unreasonable burden to change.

The implication from these constraints is that the robustness of both the deployment infrastructure and the metrics gathering software is critical. The longer the cycle of forming a hypothesis, implementing the software, gathering metrics from customers, and analysing the metrics to draw conclusions on the hypothesis is, the riskier for the startup. It is then paramount that the deployment infrastructure should not present any unnecessary delay in delivering new iterations of the product to customers. The ideal platform to satisfy this requirement is the web, as new versions of the application can be deployed instantaneously. Rapid deployment of mobile applications is also possible, although with some potential delays potentially imposed by the vendor (such as the iOS App Store acceptance process). A worse case scenario for application of the Lean methodology would be where this is a natural barrier to rapid development cycles, such as the software being delivered on a physical media or embedded device,  due to inherently longer iteration cycles.

Irrespective of the target platform or environment, the method of delivery must be robust and reliable due to the emphasis on short release cycles; this implies a hard requirement for solid engineering in the deployment process, and resources expended here (in terms of automated testing, paired programming, etc.) to ensure a solid foundation will likely be repaid with interest over the lifetime of the start-up.

In addition to a requirement for a solid deployment infrastructure, it is critical that metrics gathering mechanisms be reliable. The gathering of metrics from the usage of the produce forms a crucial component of hypothesise-build-learn iteration cycle, which is the backbone of the Lean methodology. If the mechanism for collecting metrics is not reliably, the team cannot have faith in the lessons they have learned from an implementation of a product iteration. Similarly to the deployment infrastructure, this suggests placing a high priority on expending the resources required to employ software engineering best practices to develop the metrics systems. As well as the requirement for gathering metrics reliably, the organisation must be able to analyse and process these metrics in order to come to the correct conclusion to inform the hypothesis for the next product iteration. This calls for investing resource in the development of robust tooling for metrics analysis.

This section has focussed on constraints that face start-up organisations which do not necessarily affect established organisations as critically. However, start-up organisations are typically resource constrained due to lack of human resources and funding. Therefore it is important to balance these additional requirements to be able to effectively deploy and learn from rapid iteration cycles with the start-up resource scarcity; the next section will consider how a start-up can work to optimise its development given these constraints.

# Organisational And Methodological Considerations For Resource Management

A points in the original article with which I do not necessarily agree is the contention that as a natural consequence of limited resources, a start-up should discard established Agile practice such as paired programming and working week hour limitations. These principles exist because they are considered beneficial to producing software in a sustainable manner, and should not be hastily surrendered if possible. This section considers some methodological measures a start-up can take to make best use of their resources.

As highlighted in the previous section, a start-up depends on its ability to iterate and learn rapidly; these are achieved by a robust deployment infrastructure and metrics gathering and analysis tools. These requirements are potentially expensive to implement and maintain, and typically do not form part of the value proposition of the start-up (assuming the start-up does not, upon recognition of the sophistication of its internal tooling, pivot into becoming a deployment or metrics solutions provider!). In recognition of this, various third party tooling providers exist to fill this niche. Platform As A Service (PAAS) companies such as Heroku can simplify deployment for web based start-ups to free them of the requirement to manage deployment nuances or maintain infrastructure, and metrics services such as Google Analytics, Kontagent, Flurry, etc., can remove the burden of metrics gathering from the start-up, freeing its resources to focus on the problem at hand.

When testing a hypothesis, some system implementation may need to be written. It may seem obvious that only the minimum solution which allows the hypothesis to be tested should be written, but when in the heat of the moment developing software, it can be tempting to build a fully-featured solution, which elegantly and generally solves the problem but may ultimately be wasteful if the hypothesis is proved incorrect. By ruthlessly focussing on implementing the minimal solution required prove or disprove some hypothesis about the product, resources can be most effectively channeled. For example, in a web or mobile start-up, someone may hypothesise that the addition of a feature might increase user engagement in the product. To test this, the feature could be implemented and the resulting user engagement tested. However, a more resource efficient way to test this hypothesis may be to determine some proxy for user engagement, and test for that. A link to the new feature could be added, which does not link to the feature itself but instead allows the user to sign-up to be informed when the feature is added. By measuring the number of clicks and sign-ups, the potential engagement of the feature can be determined and the hypothesis tested for a low cost. If the feature appears to be engaging, it may then be implemented, but if not then the time saved may be significant.

In addition to writing as few features as possible to validate a hypothesis, other constraints such as targeting a single platform may be appropriate. For example, a mobile application may elect to only target iOS rather than Android (for example); this is a valid strategy, as the purpose of a start-up is to search for a scalable business model. Scaling the implementation to multiple platforms should not be attempted until the business case for the product is validated.

When developing features, it may be beneficial to use as high a level language as possible (with respect to any established performance constraints). This will likely allow the most rapid iteration, which is crucial for the start-up. Even considering performance concerns such as scalability, it may still be a better idea to develop with a high level language; again, this is due to the nature of the start-up as a mechanism for searching for a scalable business model, not a scalable technical solution. When scaling technically is required, this is a very string indication that the start-up has validated its business model! As the author of the original article observes, this may have maintenance implications for the software team when the company has become established, such as Facebook’s problems scaling PHP and Twitter’s well publicised switch to the JVM after proving its business model on Ruby [5].

By taking advantage of existing tooling where available to make the best use of limited development resources, the start-up software engineering team will iteratively build towards a complete implementation of a solution. As the author of the original article suggests, this may result in an accumulation of partial implementations, or hacked in features. It is important to keep on top of this technical debt as it accumulates. This can be achieved by using standard refactoring [4] techniques, relying on automated tests to ensure that the implementation remains functional as it is refactored; this may be especially required if the implementation is created in a high level dynamic language amenable to rapid prototyping.

By a combination of leveraging existing tools and solutions where possible, by only implementing the minimum amount of features necessary to prove or disprove a hypothesis, and by selecting an appropriate language and target environment amenable to rapid iteration, a start-up team ensure that the cost of development is minimised. By doing so, it can then invest the resources it has in best established Agile software engineering best-practices such as paired programming and the 40-hour week; this has other benefits, such as building a team of generalists who have a shared ownership of the software, and promoting sustainable development.

# Conclusion

In this article I have presented various ideas and concepts which I feel help to augment the discussion presented in the “Startups and Development Methodologies” by s0969755 [1]. By considering the purpose of a start-up organisation, I have examined the specific requirements for a start-up which differentiates it from an ordinary organisation; a technical start-up must equip itself with the tools to rapidly experiment, iterate and learn. I have explored the strategies by which a start-up can make the most effective use of its limited resources, and in doing so disagree with the author of the original article on the specific contention that it is necessary to discard Agile best practices such as the 40-hour working week. Instead, by adopting a methodology such as Lean [2] which advocates a ruthless and disciplined focus on reducing risk by rapid iteration, and by best exploiting available tools and existing solutions, a start-up can optimise the use of its constrained resources.

# References

[1] s0969755. “Startups and Development Methodologies”, SAPM Blog. URL: http://blog.inf.ed.ac.uk/sapm/2014/02/14/startups-and-development-methodologies/ (Last checked 22/2/2014)

[2] Ries, Eric. The lean startup: How today’s entrepreneurs use continuous innovation to create radically successful businesses. Random House LLC, 2011.

[3] Blank, Steve. “Search versus execute.” URL: http://steveblank.com/2012/03/05/search-versus-execute/ (Last checked 22/2/2014)

[4] Fowler, Martin. “Refactoring: improving the design of existing code.” Addison-Wesley Professional, 1999.

[5] Venners, Bill. “Twitter on Scala.” URL: https://www.artima.com/scalazine/articles/twitter_on_scala.html (Last cheched 22/2/2014)

/* DELETE THIS COMMENT */

Among software engineers, the deletion of code is a celebrated act, as it typically represents the discovery of a more elegant expression of a solution. Famous anecdotes exist about the engineer who confounded his managers by reporting his productivity as “-2000 lines” (Bill Atkinson of Apple, Inc), as well quotes such as that attributed to Ken Thompson of Bell Labs, “One of my most productive days was throwing away 1000 lines of code”. Removing code typically represents refactoring an existing solution to reduce unnecessary complexity, duplication, or other manifestations of software-bloat. Deleting code removes an opportunity for confusion, and the fastest executing code is that which does not exist. Removing code is indeed a pleasure, earned as the reward for diligent refactoring, or intelligently removing complexity. I contend that deleting comments (or otherwise avoiding having to write them in the first place) can be similarly rewarding.

Drawing from a combination of the writings of various computer scientists and software engineers on this topic, as well as my own personal experience, I will explore what drives us to comment code and argue that in many cases comments may represent an opportunity for misleading the reader, or that writing a comment potentially represents a failure to refactor for clarity or to enforce invariants by design.

I will aim to convince that in many cases, comments can and should be omitted in favour of self-documenting code which enforces its invariants by design, and that comments represent an opportunity to introduce redundancy and repetition into the codebase. I will conclude that comments should be avoided wherever possible by refactoring code, introducing automated tests as executable documentation (or by providing some other form of executable API samples), while conceding that some comments may remain necessary (such as when a third party dependency is known to be defective resulting in strange usage) and considering how best to handle these cases.

# Why do we write comments?

The basic argument for writing comments is that source code serves the dual purpose of generating an executable program via a compiler or interpreter, and as a means of conveying the program to human readers (i.e., other software engineers). The source code represents the current state of the behaviour of program; it is the construction-site on which all software engineers will work. As on a larger software team, it is unlikely that all software engineers are likely to be familiar with all aspects of the source code, and will therefore need to be able to read, understand and modify source code that they have not written. Source code is likely to be read far more than it is written (as it will be read by potentially many engineers who did not write it); therefore any steps that can be taken to increase the understandability of source code for its human readers will likely pay off over the long term. The argument is that by writing high level natural language comments describing the intent behind a module, class or method, the source code is then more easily digestible for humans (and the compiler or interpreter is ambivalent).

The received wisdom is that there is a hierarchy of quality of comments, ranging from least useful to most useful. The least useful describe what the code does, essentially augmenting the source code with its natural language description, such as;

++ i; // increment i

This class of comments is considered poor form as it obviously adds little to the comprehensibility of the program; it literally describes what the source code statement does, adding no information.

The next category of comments, considered somewhat more useful are comments detailing how the code does what it does, which can add some value. Consider the following code listing for computing an approximation of a reciprocal of the square root of a number;

// inverse square root with 1st order approximation of Newton's method
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 );
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) );

The implementation shown above is lifted directly from the Quake 3 source code [2] (with the more colourful comments elided); clearly the comment (which is not present in the original source) adds some contextual information that assists a reader, who may otherwise be confused about what the program is trying to accomplish.

The final category of comments, typically considered the most useful, are comments which describe the why, signalling the higher-level intent behind the augmented code. For example;

// The following code computes the reciprocal of a square root, to a // first order approximation using Newton's method
//
// This method is required for performance reasons for lighting 
// calculations, as 1.f/sqrt(num) is too slow on target 
// hardware on [target hardware, target compiler]
//

This high-level intent is not expressed by the source code implementation itself, so this class of comment adds information to the source code which is otherwise not possible to determine from reading it. Other examples of this category of comment are explanation of why a more complicated algorithm was favoured over a simpler one, or why a specific but non obvious order of operations is required, due to some subtlety.

Of these three categories, instances of the first two are almost always candidates for removal via refactoring, as will be discussed in the following section. This is sometimes the case for the final category also; note that the why categories of comments also carry the additional danger of becoming out of date, but this being impossible to determine from the source code (due to it conveying concepts not expressed in the source code), which can lead developers to introduce defects based on misunderstandings caused by misleading comments. This is because source code is rarely the authoritative statement for high level decisions unrelated to the code (such as business domain decisions), so including this information in the source code comments is a form of “don’t repeat yourself” ( DRY) failure (as described by  Hunt & Thomas in The Pragmatic Programmer [8]), and carries similar risks to software repetition. This phenomenon, that comments can actual serve to obscure the intent of the source code, is described by Yourdon in Techniques of Program Structure and Design [3]. Several of the lessons in The Elements of Programming Style [6] by Kernighan and Plauger relate to the dangers of comments, expressed by the maxims to “ensure that the code and comments agree”, “don’t comment bad code, rewrite it”, and “don’t echo the code with comments”. The next section of this article will explore the idea that “The proper use of comments is to compensate for our failure to express ourself in code” [1].

# Comments May Represent Failure To Refactor

Consider a system which conveys invariants to API consumers via comments, such as the following method signature;

/*
* Method - UpdateThermostat
*
* Arguments - temperature. This value represents the temperature to 
* set the thermostat to. This value MUST be valid value in degrees 
* Kelvin, where 0.f is absolute zero.
*/
void UpdateThermostat(float temperature);

This comment appears to be useful, as it conveys information which the method signature does not. However, the signature itself could be refactored to enforce its invariants. By refactoring such that a type is introduced to abstract the notion of a temperature, the invariants can be enforced by construction.

class Temperature {
private:
    double valueKelvin;
    Temperature(double value):value(valueKelvin) { }

public:
    static Temperature FromKelvin(double kelvin) { 
        /* validate value in range or throw exception */ 
    }

    static Temperature FromCelcius(double celcius) {
        /* convert to kelvin and call FromKelvin() */ 
    }

    double GetAsKelvin() { return valueKelvin; }
    double GetAsCelcius() { /* convert to celcius and return */ }
};

By using this data type as part of the API, the method signature becomes;

/*
* Method - UpdateThermostat
*
* Arguments - temperature. This value represents the
* temperature to set the thermostat to.
*/
void UpdateThermostat(Temperature temperature);

This method can then rely on the invariants being enforced in the Temperature class, reducing the need to validate the parameter (reducing DRY fail if temperatures are used in multiple places). This method also abstracts the UpdateThermostat method from the underlying data type used to represent the temperature. Crucially, this method no longer needs to state its invariants in a comment header as they are enforced by the type system. This demonstrates that many benefits can be derived by selection of a better design, and the presence of comments is an indicator that a better design choice is available. After the refactoring, the comment header adds no additional information beyond the method signature, and is a candidate for removal.

Another common example of an invariant which is stated via comments is the implicit sequence of valid operations for a class. Consider the following example;

/*
* Class - Database
*
* This class abstracts a database to allow queries to be executed. 
*
* Users MUST call Connect() before executing any queries. It is an
* error to call ExecuteQuery() before connect has been called.
*/
class Database {
    bool Connect(Credentials credentials);
    bool ExecuteQuery(string query);
}

Again, this comment appears to be useful as it adds semantic information which the code API itself does not present to the consumer. However, this comment also represents a failure to refactor the design. The Database class has two responsibilities; connecting to a database, and executing queries. These responsibilities could be separated into their own dedicated classes, which could allow the invariant described in the comment to be enforced by the system design. Consider the following refactoring;

class Database {
    DatabaseConnection Connect(Credentials credentials);
}

class DatabaseConnection {
    bool ExecuteQuery(string query);
}

By extracting the responsibility for performing queries from the type which is responsible for making connections, the system can enforce that it is only possible to perform a query from the result of a connection. By doing so, the system can enforce its invariant that the Connect() method is called prior to calling ExecuteQuery(), by providing access to ExecuteQuery() via the result of a connection.

Refactoring to eliminate comments can be applied at the statement level, as well as at the level of API design and interaction between components. Consider the following code, which exists in the context of some commerce application;

// calculate total cost by applying 20% sales tax rate
result = x + (x * 0.20);

Again, the comment does serve to clarify the intent of the code. However, the code also contains a magic number and non-descriptive variable names. By addressing these other deficiencies, the utility of the comment is reduced.

// calculate total cost by applying 20% sales tax rate
const TaxRate = 0.20;
totalCost = preTaxCost + (preTaxCost * TaxRate);

This can be refactored for further clarity by extracting a method;

// calculate total cost by applying 20% sales tax rate
totalCost = ApplyTaxRate(preTaxCost);

The initial comment now seems absurd in this new context; in addition to stating what is obvious from the code, it also conveys implementation details which may be misleading, should the tax rate change and the ApplyTaxRate method be updated. This illustrates how seemingly innocuous comments can contain DRY (Don’t Repeat Yourself) violations, as the information in the comment can become out of date and stale, such that it no longer conveys the intent of the source code it attempts to describe. As the pithy quote attributed to Ron Jeffries states, “Code never lies, comments sometimes do”. The earlier example from the Quake 3 source would be a good candidate for this simple refactoring, where an appropriate method name could remove the need for the comment to explain the obscure implementation. Writing “exceedingly clear”, verbose code is advocated for by David Heinemeier Hansson in [4]. In Refactoring [7], Fowler captures the essence of refactoring to eliminate comments; “When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous”.

# Avoiding Redundancy – Executable Documentation Via Automation

Given that source code comments may exhibit problems such as redundancy and repetition, it is worth considering what alternatives are available for filling the role that comments play in providing a high level description of program behaviour. A suite of automated unit tests can help convey the intended usage of the components in the program, and integration tests can illustrate the interactions between components. Well named tests which capture usage scenarios can serve the same purpose as comments in describing the invariants of the component under test. A significant benefit of automated tests is that the tests are more likely to be maintained, as the will (hopefully!) fail if aspects of the program change, such as invariants or expected behaviour. Additionally, documenting behaviour through tests requires that the software be designed in a testing-friendly (i.e., loosely coupled and highly cohesive) manner, further clarifying the API and reducing the need for comments as the responsibilities and capabilities of components should be clear. Automated testing therefore represents a good alternative to comments for program documentation to be consumed by software developers working on the project.

To accommodate external consumers of the program who are not primary developers (such as downstream users of a software library), it may be necessary to include comments. For example, a business client may insist on class or method level comment headers. If this is the case, there may be a “natural” canonical source of documentation or specification of the domain rules for the software. Ideally, comments should refer to other canonical documentation sources so as to not introduce repetition. For library consumers, another possible documentation method could be a set of (ideally automatically testable) API examples of the various use cases of the library, which can be used to demonstrate functionality without having to describe the current behaviour in natural language. If these API examples were automatically tested, regressions of API breakages could be detected, whereas a comment or document describing how to use the library to achieve the use case may break silently.

# Comments Are A Useful Crutch And May Sometimes Be Required

This article has presented arguments for the benefits which can be derived for refactoring to remove comments, in terms of software clarity and enforcement of invariants. Automated tests and API examples have been suggested as possible mechanisms to derive similar benefits to comments in terms of providing a higher level description of the software behaviour, with the added benefit that automated tests are inherently self-validating, so should be more resistant to becoming stale and outdated.

Other categories of comments can be potentially be replaced with more appropriate tools. For example, the classic TODO or FIXME comment could be replaced with a bug tracker describing the undesirable behaviour of the current implementation or design, and could be used for tracking possible remedies for the the problem. This has the benefit of integrating a more formal life-cycle for these types of annotations to the source code, such that these defects can be categorised and searched for, resolved or waived, etc. By adopting this approach, the tracking of technical debt can be made more transparent and available to non-technical team members, rather than informally captured as source comments. Similarly, NOTE and BUGFIX comments may represent a failure to use descriptive log messages when committing code to project’s version control software (VCS). Common VCS features such as blame can be used to investigate the history of the source code.

Despite the arguments presented here, it would be remiss to suggest that it is practically possible to remove all source code comments, or that this is even a reasonable or worthwhile goal. Sometimes comments are necessary to explain a strange or unexpected interaction with a third party dependency, such as a workaround for a known defect; sometimes they are required to explain why an obvious and well known algorithm for solving a problem hasn’t been implemented. Perhaps an iterative solution for a naturally recursive problem has been selected due to stack size limitations. These types of comments strive to explain the why, but critically it is a why which is answerable in the domain of the implementation, and expressible solely in the source code, such that there is no risky repetition of business rules.

Agile coach Tim Ottinger states in his short article on the subject [5] that comments are expressing a deficiency in the code, that the code has failed to meet the natural expectation of the reader, and should therefore be considered as “apology notes”. These apologies may be for a failure to refactor to remove problems, for not being able to use a well known algorithm (or for requiring a hand optimisation due to an earlier decision to favour a non-optimal design), or for simply having written hard to understand code. Ideally when reaching for a comment as the tool to solve a problem in your source code, ask if the comment is explaining away a deficiency in your design. Can the solution be implemented in such away that the comment becomes unnecessary? Would renaming variables or extracting methods help clarify intent? Would splitting up a module to better encapsulate its responsibilities help avoid a breakable invariant by design? Is your comment replicating information form a canonical source which may be subject to change? It may be that time pressures or other constraints require that the comment be written, or it may be that the comment really is required to convey information in the domain of the implementation that would otherwise be impossible to ascertain, and which could not be more appropriately conveyed in another medium. When adding these types of comments, consider what would be required to remove the comment, be it a bug-fix from a third party, or redesigning a poor interface and write this in the comment. Then, when the underlying issue is fixed, delete the comment.

# References

[1] Martin, Robert C. “Clean code: a handbook of agile software craftsmanship”. Pearson Education, 2008.

[2] Quake 3 Arena. Source Code Listing. URL: https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/game/q_math.c#L552 (last accessed: 21/02/14)

[3] Yourdon, Edward. “Techniques of program structure and design”. Prentice Hall PTR, 1986.

[4] Hansson, David H. “Clarity over brevity in variable and method names”. URL: http://signalvnoise.com/posts/3250-clarity-over-brevity-in-variable-and-method-names (last accessed: 21/02/14)

[5] Ottinger, Tim. “Apologies In Code”. URL: http://butunclebob.com/ArticleS.TimOttinger.ApologizeIncode (last accessed: 21/02/14)

[6] Kernighan, Brian W., and Phillip James Plauger. “The elements of programming style”. New York: McGraw-Hill, c1978. 1 (1978).

[7] Fowler, Martin. “Refactoring: improving the design of existing code”. Addison-Wesley Professional, 1999.

[8] Hunt, Andrew, and David Thomas. “The pragmatic programmer: from journeyman to master”. Addison-Wesley Professional, 2000.

The Anaemic Domain Model is no Anti-Pattern, it’s a SOLID design

Design Patterns, Anti-Patterns and the Anaemic Domain Model

In the context of Object-Oriented software engineering, a “design pattern” describes a frequently recurring and effective solution to a commonly encountered problem. The utility of formalising and sharing design patterns is to provide a set of “battle-tested” designs as idiomatic solutions for classes of problems, and to increase the shared vocabulary among software engineers working on collaboratively developed software. The term was coined in the seminal book by Gamma et al [5], which named and described a set of common design patterns. The lexicon of design patterns grew from the initial set specified in the book, as the notion gained in popularity [6], [17].

Following the increasing popularity of design patterns as a concept, the idea of “design anti-patterns” entered popular discourse [7][8]. As implied by the name, an anti-pattern is the opposite of a pattern; while it too describes a recurring solution to a commonly encountered problem, the solution is typically dysfunctional or ineffective, and has negative impacts on the “health” of the software (in terms of maintainability, extensibility, robustness, etc.). Anti-patterns serve a similar purpose to patterns; the description of the anti-pattern might illustrate a typical implementation of the anti-pattern, explain the context it generally occurs in, and show how the implementation results in problems for the software.

A potential problem with the concept of a design anti-pattern is that it might discourage critical thought about the applicability of the pattern. A design that may be inappropriate in some contexts may be a sensible decision in others; a solution might be discarded after being recognised as an anti-pattern, even though it would be a good fit for the problem at hand.

I contend that such an anti-pattern is the Anaemic Domain Model (ADM), described by Martin Fowler [1] and Eric Evans [2]. The ADM is considered by these authors as a failure to model a solution in an Object-Oriented manner, instead relying on a procedural design to express business logic. This approach is contrasted with the Rich Domain Model (RDM) [1], [20], in which classes representing domain entities encapsulate all business logic and data. While the ADM may certainly be a poor design choice in some systems, it is not obvious that this is the case for all systems. In this blog post I will consider the arguments against the ADM, and contend that in some scenarios, the ADM appears be an reasonable choice of design, in terms of adherence to the SOLID principles of Object-Oriented design, established by Robert Martin [3], [4]. The SOLID principles are guidelines which seek to balance implementation simplicity, scalability, and robustness. Specifically, by contrasting an ADM design with an RDM design for a hypothetical problem, I will attempt to show that ADM is a better fit for the SOLID principles than the RDM solution. By doing so, I hope to demonstrate a contradiction in the received wisdom with regard to this anti-pattern, and consequently suggest that implementing an ADM is a viable architectural decision.

Why is the Anaemic Domain model considered by some to be an Anti-Pattern?

Fowler [1] and Evans [2] describe an ADM as consisting of a set of  behaviour-free classes containing business data required to model the domain. These classes typically contain little or no validation of the data as conforming to business rules; instead, business logic is implemented by a domain service layer. The domain service layer consists of a set of types and functions which process the domain models as dictated by business rules. The argument against this approach is that the data and methods are divorced, violating a fundamental principle of Object-Oriented design by removing the capability of the domain model to enforce its own invariants. In contrast, while an RDM consists of the same set of types containing necessary business data, the domain logic is also entirely resident on these domain entities, expressed as methods. The RDM then aligns well with the related concepts of encapsulation and information hiding; as Michael L. Scott states in [9], “Encapsulation mechanisms enable the programmer to group data and the subroutines that operate on them together in one place, and to hide irrelevant details from the users of an abstraction”.

In an RDM, the domain service layer is either extremely thin or non-existent [20], and all domain rules are implemented via domain models. The contention is that domain entities in a RDM are then entirely capable of enforcing their invariants, and therefore the system is sound from an Object-Oriented design perspective.

However, the capability of a domain entity to enforce local data constraints is only a single property in a set of desirable qualities in a system; while the ADM sacrifices this ability at the granularity of the individual domain entities, it does so in exchange for greater potential flexibility and maintainability of the overall implementation by allowing the domain logic to be implemented in dedicated classes (and exposed via interfaces). These benefits are particularly significant in statically typed languages such as Java and C# (where class behaviour cannot simply be modified at run-time) for improving the testability of the system by introducing “seams” [10], [11] to remove inappropriate coupling.

A Simple Example

Consider the back end of an e-commerce website in which a customer may purchase items, and offer items for sale to other customers across the globe. Purchasing an item reduces the purchaser’s funds. Consider the implementation of how a customer places a purchase order for an item. The domain rules state that the customer can only place an order if they have enough funds, and the item must be available in region for that customer. In an RDM, a Customer class would represent the domain entity for the customer; it would encapsulate all the attributes for the customer, and present a method such as PurchaseItem(Item item). Like Customer, Item and Order are domain models representing purchasable items and customer orders for items respectively. The implementation of the Customer (in pseudo-C#) might be something like;

/*** BEGIN RDM CODE ***/

class Customer : DomainEntity // Base class providing CRUD operations
{
    // Private data declared here

    public bool IsItemPurchasable(Item item) 
    {
        bool shippable = item.ShipsToRegion(this.Region);
        return this.Funds >= item.Cost && shippable;
    }

    public void PurchaseItem(Item item)
    {
        if(IsItemPurchasable(item))
        {
            Order order = new Order(this, item);
            order.Update();
            this.Funds -= item.Cost;
            this.Update();
        }
    }
}

/*** END RDM CODE ***/

The domain entities here implement the Active Record pattern [17], exposing Create/Read/Update/Delete methods (from a framework/base class) to modify records in the persistence layer (e.g., a database). It can be assumed that the PurchaseItem method is invoked in the context of some externally managed persistence layer transaction (perhaps initiated by the HTTP request handler/controller, which has extracted a Customer and an Item from the request data). The role of the Customer domain entity in this RDM is then to model the business data, implement the business logic operating on that data, construct Order objects for purchases, and interface with the persistence layer via the Active Record methods; the model is Croesus-like in its richness, even in this trivial use case.

The following example demonstrates how the same functionality might be expressed using an ADM, in the same hypothetical context;

/*** BEGIN ADM CODE ***/

class Customer { /* Some public properties */ }
class Item { /* Some public properties */ }

class IsItemPurchasableService : IIsItemPurchasableService
{
    IItemShippingRegionService shipsToRegionService;

    public bool IsItemPurchasable(Customer customer, Item item)
    {
        bool shippable = shipsToRegionService.ShipsToRegion(item);
        return customer.Funds >= item.Cost && shippable;
    }
}

class PurchaseService : IPurchaseService
{
    ICustomerRepository customers;
    IOrderFactory orderFactory;
    IOrderRepository orders;
    IIsItemPurchasableService isItemPurchasableService;

    // constructor initialises references

    public void PurchaseItem(Customer customer, Item item)
    {
        if(isItemPurchasableService.IsItemPurchasable(customer, item))
        {
            Order order = orderFactory.CreateOrder(customer, item);
            orders.Insert(order);
            customer.Balance -= item.Cost;
            customers.Update(customer);
        }
    }
}

/*** END ADM CODE ***/

Contrasting the example with respect to the SOLID Principles

At first glance, the ADM is arguably worse than the RDM; there are more classes involved, and the logic is spread out over two domain services (IPurchaseService and IItemPurchasableService) and a set of application services (IOrderFactory, ICustomerRepository and IOrderRepository) rather than resident in the domain model. The domain model classes no longer have behaviour, but instead just model the business data and allow unconstrained mutation (and therefore lose the ability to enforce their invariants!). Given these apparent weaknesses, how can this architecture possibly be better than the altogether more Object-Orientation compliant RDM?

The reason that the Anaemic Domain Model is the superior choice for this use case follows from consideration of the SOLID principles, and their application to both of the architectures [12]. The ‘S’ refers to the Single Responsibility Principle [13], which suggests that a class should do one thing, and do it well, i.e., a class should implement a single abstraction. The ‘O’ refers to the Open/Closed Principle [14], a similar but subtly different notion that a class should be “open for extension, but closed for modification”; this means that, in so far as possible, classes should be written such that their implementation will not have to change, and that the impact of changes is minimised.

Superficially, the Customer class in the RDM appears to represent the single abstraction of a customer in the domain, but in reality this class is responsible for many things. The customer class models the business data and the business logic as a single abstraction, even though the logic tends to change with higher frequency that the data. The customer also constructs and initialises Order objects as a purchase is made, and contains the domain logic to determine if a customer can make an order. By providing CRUD operations through a base class, the customer domain entity is also bound to the persistence model supported by this base implementation. By enumerating these responsibilities it is clear that even in this trivial example, the RDM Customer entity exhibits a poor separation of concerns.

The ADM, on the other hand, decomposes responsibilities such that each component presents a single abstraction. The domain data is modelled in “plain-old” language data structures [18], while the domain rules and infrastructural concerns (such as persistence and object construction) are encapsulated in their own services (and presented via abstract interfaces). As a consequence, coupling is reduced.

Contrasting the flexibility of the RDM and ADM architectures

Consider scenarios in which the RDM Customer class would have to be modified; a new field might be introduced (or the type of an existing field may need changed), or the Order constructor may require an additional argument, or the domain logic for purchasing an item may become more complex, or an alternative underlying persistence mechanism might be required which is unsupported by the hypothetical DomainEntity base class.

Alternatively, consider scenarios in which the ADM types must change. The domain entities which are responsible for modelling the business data will only need modified in response to a requirements change for the business data. If the domain rules determining if an item is purchasable become more complex (e.g., an item is specified to only be sold to a customer above a certain “trust rating” threshold), only the implementation of IsItemPurchasableService must change, while in the RDM the Customer class would require changing to reflect this complexity. Should the ADM persistence requirements change, different implementations of the repository [17], [19] interfaces can be provided to the PurchaseService by the higher-level application services without requiring any changes whereas in the RDM, a base class change would impact all derived domain entities. Should the Order constructor require another argument, the IOrderFactory [5] implementation may be able to accommodate this change without any impact on the PurchaseService. In the ADM each class has a single responsibility and will only require modification if the specific domain rules (or infrastructural requirements) which concern the class are changed.

Now consider a new business requirement was added to support refunds for purchases with which a customer is unsatisfied. In the RDM, this might be implemented by adding a RefundItem method to the Customer domain entity, given the simplistic argument that domain logic related to the Customer belongs as a member function of the Customer domain entity. However, refunds are largely unrelated to purchases, for which the Customer domain entity is already responsible, further mixing the concerns of this type. It can be observed that in an RDM, domain entity classes can accumulate loosely related business logic, and grow in complexity. In an ADM, the refund mechanism could be implemented by introducing a RefundService class, solely concerned with the domain logic for processing refunds. This class can depend on the narrow set of abstractions (i.e., interfaces of other domain and infrastructural services) required to implement its single concern. The new RefundService can be invoked at high level (in response to some refund request), and this new domain behaviour has been implemented without impacting any of the existing functionality.

In the example, the ADM solves the problem of bundling unrelated concerns into the same module identified in the RDM by taking advantage of the ‘I’ and ‘D’ in SOLID, namely the Interface Segregation Principle [15] and the Dependency Inversion Principle [16]. These principles state that an interface should present a cohesive set of methods, and that these interfaces should be used to compose the application (i.e., the domain service layer in the ADM). The interface segregation principle tends to result in small narrowly focussed interfaces such as our IItemShippingRegionService and IIsItemPurchasableService, as well as abstract repository interfaces; the dependency inversion principle compels us to depend on these interfaces, to decouple the implementation of a service from the details of the implementation of another.

The Anaemic Domain Model better supports Automated Testing

As well as more flexible and malleable application composition, adoption of these principles allows the ADM to extract the indirect benefits over RDM of simpler automated testing; this is because highly cohesive, loosely coupled components which communicate via abstract interfaces and are composed via dependency injection allow for trivial mocking of dependencies. This means that in the ADM it is simple to construct a scenario in an automated test which might be more complicated to construct in an RDM, so the maintainability of the automated tests is improved; the effect of this is that automated testing has a lower cost, so developers will be more inclined to create and maintain tests. To illustrate this, consider the example above, such that unit tests are to be written for the IsItemPurchasable.

The (current) domain rules for an item being purchasable are that the customer has sufficient funds, and is in a region that the item ships to. Consider writing a test that checks that when a customer has sufficient funds but is not in a shipping region for the item, the item is not purchasable. In the RDM this test might be written by constructing a Customer and an Item, configuring the customer to have more funds than the item costs, and configuring the customer region to be outside the regions the item ships to, and asserting that the return value of customer.IsItemPurchasable(item) is false. However, the IsItemPurchasable method depends on the implementation details of the ShipsToRegion method of the Item domain entity. A change to the domain logic in Item might change the result of the test. This is undesirable, as the test should be exclusively testing the logic of the customer’s IsItemPurchasable method; a separate test should cover the specifics of the item’s ShipsToRegion method. As domain logic is expressed in the domain entity, and the concrete domain entity exposes the interface to the domain logic, implementations are tightly coupled such that the effects of changes cascade, which in turn makes automated tests brittle.

The ADM, on the other hand, expresses the IsItemPurchasable domain logic on a dedicated service, which depends on an abstract interface (the ShipsToRegion method of IItemShippingRegionService). A stubbed, mock implementation of IItemShippingRegionService can be provided for this test, which simply always returns false in the ShipsToRegion method. By decoupling the implementations of the domain logic, each module is isolated from the others and is insulated from changes in the implementation of other modules. The practical benefits of this are that a logic change will likely only result in the breakage of tests which were explicitly asserting on the behaviour which has changed, which can be used to validate expectations about the code.

Refactoring the RDM to apply SOLID tends to result in an ADM

A proponent of the RDM architecture might claim that the hypothetical example provided is not representative of an true RDM. It might be suggested that a well implemented Rich Domain Model would not mix persistence concerns with the domain entity, instead using Data Transfer Objects (DTO’s) [18, 17] to interface with the persistence layer. The inclusion of directly invoking the Order constructor might be viewed as constructing a straw man to attack; of course no domain model implementation would bind itself directly to the constructor of another object, using a factory is just common sense [5]! However, this appears to be an argument for applying the SOLID principles to the application level infrastructural services, and disregarding the SOLID principles for domain design. As the hypothetical RDM is refactored to apply the SOLID principles, more granular domain entities could be broken out; the Customer domain entity might be split into CustomerPurchase and CustomerRefund domain models. However, these new domain models may still depend on atomic domain rules which may change independently without otherwise affecting the domain entity, and might be depended on by multiple domain entities; to avoid duplication and coupling, these domain rules could then be further factored out into their own modules and accessed via an abstract interface. The result is that as the hypothetical RDM is refactored to apply the SOLID principles, the architecture tends towards the ADM!

Conclusion

By exploring the implementation of a straightforward example, we have observed that an Anaemic Domain Model better adheres to the SOLID principles than a Rich Domain Model. The benefits of adherence to the SOLID principles in the context of domain design were considered, in terms of both loose coupling and high cohesion and resulting increased flexibility of the architecture; evidence of this flexibility was that testability was improved by being able to trivially provide stubbed test implementations of dependencies. By considering a how the benefits of adherence to the SOLID principles might be gained in the RDM, the refactoring tended to result in an architecture resembling an ADM. If adherence to the SOLID principles is a property of well engineered Object-Oriented programs, and an ADM adheres better to these principles than an RDM, the ADM cannot be an anti-pattern, and should be considered a viable choice of architecture for domain modelling.

References

[1] Fowler, Martin. Anaemic Domain Model. http://www.martinfowler.com/bliki/AnemicDomainModel.html, 2003.

[2] Evans, Eric. Domain-driven design: tackling complexity in the heart of software. Addison-Wesley Professional, 2004.

[3] Martin, Robert C. The Principles of Object-Oriented Design. http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, 2005.

[4] Martin, Robert C. Design principles and design patterns. Object Mentor, 2000: 1-34.

[5] Erich, Gamma, et al. Design patterns: elements of reusable object-oriented software. Addison Wesley Publishing Company, 1994.

[6] Wolfgang, Pree. Design patterns for object-oriented software development. Addison-Wesley, 1994.

[7] Rising, Linda. The patterns handbook: techniques, strategies, and applications. Vol. 13. Cambridge University Press, 1998.

[8] Budgen, David. Software design. Pearson Education, 2003.

[9] Scott, Michael L. Programming language pragmatics. Morgan Kaufmann, 2000.

[10] Hevery, Miško. Writing Testable Code. http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html, Google Testing Blog, 2008.

[11] Osherove, Roy. The Art of Unit Testing: With Examples in. Net. Manning Publications Co., 2009.

[12] Martin, Robert C. Agile software development: principles, patterns, and practices. Prentice Hall PTR, 2003.

[13] Martin, Robert C. SRP: The Single Responsibility Principle. http://www.objectmentor.com/resources/articles/srp.pdf, Object Mentor, 1996.

[14] Martin, Robert C. The Open-Closed Principle. http://www.objectmentor.com/resources/articles/ocp.pdf, Object Mentor, 1996.

[15] Martin, Robert C. The Interface Segregation Principle. http://www.objectmentor.com/resources/articles/isp.pdf, Object Mentor, 1996.

[16] Martin, Robert C. The Dependency Inversion Principle, http://www.objectmentor.com/resources/articles/dip.pdf, Object Mentor, 1996.

[17] Fowler, Martin. Patterns of enterprise application architecture. Addison-Wesley Longman Publishing Co., Inc., 2002.

[18] Fowler, Martin. Data Transfer Object. http://martinfowler.com/eaaCatalog/dataTransferObject.html, Martin Fowler site, 2002.

[19] Fowler, Martin. Repository. http://martinfowler.com/eaaCatalog/repository.html, Martin Fowler site, 2002.

[20] Fowler, Martin. Domain Model. http://martinfowler.com/eaaCatalog/domainModel.html, Martin Fowler site, 2002.