New projects are exciting. Green field. Carte blanche. They are an opportunity to do things the "right" way, upgrade to the latest versions, use a new framework and apply new design or development techniques.
Starting a new project is also an enormous responsibility -- decisions made at this embryonic stage will have lasting benefits (or consequences) and it's critical that sufficient effort be dedicated to achieve a modern, professional standard.
The upfront cost of a good setup pays for itself in dividends, and it is our duty as software consultants to lay a solid foundation for our clients and to provide a pleasant development experience.
Here is a quick checklist I've composed of must-have's when setting up a new project.
✔️ The environment setup is fast, easy and repeatable.
The development environment must be easy to set up. If your application has at least one dependency, such as a database, use something like docker-compose to manage and link various components. Provisioning and running the application should be limited to a few commands. The quality and efficacy of a project setup can objectively be judged by the amount of manual intervention required.
✔️ The version control system (VCS) is modern and is hosted by a quality provider.
This seems like an obvious one, but from time to time, I run into newer projects using dated VCS and/or less-than-ideal providers. Pick a widely-used and supported solution. Cost should not be a factor in this decision.
✔️ Tests and code linting are run each time new code is checked in.
Set up a test suite immediately when setting up the project, as well as code-style and quality checks appropriate to the language used. Use a continuous-integration tool to automatically run these tests each time new code is pushed up, and if your version control host allows it, set the status on the commit as either pass or fail.
Tests should always run quickly. If you have multiple test suites (e.g. unit tests, acceptance tests, etc.), configure separate jobs to allow tests to run in parallel.
✔️ Code coverage is measured and enforced.
Code coverage should be analyzed as part of the test suite. Strive for 100% from the get-go, and have the CI fail commits which lower overall coverage. Full coverage ensures that all code gets executed (one way or another) and is useful to highlight unnecessary or dead code.
✔️ A clear branching strategy has been defined.
Decide right away what the branching strategy is for the project, and include it in the project's README. Set up a default branch in version control for development. At a minimum, active development should be done in isolated feature branches. When working in a team, require a code review before the branch is merged into a main, stable, or development branch.
If your application needs to adhere to a steady release schedule, a more complex branching strategy like this Git branching model may be suitable. Try to keep it simple; your approach will evolve, particularly if paying users depend on a stable service. The point here is to define a process before development starts and be rigorous and disciplined in following it.
✔️ Branches are protected.
This is critical. At a minimum, Protect your main branches from accidental deletes and disallow force-pushes. In certain cases, it may be desirable to restrict merges to certain users.
Ensure that branches are up-to-date with the target before merging. If the VCS host doesn't provide you with this feature, script it and have the CI reject a pull-request with an outdated branch. All tests must pass prior to merging code.
✔️ Deployments are automated and use VCS as a trigger
Given that your branches are properly protected and that you have a clearly defined branching strategy, configure your VCS to emit a webhook, or, have your CI poll for changes on a specific branch, to trigger the deployment. The build should be fully automated to ensure consistency.
✔️ Logging & monitoring is configured.
Configure logging and server monitoring right away, not when you need them.
Automation, safety checks, and repeatability are critical to produce robust projects. Developer confidence increases when chance is removed from the build and development process, and can ultimately lead to a product with greater stability and less downtime than one requiring manual intervention.
Clients and customers won't trust a product if its developers don't, so it is critical that we build atop a solid foundation.