Saturday, June 11, 2016

An example of good engineering

I often advocate for good engineering practices and the path to Zero Bugs. Talking about these things is great and all, but concrete examples are important. I recently published an open source project that I think is a good example of this kind of work.

I hope you will copy some of the ideas to use in your own projects. You can read the source here: https://github.com/JayBazuzi/ValueTypeAssertions

Great tests

Code Coverage is a dumb measure, especially in this case. There are very few branches in the code; two tests would hit 100% coverage. 

In this project, you can pick any line of code and modify it to be incorrect, and you'll get a test failure that tells you exactly what is wrong. That is much more valuable than any code coverage number.

I can't guarantee that it has 0 bugs, but I can say that every type of bug I have ever imagined or experienced in this code is covered by a test. 

The tests are organized like a spec, using namespaces/folders to organize tests the same way as if you were writing a spec. Each name indicates what aspect of the system's behavior is being covered. 

The tests are super-fast, which makes the edit-build-test cycle a happy experience. 

ReSharper

ReSharper settings are included in the repository. All sources have been formatted with these R# settings. This makes it easy to keep formatting / style consistent. 

If a random person on the internet decides to make a contribution, I don't have to explain the project's style - they can just let ReSharper take care of that. 

ReSharper Code Inspections are 100% clean, further helping keep the code clean and consistent.

AppVeyor

Every Pull Request is automatically validated by AppVeyor, including build + unit tests.

C# Warn-as-error is turned on for the AppVeyor build. I believe it's important to have 0 warnings - either heed the warning if it matters, or disable the warning if it doesn't. But I don't want to slow down my edit-build-test cycle just because if a warning, so I don't set warn-as-error on the desktop. But I dot set it in AppVeyor, to to ensure that all changes have 0 warnings before they hit master. 

AppVeyor runs ReSharper Code Inspections, again ensuring there are 0 issues before merging to master. This is especially important because not everyone has ReSharper.

The AppVeyor web site lets you edit build settings online. It's a convenient way to tune the settings. Once I had them just right, I downloaded the appveyor.yml file and added it to the repository. Then I deleted my AppVeyor project and recreated it from scratch, to ensure that no online edits were required -- everything is in the repo. If anyone wants to fork this project on GitHub and set up the same build, that will be easy.

NuGet

Each AppVeyor build produces a NuGet package, which means we know that there aren't any problems in the .nuspec file or anything like that.

When a commit is merged to master, a special AppVeyor build runs to generate an "official" nuget package which is then automatically uploaded to the nuget.org package repository. (The API key is encrypted). AppVeyor automatically updates the version number, and it includes a "-beta" tag so no one expects it to hold to any Semantic Versioning guarantees. 

When semver becomes important for the projet, I will implement a one-touch release process to nuget with non-beta versoin numbers.

The project itself

The whole purpose of this project is to help you get a step closer to zero bugs. 

It embodies all I have ever learned about how to implement equality in C#. Everything I have read; every mistake I have made; every mistake I can imagine making. It makes it easy to eliminate a class of errors: "C# class with incomplete or incorrect equality implementation".

It reduces the barrier to addressing Primitive Obsession, which means fewer bugs in the rest of your system, too.

The project is small

This is quite a small project. You may think that your codebase, being far larger and more complex, would not be amenable to this kind of engineering. I admit that I haven't proven otherwise. And even if you believe it would be possible and valuable to do it on your big project, you may not see how to map these ideas from here to there. Sorry.

But in some ways, the fact that it is small is part of its success. I have found a single need and satisfied that need in a single package. You can adopt this package without taking on any other requirements - no opinionated framework here. It adheres to the Single Responsibility Principle. It does what is needed and nothing else. Any time you can make a project do that, it's a win.

No comments: