The Grumpy Programmer's Guide To Building Testable PHP Applications (2015)
3. Environmental Consistency
When it really comes down to it, building your application in a way that it can be easily tested requires discipline and attention to detail. Lots of it. I tell you this because you have to do a lot of work before you’ve even written a line of code.
Undisciplined developers end up experiencing a large number of problems that are really fixable. If you’ve ever come across the phrase “well, it worked for me on my computer / laptop / slice / EC2 instance” then you will understand what I’m getting at. I’ve uttered those words from time to time when 100% convinced that my environment wasn’t the problem.
What can be done to help out with this problem? If you can do only one thing that is not related to code to help make your applications easier to test (automated or otherwise), make sure that the environment you develop your application in is as similar to the environment where it will be deployed as possible. The only difference between your development environment and your production environment should be the data you are manipulating.
It is increasingly rare to come across an application that is more than just one PHP script that does not rely on other tools. Even look at the simplest programming stack available to us: LAMP, or Linux + Apache + MySQL + PHP. A project I am working on also includes MongoDB, Redis, APC, and Memcached. I’m probably leaving out a few other minor components, but even that list shows how complex a relatively simple application can get. Whatever components you choose to use, it is vitally important you make sure that every environment is using the same one.
The easiest way to accomplish this is to actually separate your development environment from whatever you are doing your development work on. This usually means you have two choices: use virtual machines locally or virtual machines remotely.
My personal preference is to use virtual machines locally. Most modern computers can run a 512MB to 1GB virtual machine image without trouble. In fact, you would be surprised how responsive a 512MB virtual machine is when doing development work, even when running a few extras like MySQL and even Memcached. To do work on a local virtual machine, I feel like you really have two choices: VMWare or Virtualbox
The only real difference between VMWare and Virtualbox is that while VMWare is free, it is not open source like Virtualbox. I prefer to use open source solutions so I go with Virtualbox. Use whatever tool you feel comfortable using, but they both accomplish the same task: letting you run a virtual machine containing the operating system of your choice on your own machine. For both choices there is an abundance of information on how to set things up so you can even locally edit code that is on the virtual machine.
For VMWare folks, the most comprehensive link I could find on setting things up for you to do local development was this blog post about creating a development environment for Drupal using VMWare Fusion and CentOS.
If you go the Virtualbox route I recommend the use of Vagrant, a tool that uses Virtualbox to help you build and distribute virtualized environments. Once you have things configured just right (you can use tools like Chef or Puppet) you can create developer and production instances that can be shared between your team in order to develop and test your application. Why is this such a good approach? You can experiment with your application and simply trash it if you do things like accidentally delete the database or screw up a configuration file for one of the associated components your application relies on.
You don’t have to use Chef and/or Puppet as Vagrant can just use a shell script as part of your provisioning process. Technical reviewer and physicist-turned-machine-language-programmer Joel Perras had this advice to offer me about Vagrant:
· Use RVM to install the latest Ruby (1.9.3 as of right now), and then install Vagrant in its own gemset. This will save you a lot of trouble down the road. I once had to spend 1.5 days debugging a Vagrant install that would basically crash every time it loaded up, and it turned out to be an issue with the Ruby version that the developer was using which was different than the one that I had been testing it on. The irony of that wasn’t lost on us.
· You don’t need to go crazy using Chef/Puppet for provisioning. Vagrant also supports a provisioning method that lets you point it to a shell script that will just be executed, so you can fill that simple text file with a few lines of apt-get foo, and that’ll let you get pretty far without needing the brain twist that is Chef/Puppet.
Now, if you’re not comfortable messing around with virtual machines on your own desktop, a great fall-back option is to do your development work on a remote server. VPS accounts (Virtual Private Server) are great for this, along with using “cloud computing” services like Rackspace orAmazon’s AWS to create remote environments that you can do your work in. My current employer has our development servers running on Amazon’s EC2 service.
For those who are comfortable working from a CLI (Command Line Interface) doing your development work is as easy as connecting to the remote development instance using SSH and then editing code using your choice of editor designed for the CLI (Vim or Emacs, usually). For those not so comfortable working like that, with a little effort you can edit those files remotely if your GUI editor supports connections via SFTP or SSH. I have found that the performance hit from waiting to save those files remotely gets annoying real fast when you have to make all sorts of little changes. I did not find the experience of using TextMate along with ExpanDrive an enjoyable one.
My crankiness about network latency and how certain plugins for editors like Vim and Textmate behave over a network connection aside, you should consider the advantages that the use of virtual machines for development work can give you. Distributing virtual machines configured for the needs of your application is the ultimate in consistency.
We have also witnessed the rise of services like Orchestra and Zend PHP Cloud for those looking for a managed, pre-configured environment to run their PHP applications in. I like these services because they actually help you in terms of consistency. Part of the reason is because they themselves have standardized what version of PHP they will support, what version of MySQL they will support, and other components they offer.
The difference between something like this and services like EC2 or Rackspace is that you can’t really run a version of it in your local development environment. While I really like things like Orchestra and PHP Cloud, you have to be careful not to deviate too far from the versions being offered when setting up your development environment.
Whatever solution you choose, keep in mind the goal: a consistent environment for all locations that your application will exist in.