How to start fast your software project with minimum technical debt

Two weeks ago, my friend Dalia asked me what the best approach is to start new software project. Her friend was starting a new project in a startup. I realized that I could have given much more precise advice. That is the reason behind this post.

The following points are representing the starting points, not hard lines that you must keep. It is a software engineering, so you might modify my recommendation to adapt to your needs. The starting point will help you to find the best path.

Buy first, do not develop

Think what you can buy as-a service. It will be faster and cheaper. 15Euro per months is nothing if you compare it to a cost of having one developer working on it. Examples: github/gitlab, TravisCI (and co) and statuscake, docker repositories, package repositories, google analytics…

That was an important lesson, I have learnt from my CTO in my current company. I have seen how much not following this advice might cost in the past.

Architecture

Briefly:

– loosely couple, if possible, decouple components with message queues
– does not try to force yourself into micro-services (to learn more, check: Martin Fowler post) from the day one

In future, I will write a separate post on this topic.

Development

0. Simple strategy for controlling your source code

Keep the number of repos to minimum. I would always start with one repository. Later, if really, really needed, split into more.

Use a simple git model (aka github model), with short living branches, do not use Git Flow.

1. Use battle-tested and boring technologies

It is consistent with common-knowledge regarding building prototypes and getting the first versions of your software to the client.

I would go with the standard tools: Github/TravisCi and programming languages you know.

If you really want to take a risk. If you explore new technologies, start with ones that you can use immediately in your product. Please, at least time-box your investigation of learning new technology. Every primitive, you build during this time, should be as close as possible to your use case. If you run of our timed box time, cut it immediately :). If things work out, immediately integrate new technology to your product.

2. EVERY COMPONENT must be runnable at your laptop.

With docker-compose, when you can have rabbitmq, mysqldb in seconds on your laptop, you can mock everything.

For example, you can use an NGINX container with generated static files, to mockup even most sophisticated REST endpoints. If you need more, go with python flask.

If it is runnable on your laptop => it is easy to run in CI => it is simple to deploy.

It will also keep in check all the configuration options your software component have.

3. A single point of entry for every project.

Use Makefile with embedded bash, if you do not know where to start. The example tasks: test, test_all, dev_run_locally, dev_stop_locally, deploy, create_config…

Your Makefile and README will be your best documentation for you and your colleagues. In the startups, you will change your working context frequently, so a good starting point and ability to run a component on your laptop will save you a lot of time and reduce stress.

4. Everything related to your component should be in the component repo (deployment, deployment code, …). Period. If you have an external wiki, link to your rst/md files in your source code repository.

Packaging

1. Use Docker as a package format.

No brainer. It will ensure that the local version on your laptop is the same as in development. Building dockerized software forces you to think which configurations options, you really need to expose. It will also keep the configuration files in check.
There is a limited number of configuration options, you can give as environment variables :). So, some of the configurations, you will put inside the docker. Your components will be simpler to operate.

2. Get your docker repository as-a-service.

Infrastructure

1. Go with AWS, deploy directly on virtual machines. Your applications should be running in docker or with docker-compose.

I love the simplicity of kubernetes. I would go with k8s on AWS or hosted solution on Google Cloud later.

2. Use Terraform to instantiate your virtual machines, networks, … I would never go for anything else.

3. Use consul for the service-discovery. If I need to choose what to invest time on the deployment side, I would go always for the service discovery. It makes the rewiring of your components very simple. It will help you to reduce your configuration. The configuration files for your staging and production will be almost the same.

4. Remote execution with ansible. Your components running in docker (with docker-compose/Docker) shall not need too much wiring or the config generation. Keep ansible to minimum. Put the effort to make your software components smarter. All ansible scripts should go to the software component git.

Monitoring

Monitoring and security usually does not get high priority usually. So, we need to choose wisely:

1. Simple monitoring from your user perspective – knowing whether your service is up or down is a good start.

Go with statuscake or similar service.

2. If you are on AWS, the Cloud-watch alarms are simple to setup and give you good feeling whether you services are up.

3. Start with the monitoring what your users’ experience is.

4. Build into your components Prometheus support.

If you do not know which metrics to expose, study prometheus exporters for popular components, such as: traefik, nginx… Read also about USE or RED

5. Push back implementation of any log aggregation. You can go very far with ansible + grep :D.

The effort should go to improve monitoring and expose better metrics from your components.

The log aggregation — ElasticSearch Logstach Kibana, EFK (Fluentd) — is always painful to implement and have very high TCO. If needed, go would go with EFK.

Notice: I do not have enough experience with the log aggregators as-a-service, to discuss whether it is a good idea to use them.

Continuous Integration / Delivery

1. Keep it simple :D. If you CI scripts are getting to big, you must have done sth wrong.

2. Go with TravisCI or another service.

3. Your CI infrastructure code should use the same commands, you use on your local dev. I like Makefile to implement shared commands among environments/machines/humans.

4. Immediately add any automatic step to CI.

Never

You MUST NOT (see rfc2119):

– Develop a join tool for all your components, e.g., shared tooling for deployment
– Use cloudformations
– use puppet or chef  – these are great tools, but encourage bad practices (leaking implementation details into the puppet and chef code). I have spent three years with Chef :D.

Avoid

You SHOULD NOT (see rfc2119):

– use ansible or salt or … to install your components. Use docker as much as possible, keep ansible/salt to bare minimum (e.g., transfer config files, start/restart new docker image).

Might

– If you use message queues to communicate among component, manage the queue, do not go with it as-a-service. It will give you better control when you decide to rewire your components or migrate them to, e.g., kubernetes.

Next

The post just covered the basics. I have marked important aspects that you need to consider when starting work on new software project.

I would love to hear what your experience is or learn about challenges you face in your project. Reach me on LinkedIn, drop in the WeWork office in Berlin for a coffee/beer, or just leave a comment.

Currently, I read DevOps Handbook (it is so much better then the famous Phoenix Project). It is a great food for thoughts and it makes me to review my own experience. There is so much more to look at, when we get time to improve our software development process.

 

wb