Development

App Architecture Series: Building a Better User Interface

October 21, 2019
App Architecture Series: Building a Better User Interface

At Michi­gan Soft­ware Labs, we don’t sim­ply write code to sat­is­fy require­ments. We find ways to solve prob­lems effi­cient­ly and effec­tive­ly. Know­ing that a well-struc­tured appli­ca­tion comes down to a set of tech­niques and pat­terns, I have been explor­ing design pat­tern the­o­ries and how they shape our think­ing. Grant­ed, it’s huge and com­plex top­ic, but here are some areas I’d like to cover: 

  • Con­sis­ten­cy
  • Reusabil­i­ty
  • Opti­miza­tion
  • Testa­bil­i­ty

Let’s begin with the pre­sen­ta­tion lay­er. The user inter­face (UI) is the top-most lev­el of the appli­ca­tion. It’s also the most frag­ile aspect of the devel­op­ment process — the part clients want to tweak long after we begin imple­ment­ing code. 

A senior devel­op­er once told me he nev­er want­ed to devel­op mobile apps because of the con­stant UI headaches. The ongo­ing changes drove him nuts. I on the oth­er hand enjoy changes, because they lead to progress. The ques­tion is, how can we bet­ter pre­pare for these inevitable changes? 

The tra­di­tion­al cod­ing work­flow looks some­thing like this: Get the mocks from design­ers, open a new sto­ry­board in Xcode (or cre­ate a new xml file in android stu­dio), fol­low the design details close­ly (font size, text and back­ground col­or, etc.), build­ing every com­po­nent one by one (text fields, labels, but­tons, views, shapes, etc.). 

A num­ber of ele­ments are repeat­ed when writ­ing UI code. Things like text size, font styles, mar­gins, paddings, and col­ors. They tend to be so sim­ple I don’t pay much atten­tion to what I’m doing. With text col­or, for exam­ple, I just grab the hex val­ue from the Zeplin file and code: 

android:textColor="#166503"
self.label.textColor = UIColor(red:0.09, green:0.40, blue:0.01, alpha:1.0)

Not ide­al, right? These val­ues don’t make much sense and are error prone. Lat­er, I changed them to: 

android:textColor="@color/colorGreen"
self.label.textColor = CustomColor.green

An improve­ment, but still not good enough. Nam­ing can be tricky. What if I want to go from green to pur­ple? I talked to our design­ers and we came up with a bet­ter col­or nam­ing sys­tem that defines pri­ma­ry col­ors, sec­ondary col­ors, error col­ors, etc. As it turns out, a small change in col­or nam­ing pro­vides far greater flex­i­bil­i­ty down the road, espe­cial­ly if there’s a theme switch requirement. 

This exam­ple under­lies the impor­tance of open com­mu­ni­ca­tion between devel­op­ment and design teams. Col­lab­o­ra­tion is a must if we want to be able to reuse/​maintain the resources ref­er­ences 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 every­thing from col­ors, typog­ra­phy to grids and paddings. This is the most abstract part of UI design sys­tem. For small projects, it should be all you need. 

The Design Sys­tem on the oth­er hand is more com­pli­cat­ed and requires more of a team effort. It’s noth­ing new. In fact, many com­pa­nies are already using it: A Design Sys­tem is the sin­gle source of truth which groups all the ele­ments that will allow the teams to design, real­ize and devel­op a product.” 

When we take a clos­er look, it’s actu­al­ly a com­po­nent-based sys­tem that ensures visu­al and func­tion­al con­sis­ten­cy. This includes all the com­po­nents of the Style Guide along with an inte­grat­ed set of func­tion­al com­po­nents, such as spin­ners, but­tons, images, etc. Although com­pa­nies have unique ways of defin­ing a Design Sys­tem, the end goal is con­sis­ten­cy and reusability. 

Con­sis­ten­cy

