Back-end development is quite an under-specified term. It is often used as a catchall term for everything that happens on the other side of the network, away from the end user’s computer. It encompasses web application programming, database design and administration, system administration and infrastructure management, and every other activity that goes on behind the scenes. For a team of our size, there is a need to simplify these activities. We do that by taking advantage of tools, technologies, and processes.
Automation increases the efficiency of repeatable processes. Therefore we strive to automate any process that can be automated. This includes the mundane tasks in back end development, such as setting up servers, managing packages, deploying applications, backing up databases, etc. The following tools help us automate easily.
- Terraform, for provisioning resources in the cloud.
- Ansible, for automating setup and management of machine configurations.
- GitLab CI, Cloud Build, and other tools for continuous integration, delivery, and deployment.
- Docker, Vagrant, and other development tools for repeatable setup of development environments.
- Good old cron and scripts where it makes sense.
Embracing automation gives us some benefits. We can work faster, onboard new team members quicker, and respond to disasters quickly.
Just enough documentation
Documentation is an essential practice in software development. The right amount of useful documentation can make all stakeholders’ lives easier; too little, and there will be missing information that can be filled only by abandoning the documentation; too much and we have a hard time finding what we need.
At Sprinthubmobile we document just what needs to be documented, which is everything. But we do not do it by writing long scrolls of text in Microsoft Word. Instead we choose the most appropriate form of documentation for each scenario. For example, our automation tools often enable us to declaratively express the desired state of the system rather than procedurally specify actions that get us to the desired state. This declarative configuration is often better for such scenarios, because the code expresses the intent, thus serving as a single source of truth for the system.
We also document requirements extensively in one place, and reference them in any related work.This makes it easier to trace the original intention of each piece of work to its related requirement, say from a Git commit to the original requirement.
Managed services, cloud-first
Managing infrastructure is not our core specialty. Whenever we can get by without having to laboriously set up infrastructure, we count it a win.
Managed services is the practice of outsourcing the responsibility for maintaining a range of processes and functions. The Managed Service Provider (MSP) provides the managed functions, such as computing services, to us under a service-level agreement (SLA).
At Sprinthubmobile we prefer the managed services, such as the GCP services, to custom setups. GCP’s Cloud SQL, MongoDB Atlas, Cloud Memorystore, etc, over a custom database setup. Similarly for computing services. We want to be freer to design delightful mobile solutions. We manage infrastructure only when it is essential to achieving our goal.
Not so simple security
When developing back end services, security is a primary concern. We would love to be featured on the news someday, but not in the disgraceful security breaches series, so we follow certain guidelines to secure the systems we build, preferring proven methods to custom methods.
- Check web applications against the OWASP Top 10 Most Critical Web Application Security Risks.
- Prefer stable dependencies. For example, prefer Express.js to whatever Node.js server framework that was released three minutes ago.
- After we build any piece of a system, many reviewers look at it. The more eyes looking at it, the better.
- Prefer proven solutions to custom solutions.
- Audit dependencies using security scanners, where possible. Such scanners include `npm audit` (for Node.js applications) and third-party services such as Snyk.
- Limit communications among systems. More communication channels means more attack surfaces.
- Prefer secure communications among systems, applying mutual authentication where necessary.
- Provide access credentials such as database credentials, API keys, etc. to only the applications that use them. Keys can be injected into the environment, but using a key management service such as Vault, Secrets Manager, or Google Cloud KMS is preferred.
- Grant the least privileges necessary to applications that access cloud resources for their function.
- Grant access to roles rather than to service accounts. It is easier to manage access on particular roles than on several service accounts.
- Expose services on only networks over which they communicate.
- Periodically review roles and their access privileges, and remove unused privileges. Google Cloud Platform’s IAM feature periodically tells us what privileges we have not used, and we remove them.
Scalability for Backends
It is important that the systems we build are available to their users when they need them, even under heavy usage. To ensure that our services respond to changes in load, we apply the following guidelines where appropriate.
- Use the auto-scaling features of the cloud provider.
- Monitor service load over time and adjust the resources provisioned to account for normal behaviour and any expected spikes.
- Before adding more compute resources to a service, consider application profiling and optimisation to identify performance bottlenecks.
- Design scalable and resilient system architectures. It is the first step in the journey to scalability. Refer to the The Twelve-Factor App, a methodology that enables building apps that are easy to scale on cloud platforms.
Enough of these guidelines, and no more
Having the guidelines outlined above helps us build reliable products quickly. But having too many guidelines can cause our work to suffer in several ways.
At Sprinthubmobile, the process is as important as the product.
We take a minimalist approach to building software. In extreme programming parlance, we do the simplest thing that could possibly work. Only when we find that there is a need to follow a particular guideline do we introduce it. That is why they are guidelines rather than rules.
Furthermore, we continually observe our process, knowing that we may need to change these guidelines as we learn. We are building both the products and the process that builds products, simultaneously.
Back-end development, and software engineering in general, can be complex. Our business is providing solutions, so we follow certain guidelines to reduce complexity.
- We embrace automation in order to relieve us of mundane tasks, reduce our chances of making mistakes, and free us to innovate.
- In order to have relevant information when we need it, we document only as much as necessary, and in the most appropriate form we can afford.
- We take advantage of managed services to avoid complexity that is not core to our business.
- We follow certain guidelines that help us protect the systems we build.
- And we apply these guidelines in a balanced manner, to ensure that their application does not introduce bottlenecks in our process.