Considering architecture for Android app

Piotr Głębocki
the-stepstone-group-tech-blog
10 min readMar 5, 2018
“Two people in elegant shirts brainstorming over a sheet of paper near two laptops” by Helloquence on Unsplash

Introduction

Based on my experience in mobile development and time working at Stepstone I would like to indicate the role of architecture design in Android projects. I am not going to suggest any detailed technical solution here, just highlight what developers should pay attention to when designing the code. I intended this article mainly for developer who don’t have much experience in designing area and people who are interested in architecture of mobile applications.

Why do you need architecture ?

Clearly defined architecture is something really important especially in projects where the team consists of few or more programmers, a lot of things change, new features are still developed, you want to keep scalability, order in code and at the end provide good quality of the product.

In simple terms, role of architecture is that all developers in the team know how they should develop the app. Let’s imagine a situation when few programmers work on the same project, each of them has a different way of implementing code, use different naming conventions, different patterns and so on. Probably at the beginning it will not be very painful, but when the project grows so does mess and inconsistency in it , up to the point when you cannot change anything without side effects.

Actually every project should have a set of development rules. Those rules might not even be called “Architecture”, the most important thing is that all features in application should be written in a consistent way and each developer should understand intentions in his colleague’s code.

What exactly is application architecture ?

There are as many definitions of “architecture” as many programming gurus, so obviously developers can have different views of it. In my opinion architecture is a set of rules regarding specific project. These rules come from agreement between developers and they define how to develop and maintain an application. There are many specific topics which should be covered by architecture. I just described few of them but it doesn’t mean that they are the most important ones.

Architectural pattern

This is probably the most important aspect. Choosing the right pattern which connects user interface with business logic and data model is the key part of the architecture. This will basically influence how your code would look like. There is a wide range of choices, you have MVC, MVP, MVVM. It’s good to know all of the mentioned patterns , know what advantages and disadvantages each of them has and choose the right one for your project. In my opinion, you should avoid mixing different patterns inside one project. You should follow one of them in every screen/feature, this way you can achieve a more consistent looking code in your application. There are a lot of more detailed articles about it, I would recommend following:

Dependency injection framework

Nowadays, most Android projects use DI. Choice and setup of DI framework can also be in scope of your architecture definition. Having DI framework is not a must, you can live without it, but right setup of DI can really make your life easier. There are several libraries which offer ready solutions (e.g. Dagger, Roboguice, Toothpick). You can decide which one will fit best in your project, considering performance and usability. With dependency injection you don’t have to care so much about things like e.g. object creation, passing references, implementing singleton pattern.

Code without DI

public class Configuration {

final private Preferences preferences;
final private RemoteConfig remoteConfig;
final private Logger logger;
final private Cache cache;

public Configuration(
Preferences preferences,
RemoteConfig remoteConfig,
Logger logger,
Cache cache) {

this.preferences = preferences;
this.remoteConfig = remoteConfig;
this.logger = logger;
this.cache = cache
}
}

Code using DI

@Singleton
public class Configuration {

@Inject protected Preferences preferences;
@Inject protected RemoteConfig remoteConfig;
@Inject protected Logger logger;
@Inject protected Cache cache;
}

Set of libraries

Almost every Android project is built on the stack of additional libraries. Android’s API is not always beautiful, so developers often decide to include various libraries. The choice is huge, you have set of libraries almost for everything you need, for example: binding UI elements, handling network calls, creating relational databases, making animations etc. I think it is a good practice to wrap libraries with a layer of abstraction, this way you can avoid dependencies from particular library implementation inside your business logic. Also if you decide to change a library to a different one, you won’t have to do refactoring in the entire project, just inside a single repository. It is not necessary to use this pattern for everything, only for libraries which you are not confident you will be using in the future.

Modularization

It is something that you definitely should consider when drawing your architecture. Separating project into a few modules should give you some profits. You can have abstract layers physically located in different modules, each module has its own build configuration, so you can customize dependencies for each of them. For example UI module doesn’t have to see database or network models, and low level modules don’t have to access libraries for animations, UI binding etc. With Android Gradle Plugin 3.0 or higher, modularization also increases building speed and makes solid fundaments for developing Instant Apps.

Keep in mind, that modularization will be easy to achieve and low at cost at the beginning of project development, but when project is mature it will require much more effort.

Programming language

Does architecture depends on language? Unfortunately this is not always clear. Developers often assume that architecture is independent from programming language, platform, technology. That’s probably right when looking from a high level perspective and thinking of the whole system. However in case of applications which is a single component in the system, you have to take more detailed approach. Each language has a unique way of implementing different patterns. For example, in one language some pattern’s implementation will be elegant, but in another it may look dirty. So, when developers decide on a language, it might have an affect on application components design.

Feature switching

