Representing status by repository location is a poor substitute for metadata

In many organisations a Production release cannot occur until a series of QA criteria have been met (e.g. successful acceptance tests, signed off exploratory testing), and a Continuous Delivery pipeline modelling such a value stream should implement corresponding safeguards.

One potential strategy is to move a binary within the binary repository according to current status. When a binary successfully completes a stage, its repository location is updated so that it becomes accessible to later stages and inaccessible to earlier stages. If the binary repository of a pipeline is implemented by a feature-rich repository manager such as Artifactory or Nexus, this can be implemented by moving a binary between artifact repositories within the repository manager.

In the above binary repository, a binary is initially committed to a QA-facing location for Acceptance and UAT stages. When a binary is signed-off by QA, it is moved to a production-facing location and becomes available for a Production release.

This solution can prove successful, but it can also introduce a number of issues:

  • Opaque implementation. Code clarity may be impaired by binary location rules necessarily being shared between stages.
  • Inflexible architecture. Value stream changes can be costly – for example, adding a new sign-off process might require the creation of yet another artifact repository if a repository manager is in use.
  • No ubiquitous language. A Release Manager is likely to speak of “releasing a tested application version” rather than “releasing from the Production Candidates pool of binaries”.
  • Lack of metrics. Pipeline activity data is limited to location modification timestamp, meaning the only available metric is Production sign-off date.
  • Reduced feedback. An unknown binary will be reported as “not found”, yet the suppressed root cause could be an invalid version, a binary still traversing an earlier stage, or a binary that has failed an earlier stage.

An improved solution would be to establish binary status as a first-class concept in the pipeline and introduce per-binary metadata support.

In this repository each binary is stored in an immutable location, with its associated metadata updated as it progresses through the pipeline. This simplifies the pipeline architecture and dramatically improves the quality of feedback.

Metadata increases feedback and ensures value stream integrity

In Continuous Delivery, Dave Farley and Jez Humble describe the Lean production principles that underpin Continuous Delivery, and how a pipeline encapsulates a value stream - the journey a customer feature undertakes from discovery to real world consumption.

In a pipeline each stage represents a step in the value stream, meaning that for application XYZ an example value stream of [Development -> Acceptance -> UAT -> Performance -> Production] could be defined as follows:

Pipeline with Metadata

In the above pipeline, each stage ends with a discrete piece of metadata (“created XYZ 2.1″, “XYZ 2.1 passed acceptance tests”, etc.) being written back to the binary repository, indicating that one or more new customer features have progressed in the value stream.

Unfortunately, pipelines are often constructed without metadata support:

Pipeline without Metadata

In this situation the lack of activity data reduces each stage to a fire-and-forget operation, constraining feedback and unnecessarily exposing the value stream to obtuse, time-consuming errors. For example, QA could mistakenly test new features that have not passed automated regression tests, or Operations could mistakenly release features that have not been signed off.

With metadata the following safeguards can be easily implemented:

  • Check if binary actually exists e.g. “can XYZ 1.2 be retrieved for deploy to Production”
  • Prevent binary re-entering a previous stage e.g. “once XYZ 1.2 has passed or failed Acceptance, the result is final”
  • Ensure binary has successfully passed sufficient dependencies to enter a stage e.g. “XYZ 1.2 can only enter Production once it has successfully passed UAT and Performance”
  • Introduce a manual sign-off process for critical environments e.g. “XYZ 1.2 can only pass UAT when exploratory testing is complete”
  • Visualise pipeline activity e.g. “I can see XYZ 1.2 was successfully released to Production a week ago, and that 1.4 is the next viable candidate as 1.3 failed Acceptance”

These features ensure fast feedback is always available and that the pipeline is an accurate representation of the underlying value stream. An absence of metadata unnecessarily hinders these goals and suggests a failure to understand the core values of Continuous Delivery.

Revision number, build number, and release number should be discrete

Gerald Weinberg once said that “no matter how it looks at first, it’s always a people problem“, and that is certainly true of Continuous Delivery. Most of the challenges associated with building a pipeline are people problems, as by definition a pipeline cross-cuts an entire organisation. Versioning is one such contentious issue, in which discussions can become surprisingly heated – people can become very attached to their versions.

For example, a source code change is committed to version control as “161178″. The build server successfully tests “161178″ and creates build “678″ as a result. At a later date this is released by Operations as release “198.4″. Therefore we have three different version numbers with three different owners:

 

Type Description Origin Owner
Revision number Uniquely identifies a particular change in the version control Auto-generated by version control Development
Build number ? ? ?
Release number Uniquely identifies a particular release to Production Chosen by Operations Operations

 

