The first flaw I did was to code on without unit tests. Yea, I did a great architecture and object oriented design. But when things change in a profound way, everything falls apart.
I made unit tests for some of the critical music rules like intervals and keys. But the majority of the model, view, editing, file operations had no automatic tests. It was futile to try to create that kind of tests afterwards.
I was at a point where I wanted to introduce variables, like in Lilypond. Write a theme or snippet once, and use it multiple times. If you change a note in the variable, it also changes automatically in all references.
This should be no problem, but my architecture was not prepared for it. It had a tight coupling between view and model to support editing. Since a variable’s notes would have several (x,y) coordinates, I needed some proxy objects – ghost notes – in the model to allow for storing of the possible differences in timing, accidentals, stem direction and so on.
It could possibly be solved, had I unit tests for all functionality. But the case was, every time I did some change to the model, some other features started to fail.
The lesson is: Create unit tests as a part of the process. Do it the TDD way:
- Create a failing test
- Make the test pass by writing a minimal amount of code
- Refactor
And try to keep the code coverage as high as possible.
Leave a Reply