Sasha

Optimising your Back End Development Workflow

The key to optimising back end development is to eliminate uncertainty and improve reliability, consistency, and flexibility. Version control, automated testing, consistent local development environments, and controlled deployment are the corner stones of an effective workflow.

Version Control

Using git for version control is a no brainer. Its distributed nature and easy merging of feature branches makes managing code a breeze. We usually have two remotes, one for development and one for production (live). Atlassian's BitBucket hosts our development code and our production code goes to the live server (usually the good folks at Pantheon). We develop using separate branches for discrete pieces of functionality, according to Jeff Kreeftmeijer's excellent post on Gitflow workflow.

Automated Testing

Continuous Integration is critical in any kind of back end development workflow. It saves a huge amount of time with testing as you can push your code changes to a repository and a continuous integration service (we use Jenkins) will detect this, build a version of the website using that latest commit, copy in the live database and run your test suite (Codeception in our case) on the freshly built site.

Development setup for our projects includes these elements:

  • Pantheon - production hosting for the project. It includes the master branch git repository.
  • BitBucket - here we host all feature branches.
  • CI server - Jenkins server which is listening for changes in our BitBucket features repository. If we push new changes to BitBucket, Jenkins will create a new website build on the Build Server.
  • Build Server - server to place website feature builds on to run the test suite.
  • Local Environment - a developer's computer where the coding takes place.

Consistent local development environments

Every developer has their own preference when it comes to their local development environment. This often differs from that of the production environment. In order to ensure the consistency and reliability of output between developers and their different computers and operating systems with the production environment, it's important to implement a unified development environment. To do this we run a custom Vagrant environment on every computer. Vagrant creates a Virtual Box instance with a LEMP (Linux, nginx, MySQL, PHP) stack in it with exactly the same settings we use on a production server. So it doesn't matter what kind of operating system our developers use, their development environment will work in exactly the same way. That is why we don't have situations like "...it works on my local, but it doesn't work on production...I don't know why...". 

Tying it all together with controlled deployment

Step 0: We setup our local Vagrant environment and pull the latest code and database from the production site.

Step 1: We push our changes from our local Vagrant environment to BitBucket into a specific feature branch:

Step 2: A Git hook on BitBucket triggers Jenkins and it creates a new website build on the Build Server using the code from BitBucket feature branch and the database from Production. During the build, Jenkins will change users' emails and passwords so we will be able to test email related functionality without spamming real users.

Step 3: Jenkins triggers our Codeception test suite on the latest build. When the test suite is completed we can see the report:

Every report includes human-readable output and clickable screenshots of any failed tests that are also emailed to us. When the tests fail, we fix the issues on our local environment and push again to the BitBucket feature branch until the test suite completes without failure.

If everything is fine we can merge the new feature branch into the master branch on our local environment and push it to Pantheon ready for testing and deployment. The code should also be able to implement any database updates required to deploy the new feature. 

Step 4: Deployment is handled using Pantheon's deployment workflow to move code from a test environment to the live environment and run any updates automatically after backups are captured of the production site.

 

This approach gives us painless deployment, stable software, and happy clients and developers. It works well for any number of developers and for any number of features. It might look complex at first glance, but the effort is absolutely worth it.

More blog posts by Sasha Varganov

In this post we will talk about how to setup Acceptance testing using Codeception + PhantomJS + Webception.