Con­sis­ten­cy can elim­i­nate con­fu­sion and short­en the learn­ing curve for users. Con­sis­tent and clear com­mu­ni­ca­tion also ensures a lev­el of qual­i­ty con­trol when ques­tions arise around use case, such as: What load­ing indi­ca­tor should we use to inform users the data is being loaded, a sys­tem spin­ner or a fan­cy skele­ton view? How should we dis­play an error mes­sage if one should occur? Should users be expect­ed to pull and refresh to search or should we show them a retry but­ton? These aren’t always indi­cat­ed in the design file, so devel­op­ers often leave them blank. 

Anoth­er issue is con­sis­ten­cy across plat­forms. Most of the time we build apps for both Android and iOS. Google and Apple guide­lines rec­om­mend using plat­form-stan­dard con­trols when­ev­er pos­si­ble. Unfor­tu­nate­ly, Google and Apple have very dif­fer­ent thoughts on the UX with their devices and apps. Google tends to go deep, while Apple is flat. 

Should we cre­ate a sep­a­rate design style for each plat­form to give users a native” expe­ri­ence and main­tain con­sis­ten­cy with oth­er mobile apps with­in each platform’s ecosys­tem? Or should we keep the plat­forms iden­ti­cal to main­tain a con­sis­tent UI expe­ri­ence for users, regard­less of who they are or what device they’re on? 

Ulti­mate­ly, these are design or even busi­ness deci­sions; how­ev­er, from a developer’s per­spec­tive it is obvi­ous that build­ing native components/​navigation pat­terns is more effi­cient than build­ing a mix of Google’s Mate­r­i­al Design com­po­nents and Apple’s Human Inter­face Guidelines. 

Before cod­ing your first ele­ment, it’s always a good idea to eval­u­ate the design’s con­sis­ten­cy with the native sys­tem to deter­mine how much effort will go into build­ing cus­tom ele­ments, such as: 

  • Nav­i­ga­tion pat­terns and nav­i­ga­tion elements
  • Default con­trols
  • Inputs styles and but­ton styles
  • Alerts
  • Typog­ra­phy
  • Ani­ma­tion

List­ing and com­par­ing these ele­ments gives a bet­ter sense of how to approach the project. For instance, whether to use native com­po­nents or exist­ing com­po­nents, or whether to cre­ate com­pound com­po­nents or self-drawn com­po­nents. A view may seem basic enough but actu­al­ly con­tain many self-drawn or com­pound com­po­nents. This is when we begin to under­es­ti­mate the amount of effort involved.

Reusabil­i­ty

It’s a tall order writ­ing code that can be uti­lized through the dura­tion of a project. By its nature devel­op­ment is an evolv­ing process, requir­ing mod­i­fi­ca­tions as new fea­tures are added or sys­tems upgrad­ed. One thing we need to pay atten­tion to is when we intend to cre­ate a component/​style glob­al­ly, but end up instead with a series of over­ride base class­es or xml styles to fit spe­cif­ic require­ments. Such over­rides erode consistency. 

Some­thing else to keep in mind are the dif­fer­ences between plat­forms. It’s impor­tant to know how UI sys­tems are struc­tured in order to deter­mine the best strate­gies for work­ing with each one. 

And we haven’t even begun to touch on Opti­miza­tion and Testa­bil­i­ty. Look for that in our fol­low up post. 

To be continued…

Mei Huang
Mei Huang
Software Developer

Looking for more like this?

Sign up for our monthly newsletter to receive helpful articles, case studies, and stories from our team.

Between the brackets: MichiganLabs’ approach to software development
Development Team

Between the brackets: MichiganLabs’ approach to software development

February 12, 2024

Read more
Information Experience can make or break a product
Design Process

Information Experience can make or break a product

January 4, 2023

Kai discusses how writing impacts user experience, providing an overview of the types of writing that are involved in product development and how to approach it from a very high level.

Read more
Advanced Tailwind: Container Queries
Development Web

Advanced Tailwind: Container Queries

July 28, 2023

Explore some advanced web layout techniques using Tailwind CSS framework

Read more
View more articles