Time for some reflection on my audio-merger project. The goal is to mix a list of audiofiles to one track. Did I learn something last week?
The first experience: refactoring.
I already had a solution with some relevant components that I probably want to combine in the future, so my merge-project is now part of this solution. The other projects were still unfinished and contained some older concepts for development. So that took some extra time to refactor.
The hardest thing was to make choices about the ‘core’ project containing business logic for that other project, versus a project ‘services’ that should contain the common, shared functionality. It gave me some extra confidence that I, with the support of Visual Studio, was able to build after some heavy refactoring.
The second experience: Domain Driven Design.
I got stuck in the first few chapters of the blue book, but coding on my project confronted me with some scenarios where I tried to fit some DDD-theory, like an evaluation of a service-layer that contained some shared object-models, that are used on multiple places. Is it a good or bad practice? It’s not the concept of a service in DDD. The models should be entities elsewhere in the solution, and consumed by other code or transferred to other segments by a DTO.
It made me also play around with the original object-representation of the real world. When you start coding you keep it simple: have some input data, a some code that will process the data and at the end the result. Later this becomes more complex, you will bundle relevant fields in a model-class, as a package of data that gets labelled with a name from the real world, and this model will be routed through methods and layers, so still you won’t recognize it as a real-world-object. To make it more real world a model should have some behaviour and a life-cycle.
E.g. I can create a model-class with properties representing a music file and create audio-player that can play the music file, or I can let my music file model have a “play”-method.
For the distribution of a file I have a ‘destination-data’ model with target file locations. I can have a distribution class that will use this for sending a file to a destination. In a setup with behaviour I can make the destination responsible for the transport, by adding a ‘Send’-method. In the life-cycle of this entity I add a new Guid for identification. Destination
The third experience: The architecture of my project.
As a product-owner from hell I figured out some new features during development. And I didn’t work it out property at the beginning because I wanted to Keep It Stupid Simple.
What I first needed was a code class suitable for different scenarios:
- a console that pick audio files from a folder, analyse them for start/ end cues and do the mix.
- a console that reads a file with a list of audio filenames, pick the audio files from a folder, analyse them for start/ end cues and do the mix.
- a console that reads a file with a list of audio files and start/ end cues, pick the audio file names and use the provided data to do the mix.
- a windows form-application, where you can create a playlist, and thus provide a list with file names and start/ end cue, pick the audio file names and use the provided data to do the mix.
- maybe in the future as a web-based application
I started with one library project responsible to do the mixing and an other project for the windows form-application: select files, set values for begin and end cue-times and start the Mixing.
That worked out well so soon I thinking about the scenario where a console picks audio files, automatically detect cue points and do the mix. So I needed to add something that could analyse audio files and detect cue points. Should I integrate this analyse-functionality in my mixer library? I choose not to, but noticed I reconsidered this choice continuously .
In my windows form I could set the cue time manually, but I also wanted to be able to analyse the audio when the file is selected. In one scenario I assume the list with cue-times is already there, it should use the provided information to merge the files and create a mix down, without the analysis step. In that case integration should be obvious.
The fourth experience: UX.
Damn, I am not a UX-designer. I want to store the merge information and relevant files, so a user must be able to modify a merge job. First I wanted to keep it simple, just to store these files always under my application root. Then I wanted to be able to separate my app and the data, so I introduced a “workspace”-folder-setting to store these files on another location. And finally I came up with the idea to let a user be able to select a location outside this default “workspace”-folder.
That’s why I also wanted a recent files-list. That introduced a lot of overhead. And although selecting a file seems so obvious, catching all events, like ‘double-click in a list to select’ or ‘cancel’ still needs to be well thought.