New Version of Sputter is Taking Time, Here's Why

For the last couple of months I have been working on solving some of Sputter’s underlying weaknesses. As described in the previous blog post this involves converting the sequencer and logic code from Java to C++ while incorporating Test Driven Development. This has been going on since summer this year, so what is taking so long time?

C++ is hard(er than Java)

Java was designed with focus on simplicity and abstracts away much of what is going on under the hood when running a computer program. C++ on the other hand exposes the “bare metal” in order to make specific optimizations and memory management possible. In other words, C++ is more suited in situations where performance is a requirement. This also makes programming in C++ more like walking on a razor’s edge. Here are some examples:

SomeType getSomeType(){
	SomeType someType;
	return someType;
}

getSomeType().someMethod();

The code above will crash. Why? The someType object gets flushed out of memory right after the getSomeType() method has completed. To solve this we can use the new keyword:

SomeType* getSomeType(){
	SomeType* someType = new SomeType();
	return someType;
}
SomeType* someType = getSomeType();
someType->someMethod();
delete someType;

That will work, but now the programmer is responsible for deleting the object returned by getSomeType(). If it does not get deleted that will result in a memory leak. Deleting it more than once will crash the program. Attempting to access it after it has been deleted it will also fail. Many of the crashes you have experienced probably have come from errors like this.

To solve this modern C++ contains something called smart pointers. The syntax is, as typical in C++, not great:

std::shared_ptr<SomeType> getSomeType(){
	std::shared_ptr<SomeType> someType = std::make_shared<SomeType>;
	return someType;
}
std::shared_ptr<SomeType> someType = getSomeType();
someType->someMethod();

This code works and although it has some theoretical overhead, it is a good way of solving the problem. There of course are a whole lot of other quirks and features to it as explained in this video.

Test Driven Development Takes Time

As demonstrated by Uncle Bob in this video practicing test driven development implies:

  1. Write a very basic test
  2. Write some naive and stupid code to pass the test
  3. Write another test which proves that the code from the previous step is naive and stupid
  4. Rinse and repeat until the code does what you want

Granted, this takes longer than just hammering out the code without testing, especially for someone who has not worked this way before. The upside is it produces a suite of tests and code which will be rock solid and prevent stupid mistakes like has happened in the past.

Current Status

Currently I have got to the point where I almost have a working sequencer logic without any fancy features like note velocity, note length or automation. This should be finished within the next couple of weeks. In other words, a fully working reimplemented system is still some time ahead.

Since it is taking longer than expected I am strongly considering an intermediate release before the version with reimplemented sequencer logic. Some ideas for new features in that release could be:

Further details will be posted probably right after new year.