At Michigan Software Labs, we don’t simply write code to satisfy requirements. We find ways to solve problems efficiently and effectively. Knowing that a well-structured application comes down to a set of techniques and patterns, I have been exploring design pattern theories and how they shape our thinking. Granted, it’s huge and complex topic, but here are some areas I’d like to cover:
Let’s begin with the presentation layer. The user interface (UI) is the top-most level of the application. It’s also the most fragile aspect of the development process — the part clients want to tweak long after we begin implementing code.
A senior developer once told me he never wanted to develop mobile apps because of the constant UI headaches. The ongoing changes drove him nuts. I on the other hand enjoy changes, because they lead to progress. The question is, how can we better prepare for these inevitable changes?
The traditional coding workflow looks something like this: Get the mocks from designers, open a new storyboard in Xcode (or create a new xml file in android studio), follow the design details closely (font size, text and background color, etc.), building every component one by one (text fields, labels, buttons, views, shapes, etc.).
A number of elements are repeated when writing UI code. Things like text size, font styles, margins, paddings, and colors. They tend to be so simple I don’t pay much attention to what I’m doing. With text color, for example, I just grab the hex value from the Zeplin file and code:
self.label.textColor = UIColor(red:0.09, green:0.40, blue:0.01, alpha:1.0)
Not ideal, right? These values don’t make much sense and are error prone. Later, I changed them to:
self.label.textColor = CustomColor.green
An improvement, but still not good enough. Naming can be tricky. What if I want to go from green to purple? I talked to our designers and we came up with a better color naming system that defines primary colors, secondary colors, error colors, etc. As it turns out, a small change in color naming provides far greater flexibility down the road, especially if there’s a theme switch requirement.
This example underlies the importance of open communication between development and design teams. Collaboration is a must if we want to be able to reuse/maintain the resources references in the code.
Start With a Style Guide or Design System?
As the chart, below, shows, Style Guide is a set of design basics. Here, you can find everything from colors, typography to grids and paddings. This is the most abstract part of UI design system. For small projects, it should be all you need.
The Design System on the other hand is more complicated and requires more of a team effort. It’s nothing new. In fact, many companies are already using it: “A Design System is the single source of truth which groups all the elements that will allow the teams to design, realize and develop a product.”
When we take a closer look, it’s actually a component-based system that ensures visual and functional consistency. This includes all the components of the Style Guide along with an integrated set of functional components, such as spinners, buttons, images, etc. Although companies have unique ways of defining a Design System, the end goal is consistency and reusability.
Consistency can eliminate confusion and shorten the learning curve for users. Consistent and clear communication also ensures a level of quality control when questions arise around use case, such as: What loading indicator should we use to inform users the data is being loaded, a system spinner or a fancy skeleton view? How should we display an error message if one should occur? Should users be expected to pull and refresh to search or should we show them a retry button? These aren’t always indicated in the design file, so developers often leave them blank.
Another issue is consistency across platforms. Most of the time we build apps for both Android and iOS. Google and Apple guidelines recommend using platform-standard controls whenever possible. Unfortunately, Google and Apple have very different thoughts on the UX with their devices and apps. Google tends to go deep, while Apple is flat.
Should we create a separate design style for each platform to give users a “native” experience and maintain consistency with other mobile apps within each platform’s ecosystem? Or should we keep the platforms identical to maintain a consistent UI experience for users, regardless of who they are or what device they’re on?
Ultimately, these are design or even business decisions; however, from a developer’s perspective it is obvious that building native components/navigation patterns is more efficient than building a mix of Google’s Material Design components and Apple’s Human Interface Guidelines.
Before coding your first element, it’s always a good idea to evaluate the design’s consistency with the native system to determine how much effort will go into building custom elements, such as:
- Navigation patterns and navigation elements
- Default controls
- Inputs styles and button styles
Listing and comparing these elements gives a better sense of how to approach the project. For instance, whether to use native components or existing components, or whether to create compound components or self-drawn components. A view may seem basic enough but actually contain many self-drawn or compound components. This is when we begin to underestimate the amount of effort involved.
It’s a tall order writing code that can be utilized through the duration of a project. By its nature development is an evolving process, requiring modifications as new features are added or systems upgraded. One thing we need to pay attention to is when we intend to create a component/style globally, but end up instead with a series of override base classes or xml styles to fit specific requirements. Such overrides erode consistency.
Something else to keep in mind are the differences between platforms. It’s important to know how UI systems are structured in order to determine the best strategies for working with each one.
And we haven’t even begun to touch on Optimization and Testability. Look for that in our follow up post.
To be continued…