anchor.diff:  
   It is not atypical (though it is changing slowly) to deploy a build which has gone through all of these tests onto a set of deployment environments such as a UAT, pre-production and production environment. We'll look at how you can model these in your deployment pipelines in our next post.
   
  - 
  +
   <div class='row'>
     <%= partial "partials/downloadbanner" %>
   </div>
  
positive.code: 
  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-04.jpg', :alt => 'Pipeline', :title => 'Pipeline' %>
  
  Hopefully, that change didn't feel like the ["How to draw an owl"image] ("http://sethgodin.typepad.com/seths_blog/2014/01/how-to-draw-an-owl.html")!
  
  Since stages run one after another, only if Stage 1 passes does it go to Stage 2 and so on. Also, since jobs run parallelly (assuming agents are available), the two jobs which run tests in Stage 2 can potentially run parallelly and provide quicker feedback than when run serially. Also, if both unit tests and integration tests fail for a changeset, then both parts of that feedback will be available simultaneously (in a single pipeline run). This is different from when they were all run serially as tasks in a single job.
  
  ## More Jobs vs More Pipelines
  
  We did mention earlier that our application was cross-platform. So, let's assume that the functional tests need to be run on three different operating systems - Mac OS X, Windows and Linux. We could start to approach this by adding jobs in Stage 4 and use GoCD's [*resource*]("https://docs.gocd.io/current/introduction/concepts_in_go.html#resources") concept to make sure that the jobs are picked up by [*agents*]("https://docs.gocd.io/current/introduction/concepts_in_go.html#agent") with the right operating system. This will involve running agents on the different operating systems and tagging them with resources "mac", "windows" and "linux". Once that's done, we could setup our pipeline to look like this:
  
  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-05.jpg', :alt => 'Pipeline', :title => 'Pipeline' %>
  
  
negative.code: - An obvious disadvantage here  is the duplication between the three jobs.
  - Another problem is the lack of extensibility of this approach. It is usual practice to run a set of "smoke" tests before running the full set of functional tests - so that any obvious issues in core functionality are found earlier rather than later. It is also possible that functional tests might need to be run in parallel. So, having a job for each OS's functional tests ends up being limiting. The only way to extend within the job would be to add more tasks which run one after the other.
  
  To get around this, we can use GoCD's powerful [pipeline chaining mechanism](https://docs.gocd.io/current/introduction/concepts_in_go.html#pipeline_dependency), where a stage of a pipeline can be setup as a dependency for another pipeline. We can create one pipeline per operating system's functional test. Let's see how that looks:
  
  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-06.jpg', :alt => 'Pipeline', :title => 'Pipeline' %>
  
  