This is the first article in a “Continuous Delivery” series. We’ll start out journey with brief explanation of Continuous Delivery. After short exploration of some of the tools used today, we’ll move towards the flow (from setting up brand new environment and getting the code from the repository to the creation of fully tested and verified distribution). Each section will present different approaches, compare different tools and, finally, provide some hand-on examples. After the flow, we’ll explore changes required in the development life cycle. Finally, we’ll dive into last steps required for the transition from Continuous Integration towards Continuous Delivery and Deployment.
“Legacy code is code without tests” – Michael Feathers
According to Martin Fowler:
Continuous Delivery is a software development discipline where you build software in such a way that the software can be released to production at any time.
You’re doing continuous delivery when:
- Your software is deployable throughout its life-cycle
- Your team prioritizes keeping the software deployable over working on new features
- Anybody can get fast, automated feedback on the production readiness of their systems any time somebody makes a change to them
- You can perform push-button deployments of any version of the software to any environment on demand
There is a certain confusion as to what is the difference between Continuous Deployment, Continuous Delivery and Continuous Integration, so let us start with definitions.
- Continuous Deployment means that every change goes through the pipeline and automatically gets put into production, resulting in many production deployments every day.
- Continuous Delivery just means that you are able to do frequent deployments but may choose not to do it, usually due to businesses preferring a slower rate of deployment. In order to do Continuous Deployment you must be doing Continuous Delivery.
- Continuous Integration usually refers to integrating, building, and testing code within the development environment. Continuous Delivery builds on this, dealing with the final stages required for production deployment.
Each of the points above depend on those below. In order to do Continuous Deployment, one must be able to continuously integrate and deliver.
In order to successfully and efficiently implement Continuous Delivery, new tools need to be adopted. That adoption should be followed by a change in development procedures and workflow.
Some of the commonly used CI tools are Jenkins, Hudson, Travis and Bamboo. Basic principle behind all of them is the detection of changes in the code repository and triggering a set of jobs or tasks.
Both share the same code base and very similar (if not the same) set of features. Both are easy to extend, powerful and free. Their main advantage is in the number of plugins and community support. One can hardly imagine a need that is not already covered by one or more plugins. Jenkins/Hudson can be extended easily. As a downside, such architecture based on plugins comes at a cost of stability. Plugins are of different quality and it is not uncommon for an update to break existing jobs or to provoke unexpected behavior of the system. If one is looking for robust and flexible solution without any cost, Jenkins/Hudson is the best choice.
What is the difference between the two? In 2011, Jenkins forked from Hudson and continued being developed as a OSS (Open Source Project). The decision to fork was made by the creator of Hudson, Kohsuke Kawaguchi. Hudson, continued being under Oracle. In 2012, Oracle formally transferred Hudson to the Eclipse Foundation.
Hudson is oriented more toward enterprise organizations. Additional effort is put to clean the code, stability and performance. On the other hand, Jenkins is more accepted by the community, more vibrant and dynamic. In terms of numbers (commits, new lines of code, plugins…), Jenkins is winning over Hudson.
Jenkins is probably the most popular CI tool. Because of that, finding help and other users is easy.
Bamboo is the product of Atlassian. When compared to Jenkins, Bamboo is sexy. It is easier to use and it looks better. Usability is one of the first differences one would notice. Moreover, it is well-integrated with the rest of Atlassian’s products (JIRA, Confluence, BitBucket, etc).
Major downsides are its price and extensibility. It is the only tool listed in this article that is not free. If one needs to perform some non-common task, it is much more likely that plugin exists only for Jenkins. Same applies to help. Even though Atlassian provides great support, it is not so easy to find other users to talk to or ask for help.
If ease of use or integration with Atlassian products is priority and licensing price is not an obstacle, Bamboo is a great choice.
Main strength of Travis is that it is simple. Unlike Jenkins that allows almost unlimited plugins, creation of innumerable jobs, complicated flows, etc, Travis is based on a single file .travis.ylm that resides in the root of your code. Even though contents of that file can become complicated, in most cases Travis assumes that we’re following certain standards. Use of standards and simplicity is what often leads to a better and more efficient design.
Travis most of the time knows what should be done without any need to explicitly define the flow. For example, if there is the build.gradle file, Travis will understand that it should be compiled, tested, etc. using Gradle. It inspects your code and acts accordingly. One can switch from Ant to Maven to Gradle without making any changes to Travis or the configuration file.
Travis has a strong dependency with GIT. In cases when some other version controls system is used, Travis is not a good option. If, on the other hand, you are using GIT, working with Travis is like forgetting that CI even exists. Whenever the code is pushed to the repo Travis will detect it and act depending on changes in the code (including .travis.ylm). If there is a problem, you will be notified by email. All CI tools, when setup correctly, should work like that. Kind reminder when there is a problem, oblivion when there is none. Travis, brings this to the next level by, in most cases, removing the need to deal with jobs, configurations and other nuances.
Keeping CI configuration (.travis.ylm) as integral part of the code brings advantages. Through that config, you tell it what to do and he does it.
Simplicity comes at a cost. When complicated, non-standard, nobody-heard-of-it-before type of things are needed, Travis tends to be difficult to fight with.
All four tools described in this article are worthy candidates as your CI solution. They are by no means all tools one should have in account. There are many others to explore.
My preferences for Jenkins and Travis over Hudson and Bamboo are based more on details than big differences. One cannot say that any of them is clearly better than the other. It is often a matter of personal choice, type of the project or what we’re used to.
For new projects, Travis is my favorite and I use it extensively. It is the new kid on the block (at least when compared with Jenkins, Hudson and Bamboo). It requires a switch in the approach to the CI setup. At the first look, its simplicity can be confusing. However, soon after the initial shock, Travis proved to be valuable, great, easy and fun to use.
Jenkins, on the other hand, fulfills my “corporate” needs that often require I-wish-this-does-not-exist-but-I-have-to-maintain-it type of tasks. It is a beast on its own. While it does require additional setup, maintenance and administration work, that overhead is compensated with almost limitless possibilities.
The next article Continuous Delivery: CI Tools Setup provides more details into the setup of Jenkins and Travis servers. We are strong believers that everything should be stored in a version control system and that the process must be repeatable. For that, we’ll have to jump into configuration management and explore tools like VirtualBox, Vagrant, Docker and few others.