This is not really something that you must have, but in some cases it can be useful. Feature switching basically allows you to configure set of features/screens which should be enabled in the app, this could be done via local configuration or remotely (e.g Firebase Remote Config). FS is pretty useful when you deploy several apps from one base code (whitelabel approach), then you can easily configure features for particular flavor. For example in the company that I work for there is a project from which we deploy 17 apps built on top of a common code base (If someone is more interested in the topic, my collegaue Piotr described it in more details https://medium.com/stepstone-tech/how-to-build-17-apps-with-a-single-android-project-and-not-go-crazy-91d025adf0f0). Those apps have different styling and a different set of enabled features, for such approach FS is indispensable. I especially recommend to have remote feature switching if your application contains functionality dependent on external web services. If external API fails, dependent features in your app will stop working as well. In such situation you should disable broken feature ASAP to avoid annoying users. If you have a remote configuration setup you can just disable given feature in remote console, until the API starts working again.

I just described a few points, but there is obviously more things which should be taken into consideration when designing basic framework of your project. There are at least :

  • Design patterns
  • Communication (data flow)
  • Package structure
  • Naming guideline
  • Test framework setup
  • Build system

If you are more interested in any of mentioned topics then please let me know in comments, I will try to cover them in more detail in next article.

Obviously every project architecture is unique, it means that solution used in “messaging app” will not fit well for “image gallery” or “game”. Each project has it’s specific problems, use cases, functionalities etc.

What determines a good architecture?

So far, we’ve talked about various aspects of architecture for Android application. You might wonder are there any general principles that can help distinguish the bad architecture from the one that gives you profits? I have collected couple points which might be helpful to evaluate the choices:

  • Code readability
  • Cost of refactoring and adding new features
  • Bugs resistance
  • Clear data flow
  • Performance
  • Test coverage
  • Building/compiling speed
  • General understanding of the concept

I will elaborate what each of those points means to me.

Code readability

What does “readable code” mean? I suppose that opinions can differ in this matter. As I see it there are few factors that can describe the quality of the code. They are: significant naming (classes, method variables), good documentation and comments, whole method visible without scrolling (no spaghetti code), consistent code formatting, lack of nested callbacks, avoidance of massive class definitions.

Cost of refactoring and adding new features

If simple component refactoring or new feature implementation is really complex, time consuming and requires changes in many places, this probably means that your design needs improvement.

Bugs resistance

If bug fixing or other changes are causing many side effects it means that probably there are too many mutual dependencies between components. It’s probably good to think about more separation, independence and weak connections between features and functionalities.

Clear data flow

If you have problem tracking the flow of data in an application, if it is not easy to find who is broadcasting an event and who is receiving it, it means that you still have room for improvement.

Performance

In mobile applications, speed and performance are key factors of user’s satisfaction. Developers are using many libraries, loading tons of resources, doing time consuming operations, downloading lot of network data, but everything must be balanced. Before you add a new library to your project it is good to understand what it does under the hood, what performance drawbacks you could experience when using it. There are tools in Android Studio which helps you with performance tracking, so don’t forget to use them regularly.

Test coverage

The product should be tested as thoroughly as possible to avoid potential errors in live product and make the user happy with a well working application. You can write many types of tests for almost everything, however you should avoid writing test only for “testing religion” :) Tests are the most useful when covering real functionality. Notice that even if you have 80–90% of code coverage, it doesn’t mean that your application is fault-proof. Good design of the project, highlighting abstraction layers and appropriate granulation of components should be helpful when writing tests.

Building/compiling speed

This is something important mainly for developers. If your app is one big monolith, making small change and building project takes way too long, it means that you should search for some improvement here as well.

General understanding of the concept

As I said before, architecture of application is a contract between developers. Of course architecture could be also imposed by Technical Leader or Software Architect, however everyone working on the project should understand and accept that contract. Let’s assume that half of development team like proposed architecture, but the rest do not. In such situation you should keep searching for compromise.

When something does not fit

Obviously, there are no perfect solutions, but it doesn’t mean that you should not strive for them. You often find yourselves in a situation when your architecture works perfectly for implementation of most of the features but there are still some corner cases that just don’t fit. Sometimes you need to implement a simple use case and when you try to do it accordance with architecture, the effect could look like an overkill. The question is, should you always follow architecture guidelines or can you sometimes make exceptions if necessary ? The answer is up to you. The main goal of having defined architecture is to have order in the project and consistent way of doing things. So, if some minor exceptions will not destroy the whole concept, then you probably could live with that. In turn if there are more and more exceptions, then probably you should make some modification in architecture to solve them. Sometimes it’s good to rethink your basic assumptions, decide which aspects are the most important and then decide how to handle unusual stuff.

Summary

You should remember that architecture design is unique for a specific project. As I mentioned before, copying architecture from one project to another will not usually work good, the exception here is when both projects have similar functionalities. Architecture design depends on goals you want to achieve and problems you want to avoid. I assure you that choosing perfect architecture in first approach is almost impossible, it requires continuous trial, experimentation, drawing conclusions and consistent introduction of design improvements. Basically you need a few design iterations to achieve acceptable solution.

Software engineering is a very young discipline of science, a lot of questions have no yet been answered, so a good developer should not only be a coder, but should also be a researcher, who keeps experimenting and trying new approaches.

This was my first publication. Hope it was helpful. I will be very grateful for any hints or comments :)

Thanks to my colleagues from the StepStone :)

Read more about the technologies we use or take an inside look at our organisation & processes. Interested in working at StepStone? Check out our careers page.

--

--

Piotr Głębocki
the-stepstone-group-tech-blog

Senior Android Developer at VIMN. Interested in software engineering, design, architecture, Android development, technology, music.