Systematically developing high-quality reusable software components and frameworks has traditionally been a tall order. Many developers successfully reuse code snippets from one program to another, which saves a certain amount of development time; however, this practice does little compared to leveraging assets like architectures, components, and frameworks.
There are a number of reasons (both technical and non-technical) why software reuse is difficult, particularly in companies with a large installed base of legacy software and developers. One of the reasons we see most frequently – and one of the easiest to correct – is the failure to separate business logic from the UI (user interface). Projects with interwoven business logic and UI code are time-consuming and tedious to convert over to new screen sizes, hardware platforms, or operating systems - a common requirement.
There are four steps you need to take if you are building products with embedded GUIs (graphical user interface) and want to take advantage of code reuse in a systematic fashion. Although it’s Storyboard-specific, the central ideas are applicable elsewhere.
In other words, keep the embedded GUI focused on its role: presenting information and interacting with the user. The application’s brains (also known as the backend) – the system interaction, calculations and algorithms, and domain-specific knowledge – needs to stay completely outside of the UI. Since the GUI is nearly guaranteed to change when moving the software to different products or platforms, having decoupled business and UI logic allows you to easily “chop the top”, creating a new look or new behaviour that relies on tried and tested components.
To protect the back-end business logic from all of that churn and make it as reusable as possible, implement a client-server model, a model-view-controller, or whatever other paradigm works best for you and your team.
If you’re using Storyboard, this all-important decoupling is automatic due to our product’s design. A Storyboard application’s user interface is represented by the design (the screens, controls, and animations), while the core logic is in C/C++ source files. Because the logic is physically and conceptually separated from the user interface, they are inherently uncoupled.
So, how do these pieces talk?
While you want the business logic and UI to be completely separate components, they need to be able to communicate. You need “glue” to connect the two together with a configurable event system, a scripting environment, or programming API that can loosely couple the UI to the backend. The glue takes information coming from the backend and uses it to populate user controls, all while also communicating user actions to the backend.
There’s a risk that if the glue’s connection mechanism is too weak, you’ll be forced to implement some of the UI logic into your more powerful backend software, exactly where it shouldn’t be. Similarly, if the glue environment is too strong there may be a temptation to implement parts of the business logic within the UI environment itself. This usually doesn’t happen on purpose, but logic code sneaking into the UI layer is a common problem in frameworks that share the same language for the backend and the GUI. You want a glue that’s just right – powerful enough to get the job done, but one that makes it easy to avoid implementing business logic by accident.
In Storyboard, that perfect glue is provided through Lua scripting. Lua gives you the logic, branching, and calculations to build the most sophisticated embedded GUI you could imagine, but the amount of code you need is relatively minor for most applications - and that layer of code remains thin. All of the interactions between the UI and the back-end pass through a controlled, well-defined API – which is where our next point comes in.
To enforce the clean separation of your components, you need an API contract. The API contract is documentation that serves as a guarantee of what one piece of code does when it receives certain inputs. The contract provides a shared understanding of what the caller and callee’s responsibilities are, and it allows the caller to rely on the results of the functions within the module – nothing more, nothing less.
In the world of Storyboard, the API contract between the business logic and the UI is provided through the Storyboard IO API. This is a structured mechanism for sending and receiving messages between the two components to guarantee that no “side-channel” communication exists and that the access to your business logic or your UI is clearly defined.
But is there any way to enforce your API is remaining true to its contract?
Unfortunately, there is no magic bullet here; to enforce that an API contract is valid, the programmer needs to create tests. A properly designed test suite ensures that the software works when it should. It can help you isolate problems to discover if they’re within the application logic or the UI. Testing may be a necessary evil that we put off if we can, but we always feel better when we can run tests to validate that our changes didn’t break anything. Testing is the difference between walking on a tightwire compared to walking on a sidewalk. With the support of the sidewalk under you, you’re a great deal more confident you’ll arrive safely.
This summary focuses on the interface between business logic and the UI – the place where we often see reuse attempts fail. However, the discipline of code reuse is much broader than that. If you’re interested in more great tips on reuse, opensource.com has a great blog with 30 best practices to keep in mind. And if you’re interested in other elements important to building a successful product, take a look at our eBook, Building your next killer embedded UI. Enjoy!