How we code to never fail
As we rely on agile software development, we believe software has to be built in a professional way. This mindset brought us to the following rules:
- Automate setup as much as possible to reduce time and costs for new developers or changing environments.
Good programmers are lazy programmers. So we don’t want to repeat the same job every day or even multiple times per day. For this kind of jobs we have our great employees called “Computers”. Yes we know computer is a tool but sometimes we can treat them as our friendly employees. Be kind to computers and write them a very detailed recipes (in any programming language), how to help us at work, be more productive and stay lazy.
- Offer maximum portability for having the availability to move the software to any place at any time.
Today we could deploy on AWS tomorrow we better deploy on DigitalOcean or maybe a service which is much cheaper? And in one year there is another super duper cloud provider which rules the world. We want to be ready to move to the best service in no time. Btw. “portability” is defined as a software quality attribute ISO/IEC9126.
- Use the cloud and modern deployment strategies to avoid administration work.
This is also related to setup automation. We use Continuous Integration and we also have to deploy automatically. We see deployment setup as one of the first steps when starting a software project. Modern Continuous Integration tools like Circle CI, Gitlab, Travis or Jenkins have great support for building and managing docker containers. We use kubernetes to orchestrate those containers on the servers because it is a nice handy tool.
- Get rid of differences between development / staging / production, to minimize unexpected issues.
We all heard the following sentence: “It works on my machine”. Making sure, there are no differences between multiple environments is very important to avoid unexpected bugs after we deploy from one environment to another. Minimizing differences can be ensured with Virtual Machines or the right usage of our lovely Docker. One another thing is data. Data has to be migrated properly. Often missing datasets or different data structure causes bugs. For example copying some of data from production to staging environment or using good data fixtures could sometimes be a very good idea.
- Be ready to scale at any time, without big architecture changes or development works.
You will never know how big your next application will be. To be able to handle million of users on your system you will need to scale fast. This should be a criteria even before you start coding. Using kubernetes properly will make scaling quite easy.
- Monitor applications logs and resources to be informed about issues before your customer does that.
We have to expect bugs in our software. Even if we think we write perfect bug free code. When a doctor is doing an operation he always needs to see inside the body, monitor the pulse, the heart rate etc. That is very similar to making code changes or to implement new functionality. We need some indicators for heart rate and pulse of our software and we need a possibility to always look inside by reading the logs. Use monitoring like prometheus, define rules for your logs, write them, collect them and read them. Mail or slack notification might be also useful.
- Use best practices and contribute to open source projects. We don’t have to reinvent the wheel, we are not alone with our problems.
Before we start code a complex algorithm or write a component, we always should look if there is any implementation done yet. When yes, just use it. For missing features you can just make a pull request or create a for of repository. Developers are kind and want to help each other. This is what open source is all about.
- Implement the “green light” which tells us, if our product is still working as we expect.
Wouldn’t it be awesome if some indicator can tell you, if you broke any function of your software or not? Write tests and run them on your machine and in the CI before you deploy.
Code structure has to be clearly defined and understood inside the team.
- A codebase is defined as a git repository
- One git repository has a file called README.md which describes: What this repository is good for, How to run checks and tests, How to contribute, How to deploy
- Every codebase can be a port of a distributed system and is runnable and deployable as it is.
- When a codebase has to be shared between two or more repositories, we call it a “dependency” and should be managed and versioned by pip, npm, maven, composer or other dependency management tools.
- Define a code style for your codebase and check it every time changes are made to improve readability
Don’t hold any state for your application on the server.
- All state data should be saved in external data stores “Databases” or “File systems” and not on process it is running.
- Only cache can be saved on the machine “RAM” or “File system”
- Administrative commands like DB migrations, running tests, deployment command, should be defined in each codebase.
Keep your Tasks, MRs and commits small
- Small tasks are better understood and motivation is higher to accomplish more tasks per day
- Small MRs are always better reviewed
- Small commits describe your work better.
- Know-How transfer is more precise
- Quality will be improved