Reusable software can be used by different users for different uses. While reproducible software might just be a collection of scripts, reusable software will typically include functions and/or classes intended to be called from other code. Once other code or other people depend on your code, the bar is much higher for ensuring the code supports the needs of its users and keeps working. Reusable software is often developed by multiple people, which introduces additional challenges as the team grows.
The most common challenges we see with making software reusable are:
- Updating your code can unintentionally break features that other people depend on
- When several developers work on the same codebase, it's easy to accidentally overwrite someone else's changes
- It can be difficult for other developers to read, understand, and modify your code
Reusable software benefits from all of the tools and practices you'll adopt for reproducible software. Additionally, address these challenges with the following tools and practices:
- Unit tests, MATLAB® unit testing framework
- Git™ branches, Git releases, pull requests
- Diff/merge tools, Comparison Tool
- Project structure standards, MATLAB Toolbox Best Practices
- Coding standards, MATLAB Coding Guidelines
You wrote a useful function that you use whenever you analyze data. Later, you modify it to handle a new case, but then eventually realize you broke other code that called it.
Testing verifies that software continues to behave as expected. Unit tests verify that individual "units" of software behave as expected. When you change a unit of software, run the corresponding tests to make sure it still works. You can also run tests when you get a new version of MATLAB to see if there are any incompatibilities with your code.
The MATLAB unit testing framework provides a structure for writing and running unit tests. While it supports writing tests as scripts, functions, or classes, use class-based tests. Class-based tests are much more capable than script- and function-based tests, supporting your needs as they grow with the value and impact of your code.
MATLAB provides templates, editor tools, and the Test Browser desktop side panel for writing tests, running tests, and viewing results. MATLAB Test provides additional tools for automatically generating tests, including generation of larger test suites with MATLAB Copilot. MATLAB Test also provides the MATLAB Test Manager to manage tests and test results for projects.
How do you approach updating your code? If it's a small change, you probably just make it directly in the file and move on. But what if it's a bigger change, requiring you to touch a bunch of code across several files? Frequent commits make it easier to revert your changes when needed, but committing incomplete changes can often break features that other people depend on.
Git addresses this tension with a feature called branches. Git branches let you make changes to your code without touching the original. Keep your original code on the primary branch, which we recommend calling "main". Create a new branch to make your changes. When you are happy with the changes (after running your tests, right?), merge the changes into your original code on the main branch. Professional developers often have a rule that the "main branch is always ready to ship." It might not be perfect, but it always works.
MATLAB offers both interactive and programmatic interfaces for working with Git branches, including the Branch Manager for visualizing and managing them.
One of the most immediate benefits of using branches is that other users of your code can always get the latest working version from your main branch, because your work-in-progress code is on a different branch.
While your main branch (hopefully) always contains the latest working version of your software, it might contain incompatible changes that break other code that uses your software. To address this, create releases, which are snapshots of your code at specific points in time - typically when you reach a stable milestone or finish a set of features. By tagging these releases, you provide a clear reference for others to use, ensuring that anyone who depends on your code can always access a tested, reliable version. Releases are a feature of popular Git-based tools like GitHub and Gitlab, not native to Git.
Label your releases with semantic version numbers (for example, v1.2.0), which make it easy for users to identify which version they should depend on and understand the scope of changes between releases. This way, other projects or teams can specify exactly which version of your code they rely on, avoiding surprises from breaking changes and making it easier to manage dependencies over time.
Challenge: When several developers work on the same codebase, it's easy to accidentally overwrite someone else's changes
Git branches are even more helpful when you work on your codebase with other developers. They let multiple developers work on different features or fixes at the same time without interfering with each other's code. By creating separate branches, you can safely experiment, collaborate, and merge updates while keeping the main codebase stable. A developer creates a "pull request" to propose integrating their changes with the main codebase. Other developers review and iterate on the code changes before merging them into the main branch. Pull requests are a feature of git-based services like GitHub and GitLab, not native to Git. Some systems call them "merge requests."
The Comparison Tool shows the differences between versions of files, folders, and projects, highlighting lines that have been changed, added, or removed. Tools like this are called visual diff and merge tools. When two developers edit the same file, the Comparison Tool lets you spot conflicts and decide how to merge the changes, so you don't lose any work or overwrite someone else's updates.
Even with a project guiding you, it can be difficult to know where to start when jumping into a codebase you haven't used before (or haven't used for a while). Well organized, consistent folder structures and file names make it easier to know where to look for different parts of the codebase, such as the source code, the tests, and the documentation. The MATLAB Toolbox Best Practices recommend a file and folder structure for developing MATLAB Toolboxes, and can be a good starting point for any MATLAB code project.
One of the great things about MATLAB is how loosely and informally you can write code and still get a great result quickly. If the code works, and nobody is going to see it again, does it matter what it looks like? Your time to insight is the most important matter, not the longevity of the code.
But as the value of your code increases, more people are going to spend more time reading your code. It does matter what your code looks like. Users of your code need to know it will work consistently as designed. Other developers will need to understand your code so they can work with you on it. A good set of coding standards helps enforce best practices for writing good code, and perhaps more importantly, get an entire team writing code in the same style so it's easier for everyone to work on each other's code.
The MATLAB Coding Guidelines recommend standards and best practices for writing good MATLAB code. They capture the essential familiar MATLAB style while applying best practices from professional software developers for writing readable, robust, code. The Code Analyzer analyzes your code as you type, and can be configured to check compliance with many of the MATLAB coding guidelines.
For reusable software, your README file also considers the needs of other people who help develop the software.
Append directions to the end of your README file that explain to other developers how to build and develop your software. For example, include instructions on setting up their environment and an overview of how the code is structured. This helps new contributors quickly understand the workflow and the steps necessary to effectively collaborate on the toolbox.
Projects are great for sharing code for others to run, view, and modify, but many users just want to use the features you have developed. They just want to install your code so that they can use it easily from within their projects like they do with MathWorks Toolboxes.
The recommended way to share your reusable code with your users is to create a MATLAB Toolbox file (MLTBX). This bundles all code, documentation, and supporting files into a single installable file. Your users just open the file to install your reusable code.
MATLAB also includes a package manager for automated installation of packages, including dependencies. This is an emerging technology that is currently recommended for users within a single organization who need robust automated installation of packages. The package manager is currently limited to using a shared file system to host packages. It is not yet integrated with MATLAB projects or toolbox packaging.