TrueVote.Scaffolding — Construction of best practices in software development
As of this writing, the Api does little, but it does it well, and it does it with best practices. It is now the scaffolding upon which we construct the house for the TrueVote Voting Suite of Applications. Brick by brick, we build this house to last.
There are several approaches to launching new “greenfields” software. One is just to hack away and prototype quickly towards an MVP (Minimal Viable Product). Another is to meticulously design everything and iterate across stakeholders, modifying written functional requirements before coding. Our approach is to take what you’ve learned and build something solid to meet the principles you value. Among those:
- Performant — To approach each part of the software with a sense of large-scale utilization and understand that through the build, test, merge, and sign-off cycle.
- Secure — We always develop with the mindset of Murphy’s Law — “what can go wrong, will go wrong” and code defensively and with an atomic approach. For further assistance, the scaffolding is set up with static code analyzers at compile-time to help us find potential problems before they become vulnerabilities.
- Full test coverage —We’re building a rigorous test suite, inspired by Dr. Richard Hipp of SQLite, more on that below.
- Ultra-strict linting at compile-time — All contributors’ code shall look the same. We’ve turned on virtually every linting option to ensure the strictest patterns.
- Self-Documenting — Well-designed software doesn’t need a manual for new developers to come on board. Strict enforcement of model and endpoint descriptors helps ease the learning curve.
- Portable across cloud service providers — while our initial deployment is with Microsoft Azure Functions, we could move the workloads to AWS Lambda or Google Cloud Functions. The word “Azure” doesn’t exist in the scaffolding beyond the headers, and we will abstract vendor-specific components.
Tooling used in the scaffolding:
- OpenAPI & Swagger — standardized method for publishing endpoints
- Coverlet & Coveralls —track code coverage
- XUnit & Moq — unit testing framework
- GitHub Actions — CI/CD (Continuous Integration / Continuous Deployment)
- Logging — Standard logging throughout all components
- Dependency Injection — Enables class instantiation simply by declaration
Swagger can and should be customized if you have a public-facing API.
OpenAPI allows for detailed descriptions of each endpoint’s purpose and data model property descriptors — if you choose to use them.
Culture of Test
“Test your code — or your code will test you”
Brett Morrison, 2014
SQLite is one of our favorite projects. There are over 1 Trillion instances of it running worldwide. It’s also regarded as the most thoroughly tested codebase in the history of software. At TrueVote, we have goals, and we strive to meet them. We have our code-coverage threshold at 100%, and we intend to keep it that way. For something as important as voting — there is no compromise.
The coverage badge on the front of each of our repositories is a badge of honor and a testament to hard work.
First Endpoint: /status
Software should provide an internal “health check” and some diagnostic information.
/status simply returns a data model of a few elements of the software that are useful to quickly check.
It reads a compile-time generated `version.json` file, stores it in a static variable for subsequent reads, and returns a json payload. This can be used to monitor health checks and confirm exactly what version is running on the instance serving the request. Later, when we deploy deterministic builds (as specified in the white paper), it will return a checksum of the code to prove that it matches the code on GitHub.
TrueVote is open source. Please consider contributing! Check out the guidelines on our contributor page to get started.
A few open issues with tightening and automating the scaffolding further:
- In addition to REST, add GraphQL.
- Enforce OpenApi descriptor annotations. The C# linting options specified in
.editorconfigdo not have a way of ensuring that public endpoint methods are correctly documented. We want to ensure that the 4 lines above the function declaration are included, ideally at compile time.
- Automatically export data models as TypeScript .ts files for use in the mobile application.
- Add git hook and GitHub hook to enforce commit messages with a reference back to a JIRA ticket or GitHub issue.
Future Blog Posts
Looking ahead, concurrently as we build on TrueVote.Api, we plan on publishing more about our efforts of the additional elements in the TrueVote Application Software Suite:
- TrueVote.Scaffolding for the mobile application
- Why TrueVote chose Bitcoin as its immutable blockchain for tamper-proof data