At my new position at Plemi, I want to optimize the continuous integration flow. Last week, I had a pretty interesting conversation with Mathieu Nebra, we discussed about our same quest: best ROI through the development flow. I also had an awesome experience with Antoine Guiral (the man behind twoolr), we shared a “lean startup" friday night around a very interesting project.
In my previous article, I introduced a pragmatic Git flow. A first step in the flow focused on the local environment of the developer. I like to start this post with a personal, yet simple consideration : “the trust in your development team is reflected by your CI flow”.
It’s very reductive but the github flow is a perfect example. It’s composed of only one master stable branch and several feature branches, the production flow is deadly simple. However Github uses Github (dog fooding for the win) and this flow strategically relies on it own awesome feature called pull request. Sadly, I can’t afford to use github everywhere for many -good and bad- reasons. So I tried to set up a flow with a self-hosted git repository coupled to our continuous integration server
Overview of the development flow
- A Developer works on their local git repository in a dedicated feature branch
- He pushes often as he can (min 2 in a day) to the remote feature branch
- The CI builds on every push, merging the trunk and his feature branch
- When a feature is over, the developer merge it back to the trunk
The context and the tools
For the new comer, a quick summary of the tools used in this flow
- Source code management with git
- Branch management is based on the git flow template
- Continuous integration rely on Jenkins
- Code quality rely on Sonar
- I work with PHP, yet the flow can be used in other langage
The flow starts on the developer side
I already wrote on that topic in my previous article. In short, the developer works into a feature branch named against this pattern: "feature.ticketNumber_description". He writes code without worrying about the SCM. Then, he dedicates some time to nicely split his work into several independent commits. If it’s needed, he can rebase his local branch. Finally he pushes the commit pack.
On the continuous integration plateform side
We have two jobs for each repository: one for the develop branch and another one for all feature branches. The feature job is configured to build every branch with the pattern “feature.*”. Jenkins is notified after each push by a git post-receive hook.
Tip: this hook doesn’t start a build, it trigger Jenkins for a SCM polling. In this way Jenkins will start to build only if there is relevant change(s) in the repository. Read the official documentation: “Build by source changes"
I configured Jenkins to merge locally the lastest pushed branch with the develop branch. This allow an early and cheap detection about merge conflicts.
If Jenkins can’t merge automatically, it fails the build and the developer is already aware that he needs to manually merge back the develop branch into his feature branch. He can’t delay this conflict resolution because it blocks the CI process: checkstyle, unit tests and coverage won’t be available to him until he resolves the merge.
This continuous merge process has the huge advantage to avoid the nightmare of a messy merge while your developer responsible of a shitty conflict is unreachable for an undefined period.”
Don’t trust Jenkins too much
I don’t use "push after a successful build" option provided by Jenkins. Basically, This allows you to automate the integration process: if a build is stable it will push the new modification to a remote branch. Yet, it don’t fit our needs since I ask the developer to push everyday. Many features need more than one day to be achieve and I won’t let Jenkins push some kind of work in progress.
Don’t trust a single developer
I don’t rely too much on Jenkins and this is also related to my first quote: I work with a pretty nice team but “I don’t trust a single developer” (and even myself!) about building the perfect git log (i.e. the perfect code) in a one shot. We are all new in the company and we need to practice a little bit more with the processes or the new coding standards for example.
Trust your team
Moreover, when I say: “I don’t trust a single developer”, it’s a way to highlight the code review phase. When a feature is closed, it must be fully reviewed and discussed by a technical leader before being merged into the develop branch. This has 2 majors consequences: First I can’t let Jenkins automatically merge into the develop branch; second, the technical leader is free to make a final rebase of the feature branch before the merge. This ensures a stable and clean develop branch.
Finally, we have to distinct the 2 usages of develop. Jenkins use this branch locally as an integration branch for each feature while the remote branch reflects the lastest stable version ready to be checked by Q&A and then deployed.
What’s next ?Depends on your need, you’re free:
- Everything go to the production.
- You launch some stress test on a staging server and then deploy to prod
- You notify your Q&A and expect a final feedback
At our office Q&A check is “asynchronous”, it can be delayed from 1 to 3 days. That’s why I’m still using the release branch from the git flow template. I freeze develop into release and wait for a Q&A feedback. If it’s a green light, I’ll deploy the release branch.
I customized the git flow for my need, we don’t use the “release” concept because we deploy ASAP each feature. This flow fits perfectly to the AGILE methods. You collect technical metrics sooner and it’s simpler to detect and to fix potential problems on a small iteration. Your project manager/product owner collects user feedbacks sooner, easing the business decisions for the next sprints/features
I mentioned 2 jobs for each repository, one job is limited to the develop branch and serves the code quality purpose, metrics from this job are exported to Sonar
Continuous integration is not a new concept in software development, yet it’s a trending topic in the PHP community. Actually, the PHP development is evolving to a professional step. AGILE processes are spreading the web development world and so the continuous integration becomes a real business need.
This is a short and condensed introduction to the continuous integration in PHP. My next posts will cover deeply some parts. The main purpose of this blog is to provide keywords and concepts to ease your research.
I discovered the test-driven development more than 3 years ago in the symfony 1 documentation. This framework embeds a rudimentary, but efficient, test suite called lime. Frankly the tools don’t matter without the real will to improve your code quality.
The first question for many companies is: how much will it cost?
The long version : how much time/money will I have to spend to get a more reliable product or service? For this wrong paradigm, my answer is a reversed approach: could you estimate precisely the time/money lost without a continuous integration process?
To be honest, for lightweight projects, it’s still possible to evaluate the maintenance cost. But for huge projects using legacy-hard-coupled code, it’s a nightmare.
The customer, the boss or the developers love a bug tracker when it’s empty. The idea behind Test Driven Development (TDD) is to test your application before the release instead of fixing it after. Yes, it’s an extra cost on development estimated to 20% by Hugo Hamon from Sensio.But try to estimate the cost of your maintenance time and compare it. With the classic Blind Development you can’t predict it, since you have no reliable metrics on your application.
Test-driven development and continuous integration come to the rescue and don’t only allow a correct planning, it also reduces the number of “friday’s night emergency fix of the magic bug”. In short, everybody is happy : the customer, the boss, the wife and thus you too.
Unit test, functional test, acceptance test… These are answers which could and must be combined to match your need. Below is a quick summary and a tool kit for each purpose.
If you’re new to TDD or if you have short deadline : focus on unit tests. It’s the first mandatory step for the backend development which will reward you greatly. For php, consider phpUnit which is the actual standard, but keep also an eye on atoum. I believe that Behavior Driven Development should be use for acceptance, yet phpspec, mentioned by @andhos on twitter, offers a different approach : it’s a BDD framework focused on unit testing.
Sometimes you will need to test your whole application and probably by the presentation layer (i.e. almost like an user). Two solutions are available, first “Headless browser emulators” which are fast and reductive test focused on raw http output (See Goutte or Zombie.js). A second option are “Browser controllers” which simulate navigation with advanced js for example; you can use Sahi which replaced the famous Selenium.
To go further, look at Mink. It’s a web acceptance test framework based on the behavior test framework Behat (a port from cucumber in php). Mink provides an abstract layer for the web acceptance test which could be then executed by any tools mentioned above.
Beyond the test, lot of metrics can be collected about your code like cyclomatic complexity, duplicated code, coupled code… Furthermore, code standards should be controlled by a tool rather than an human eye. See Pdepend, phpmd (Mess Detector), phpCPD (duplicated code)…
Testing is one purpose, automating test is another one.
Let me introduce the gentleman called Jenkins (previously called Hudson), an open source java CI server. It’s the standard in this business. Sonar is another CI server, also in java, providing a nicer web GUI than Jenkins and maybe the nicest web GUI on the market for this concern. Finally, 2 new comers, first Travis CI a PaaS solution perfectly plugged with github, it’s a very sexy beta software. Second, mentioned in the comment by Pedro Mata-Mouros, an interesting solution called Cintient. It’s a beta but it seems to provide a cool UI with a minimal setup flow. I have to try it, yet expect a feedback on this blog soon.
For the deployment, only one answer : Capistrano. An unvaluable ruby tool for automated deployment processes.
Last thing, PHP is open-source like all the tools mentioned in this post. Most are hosted on github and provide a pear package. So now, you have no excuse to don’t start right now to improve your developments.
EDIT : thanks to the comments, I’ll added Cintient CI server.