When this diversity is considered undesirable, one of the following strategies may be suggested:

  • Use revision number as build number i.e. “161178″ is built as “161178″ and released as “198.4″. This eliminates the build number, but uniqueness is lost – the same revision number can be used to create multiple builds on a build server
  • Use revision number as build number and release number i.e. “161178″ is built as “161178″ and released as “161178″. This again eliminates the build number and can appeal to Development. However, as well as the uniqueness problem a release of 161178 is confusing and lacks credibility. When the next release candidate is 161201 not 161179,  the situation becomes even more confusing
  • Use release number within  build number i.e. “161178″ is built as “198.x” and released as “198.x”. This also eliminates the build number and can appeal  to Operations. However, this approach can be just as confusing. Major and minor versions have no relevance pre-Operations, and rooting build numbers in release major versions can easily lead to “198.78″, “198.79″, and “198.80″ release numbers. It is clearly a smell if the first major release  in a 198 workstream is 198.78

Each of the above approaches seek to eliminate the tricky middle ground of build number, yet each is flawed. This is because diversity in version numbers is desirable – like revision number and release number, a build number is a view of the same valuable thing – it represents the unique ID of the application artifact (known as an application binary). Revision number, build number, and release number have different owners and each has its own lifecycle when responding to change.

 

Type Description Origin Responsibility
Revision number Uniquely identifies a particular change in the version control Auto-generated by version control Development
Build number Uniquely identifies an application binary Auto-generated by build server All
Release number Uniquely identifies a particular release Chosen by Operations Operations

 

We therefore need a method of implementing our original versioning strategy, and that is to relabel build numbers as release numbers. This is where Operations can arbitrarily rename application binaries as and when necessary, although the tool used must obey the golden rule of Build Your Binaries Once. Provided that the build server inserts into the manifest both the revision number and the build number this is a repeatable, understandable process that can safely cross-cut an organisation and encourage the development of always-releasable code.

A badly-defined Deployer abstraction impairs Continuous Delivery

As Continuous Delivery patterns are gradually establishing themselves, antipatterns are also surfacing – and a common antipattern is the Deficient Deployer.

When we talk about a Deployer, we are referring to a pipeline task that can be invoked by any post-Commit stage to deliver an application binary to an environment. A Deployer interface should look like:

Deployer#Deploy(Application a, Version v, Environment e)

There are a couple of ways Deficient Deployer can creep into a Deployer implementation:

  • Anemic implementation – this is where the Deployer behaviour is solely specified as ”download binary and copy to environment”, ignoring any one-time operations deemed necessary for a binary to be in a valid state. For example, environment configuration should be filtered into the application binary during deployment, as it is a one-time operation decoupled from the application lifecycle. If this configuration step is omitted from the Deployer, then additional manual effort(s) will be required to make the binary ready for use.
  • Over-specified interface – this is where environment-specific parameters are added to the Deployer interface e.g. Deployer#Deploy(Application a, Version v, Environment e, Server s). The server(s) associated with an environment and their credentials should be treated as an implementation detail of the Deployer via a per-environment server mapping. Application version, and environment are the only consistent mandatory parameters across all environments.

The root cause of the Deficient Deployer seems to be a reluctance to treat deployment scripts as first class citizens.

Our highest priority is to satisfy the customer through early and continuous delivery of valuable software

In November 2011, Dave West argued that “Water-Scrum-Fall is the reality of Agile for most organisations today“. Dave suggested that in many Agile organisations the Agile process in Development (“Scrum”) is constrained by culture and governance in both Business (“Water”) and Operations (“Fall”), and that such an organisation “fails to realise Agile’s business benefits, such as faster time-to-market, increased business value, and improved flexibility and responsiveness“. This can be summarised as:

Agile has transformed software development, but not product development

By definition, software can only generate revenue when it is in Production. However, Dave Farley and Jez Humble assert in Continuous Delivery that such common sense is not common practice in the software industry, saying that ”in most organisations the release of software into Production is a manually intensive, error-prone, and risky process“. The high-cost, high-risk nature of this scenario is the root cause of the low frequency release policy so common in the industry, where stability is favoured over flexibility.

Dave F and Jez go on to argue that such a release policy is inherently expensive, stating that “every week of delay between having an idea and releasing the code that implements it can represent millions of dollars in opportunity costs“. The elapsed time between feature inception and feature delivery is the cycle time of an organisation, and by establishing a regular cadence of Production releases we can reduce cycle time and as a consequence dramatically improve throughput.

Enter Continuous Delivery, which is defined as ”releasing high quality software fast through build, test and deployment automation“, and has been adopted by organisations such as FacebookLMAX, and TheTrainLine to create reliable, repeatable, low-cost delivery mechanisms that release software to Production on a weekly or even daily basis. Such significant reductions in cycle time mean that more time can be invested back into product development and revenue growth, while the reduction in batch size provides faster feedback and reduces risk.

This is the value proposition of Continuous Delivery – firstly, “that we now have the tools, patterns and practices to drive down the transaction cost of releasing a change enormously“, and secondly that by fostering closer Development/Operations partnerships (such as DevOps) the artificial boundaries within “Water-Scrum-Fall” organisations can be dismantled.

« Older entries