The MuseScore system is based on an architecture that supports all the requirements, both functional and non-functional. Furthermore, each architectural decision made should support the software development process. This essay addresses issues that occur during the design of the architecture and the decisions that were made based on these issues. An outline of the different views of the system will be given, and some will be explored more in-depth.
Several books discuss the architectural views that can be applied to a software system. The ‘classic’ division, as written by Kruchten1, contains 4+1 views: logical, implementation, process and deployment, which are all dependent on the use-case view.
The 4+1 views as identified by Kruchten1
However, others have argued that more views can be applied to a system: an operational, context, functional, information and concurrency view2, for example. It is therefore important to determine which views are relevant to the MuseScore system.
We identify the following views to be relevant to MuseScore:
- Context view, also referred to as use-case view. Without a context, how do you know what you are developing towards, so this is a necessary part of any system architecture. A detailed illustration of this was previously given.
- Development view, which “describes the architecture that supports the software development process”2.
- Deployment view, which “describes the environment into which the system will be deployed and the dependencies that the system has on elements of it”2.
- Operational view, also called runtime view, which focuses on the production environment when the system is already running.
- Information view, also referred to as the data view, which discusses what and how data is stored and managed in the application.
- Functional view, or logical view. It identifies the functional components of a system and their responsibilities within the system as a whole.
These views are represented in the diagram below, inspired by Rozanski and Woods2. We do not identify the concurrency view for the MuseScore system, because we see this as less relevant. The system runs locally, so one user will be using that instance of the system at a time. Therefore, the concurrency is not an issue that needs to be addressed by MuseScore and thus not relevant for the views.
The images and their dependencies sketched
Styles and patterns
In this section, we identify architectural patterns used to tackle issues in software development. We studied the architecture extensively, but could only find one pattern and no further styles.
MuseScore employs the model-view-controller (MVC) pattern3. When using the MVC pattern, the model (data), controller (logic) and view (UI) are loosely coupled. This results in more maintainable software, as changing code in one module does not necessarily affect the code in another module.
Although the MVC pattern should facilitate a loosely coupled codebase, the MuseScore source code has not separated the three rigorously. The view of MuseScore is built in Qt, which is a framework for UI development in C++. The package
mscore contains most of the controller classes, however, a lot of UI is implemented here as well. The package
libmscore includes the model classes, but also some controller functions.
The MVC pattern applied to the MuseScore system
We will first show how the project is divided into different modules of code in the module structure organization section. In the common design models section we show how MuseScore maintains a consistent code style despite having multiple contributors. The codeline model describes how the code is maintained by a large group of contributors.
Module structure organization
The structure of MuseScore has several main components. These are all outlined as packages in the ReadMe on the Github page of MuseScore. There are two main components that we will highlight:
libmscore: the data model for MuseScore.
mscore: the package for the MuseScore UI and controller.
Together these two packages make up for 75% of the code of MuseScore itself, measured in man-year4. This percentage is based on the information from the SIG analysis, which calculated the man-years of individual components5. These two packages together make all the other packages more of a support package to these two, as seen in the model structure below.
In the model, most of the packages of MuseScore are represented, the ones that are missing are either packages that do not contain relevant code, such as the share package, or third party software.
The model structure of MuseScore. The greener the packages, the bigger they are
Common design models
MuseScore has several rules and guidelines on how to work on this project. They have a code rule book that explains how to write your code. For example, it is not allowed to work with tabs for indentation; and they use six spaces instead. All of the rules can be found on their website. Furthermore, the test guidelines explain how to write tests for your code.
To maintain the code of the project, MuseScore uses GitHub and git for version control, and their own issue tracker for potential new features and a forum for documenting bugs. It is required to create or choose an issue when you want to contribute to the codebase, so other contributors can clearly see your progress. This is clearly defined in the contributors guidebook.
Deployment and operational view
Many ways of publishing or distributing a software system exist. Whether it is a SaaS, a library or a mobile application; each situation is different.
As MuseScore is a stand-alone application, to be downloaded from the website as an executable for your operating system of choice, installation is trivial. Any dependencies, in the form of audio codecs6, text fonts, and so-called soundfonts7 are bundled with the application (although MuseScore supports adding third-party soundfonts and plugins).
Once installed, MuseScore has functionality for automatically updating the software. This is a setting that can be toggled in the preferences. When this is turned on, the system checks for updates on every startup. It is also possible to manually check for updates. This allows users to easily have the newest version available.
In terms of the system environment, MuseScore has two strict requirements8:
- At least 300MB of free disk space.
- A recent version of any major operating system (Windows 7, macOS 10.10, etc).
Because of the simplicity of this system, and the very brief requirements, further aspects of the operational view are not worth mentioning.
In short, the deployment and operational views are rather straightforward. MuseScore is a stand-alone application with all of its dependencies bundled together into one executable. It automatically checks for updates and has system requirements easily met by most systems.
Information and functional view
MuseScore creates data in the form of music scores, and the way this data is handled, stored and shared is important to the users. This can be seen in the way MuseScore handles copyright and how their data is saved.
Copyright can be a big issue in the music industry and the MuseScore system needs to handle this properly. MuseScore has the functionality to add copyright information to the footer of scores. Although it is the responsibility of the user to adhere to any copyrights on scores, MuseScore assists users by providing an easy to follow manual.
While editing, a score is saved in a compressed MuseScore custom format. These can be converted to a MusicXML file, clearly showing all stored information: chord, duration, beam, articulations, volume and instrument.
In terms of functionality, MuseScore supports the use of MIDI conversion to allow users to easily input chords. This is a great feature as it makes sure that chords do not have to be entered note by note, which can quickly become tedious.
Trade-offs of non-functional properties
In every system, trade-offs have to be made on numerous levels. These trade-offs eventually lead to architectural decisions made during all phases of development. Non-functional properties are usually traded off in favor of functional properties, as architects do not want to limit the core features of their system.
Some non-functional properties that apply to MuseScore include the size of the application, the size of scores when exported, the speed of importing scores and the speed of exporting scores.
The MuseScore 3 application has a size of around 300 MB, once downloaded, it runs smoothly. However, when developing, the compilation does take up a lot of time. Considering the exporting of files, MuseScore supports PDF, PNG, and other graphic formats9. The size of these files depends on the length of the score and chosen export format, but they are relatively small. This might suggest that the developers have traded off efficient compilation in favor of smaller files.
Finally, MuseScore has made the accessibility of the application a high priority to support all of its users10.
To summarize, MuseScore has mostly focused its non-functional trade-offs to benefit the score size and accessibility, as users will mostly use the created score once finished and focus less on the time it takes to get there. The application’s compilation and execution time have suffered from this.
To conclude, MuseScore has implemented an MVC pattern to ensure a loosely coupled system for easy maintainability. It is deployed with individual releases, where dependencies are included as well. Once operating, the system has a few dependencies, automatic updating can be enabled for an up-to-date system guarantee. The data for MuseScore is saved in a custom format which stores all the necessary information. In terms of functionality, MuseScore provides support for MIDI conversion. Finally, we saw that MuseScore has made its biggest trade-off to benefit the size of created scores and accessibility, at the cost of compilation and execution time.
Nick Rozanski and Eoin Woods. Software Systems Architecture: Working with Stakeholders Using Viewpoints and Perspectives. Addison-Wesley, 2012, 2nd edition. ↩ ↩2 ↩3 ↩4
Gamma, Erich et al. Design Patterns. Addison-Wesley, 1994. ↩
Kan, Stephen H. Metrics and models in software quality engineering. 2003. p. 343. ↩