One codebase tracked in revision control with many deploys
Like many of today's agencies we have one codebase per project tracked in a revision control systems with many deploys on daily basis.
we use GIT:
https://git-scm.com/
As our code repository of choice and we manage all our repositories through GitHub:
https://github.com/
It is standard for us to use to three environments (local: development | staging: testing | production: live). All three share the same codebase, same operating system, the same back services and the same dependencies.
The codebase will always support these environments with unique configurations.
Explicitly declare and isolate dependencies
Modern software relies heavily on the work of others, it's the very nature of open source technology. You must never assume that external libraries exist on the target system. Rather you should declare all dependencies and state the required versions.
By in large we use Composer:
https://getcomposer.org/
To handle all our dependencies for us. But we have also started to use:
Yarn
When we deploy to a server via Capistrano or Travis, we always ensure the latest dependencies have been installed on the server as part of the deployment process.
Store sensitive config in the environment
You would never want sensitive data such as mysql username and passwords committed to your central code repository! Or you might want different configurations for each environment. It is for this reason we manage configuration items outside of the repository.
Each environment has it's own unique ENV details, that the app running on the server then relies on.
Treat backing services as attached resources
Isolate backing services such as mysql or memcached and store these details in your configuration, that way if the network connection changes you only need to update one location.
For example, your development environment talks to a MySQL server on your local machine. On production it might run on a completely different server, you should only need to update your configuration with the differences for the web application to continue to work as expected.
Again these differences can be stored in the environment.
Strictly separate build and run stages
Build should be different to the release, and the release should be different to the run.
1. The build stage is fully controlled by the developer. It's here that we create new versions, releases, tags and fix bugs.
codebase. + dependencies + assets
2. The release stages prepares the build for execution in the target environment (production | staging).
build + config
3. The run stage then executes the application and shouldn't need any intervention.
execute, no code changes
Automation of this stage will make this simpler for the whole team. GitHub can be used to tag your latest build, whilst Capistrano:
https://capistranorb.com/
And tools like Phinx:
https://phinx.org/
can be used to deploy your codebase to the environment (production | staging) with absolutely no interuption to the service. You further have the ability to rollback deployments in the case of problems.
Execute the app as one or more stateless processes
Stateless apps should degrade gracefully. If one part of the stack fails, then the whole app should not become a failure.
Export services via port binding
You application should be accessible via url, just as your backing services also (MySQL | Memcache):
127.0.0.1:8000 - application 127.0.0.1:3306 - mysql 127.0.0.1:8025 - mailcatcher
By doing so you should be able to run your application though PHP's built in server:
https://secure.php.net/manual/en/features.commandline.webserver.php
This would be useful for local development or for integrating your app into Travis, where as for production or staging environments you would need a more complicated webserver on top.
Scale out via the process model
Each process required to run your application should be able to scale, restart or clone itself when required.
Maximise robustness with fast startup and graceful shutdown
When you deploy new code to staging or production you want the new version to start straight away and deal with the incoming traffic. Similarly after a crash or new deployment your app should have everything it needs to run. Reloading the code should only take a few seconds max... Capistrano/ Travis handles the change of code effortlessly!
Keep development, staging and production as similar as possible
Your development environment should resemble production as close as possible. This means working on the same codebase, operating system, the same back services and the same dependencies. This reduces the amount of bugs and downtime, allowing your organisation to have a much more rapid development cycle.
This is why we all work on a vagrant box, which is provisioned by re-usable Puppet roles/ profiles. This configuration contains all the code to set up a perfect local development environment, and we can then define how our production and staging environment will work at the same time.
It prevents that "It's working on my machine" problem.
Treat logs as event streams
Logging is important for debugging and checking up on the general health of the application. But do you really want your application to be responsible for storage and maintenance of these logs? We make use of external services that help with the archival and analysis.
Examples include:
Run admin/ management tasks as one-off processes
So your application has been running on production for some time, now you need to handle a database migration or fetch data for anaylsis. These `commands` are handled by Smyfony console and ensure that the same commands can be used on any of the environments, even when we are building complex sites on Travis.