When I see Android code like this, it makes me feel uncomfortable:
class Foo {
private final Context mContext;
public Foo(Context context) {
mContext = context;
}
....
}
You may be thinking: “What on earth are you talking about? That’s a super common pattern in Android development to pass Context around from class to class. We need a Context instance for all sorts of things like accessing system services etc! Oh wait, I get it, you’re talking about the m prefix for class member variable names which is specific to Java code in Android!”
No, I’m not talking about the weird and unnecessary “Hungarian notation” prefix in mContext, although I agree it is an eyesore, but that’s a topic for a different blog post! ;-)
tl;dr:Inject/pass explicit types (e.g. LayoutInflater) to classes where they are needed, instead of passing Context all over the place.
I find the pervasiveness of this habit of passing a Context instance into class constructors and method parameters confusing and disturbing. It’s unfortunate that the Android framework provided the Context base class as a kind of god object or together with things like getSystemService() as a kind of service locator - i.e. it’s the class that knows and does everything!
Why is it a bad idea to pass Context to a class’s contructor or a method, when everyone does it and you can’t do anything in Android without a Context?
Some examples of issues:
If I’m not the original author of this code, I will wonder: which context is this? Activity, Application, Service?
Can I hold a reference to this context in case I need it later? No, not unless it’s the application context. But how do I know for sure
this is the application context? Especially if this class is used in different context further down the object graph and I don’t know who the caller is. It will eventually cause leaks somewhere e.g. activity leak, because some class will inadvertently hold a reference to the Activity.
Can I use LayoutInflator on it? No, not if it’s not the context of the activity I’m expecting.
It’s a violation of the Law of Demeter. For example, when I write the unit test for class Foo which takes Context as a constructor dependency, how do I know which parts of Context I need to mock for the test to legitimately pass? If the class is sufficiently complex, I’ll just have to “guess” and figure it out by trial and error. Worse, I may have to mock A to return a mock of B to return a mock of C… Now the unit test is becoming unwieldly.
A solution
Assuming you’re convinced at this point that it’s a bad idea to pass Context down several levels from class to class, what can we do to improve the situation?
Apply this simple principle: communicate your intention explicitly in your code.
In other words, in many cases, you don’t really want the Context reference itself, you just want to use it to invoke some action or retrieve some system service. In that case, rather pass the exact service(s) explicitly to the constructor of the class instead of Context.
As a simple example to demonstrate the point, consider this snippet from a simple hypothetical list adapter:
We pass the Context into the adapter, but the code doesn’t actually need a Context, it really needs a LayoutInflater instead! There is no need carrying the Context around all over the place just in case we need it some day.
Let’s refactor this code to make it slightly easier to understand, reason about and slightly easier to unit test:
private final LayoutInflater mLayoutInflater;
private final String[] mValues;
public MyListAdapter(LayoutInflater layoutInflater, String[] values) {
this.mLayoutInflater = layoutInflater;
this.mValues = values;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = mLayoutInflater.inflate(R.layout.rowlayout, parent, false);
...
Even if you need need to retrieve multiple objects from Context and not just one as in this example, then it’s still better to pass separate references to those objects.
Of course there are many exceptions to this advice, because often you’ll be forced to pass Context around through several layers of an object hierarchy because some leaf node which you didn’t write requires it, but even then, you can still be more explicit with your paramter types (and/or parameter names) to communicate your intention more clearly.
For examle, let’s say our list adapter really needs the activity Context, then I’d propose refactoring the code to accept an Activity instance instead, so it’s clear what kind of Context we’re expecting here:
Or if you’re using Dagger for dependency injection, you could use qualifier annotations like @ActivityContext and @ApplicationContext to differentiate (or even better if possible, separate your Dagger scopes to make it impossible to inject an Activity reference into a service that will outlive the activity…)
Note to self: how to install Oracle JDK 8 and Android Studio on Ubuntu 14.04 64 bit:
When I installed Ubuntu using the x86_64 image, I realized that Android Studio and the Android SDK tools don’t just install on the default Ubuntu 64-bit image, it’s easier to use the 32-bit image, but I wanted to get it working anyway, so here’s the steps for prosperity.
First install some dependencies needed by Android Studio and the Android SDK on Ubuntu x86_64:
In the previous post, I described one aspect of modularity: how should you split your app into multiple packages/directories? In this post, I’m continuing on the topic of software modularity…
Too often, not enough thought is given to applying SRP on the module level. In other words,
a large application should be broken into many small modules instead of growing it into a
large monolithic application over time.
Why?
Some people object to splitting an application into physically separate modules using
arguments like “that’s what packages/namespaces are for”, but that’s not necessarily
enough. Properly structuring the code into packages is definitely a good idea, but we
need to do more. A large application easily becomes a monolithic mess that is
hard to maintain, because changes in one area affect other unrelated areas when
components are so intertwined that it’s difficult to see the boundary between layers.
A modular design allows us to grow the application by adding new modules, with very
little impact to existing modules. That means that separate teams can focus on the
modules applicable to their areas of the application, without being distracted by the
complexity inside unrelated modules.
What is modularity?
Modularity is the degree to which a
system’s components may be separated and recombined. A module is a collection of
related concerns/components. Modules are independent and typically communicate in
a loosely-coupled fashion, e.g. using an event bus
or well-defined interfaces.
One big advantage of modular design is that it limits the amount of code you need
to consider (i.e. the size of the model you need to load into your brain) when working
on something. You don’t need to understand the entire codebase to see how your change
is going to affect the entire system, you can focus on the module alone, and as long as
the module’s API/interface doesn’t change you can be fairly confident that you’re not
breaking something else.
Goals
What are we trying to accomplish? Some random goals of a modular design:
Maintainability: a smaller code base is simply easier to understand and therefore
easier for maintain.
Facilitates teamwork by breaking system down into smaller pieces. A team doesn’t have
to understand or consider the entire application, only their own module(s) and the
interfaces of external modules. Separate teams can work on separate modules without
stepping on each others toes.
Flexibility: can replace/refactor a module’s implementation without affecting the
rest of the system.
Composition: can re-configure an application to include/remove modules as necessary.
Composition of modules can either happen at run-time or statically during compile-time,
for example modules are merged into a single project before compiling. For example,
ideally, new large features would be encapsulated in its own module. When the feature
(experiment) is removed, the separation is clear.
Re-usability: clearly defining and limiting a module’s responsibility means it’s more
likely to be usable in other applications.
Enforces architectural layer integrity: by separating concerns using modules, it’s
easier to enforce the
Dependency Rule
which says that “source code dependencies can only point inwards”, for example, your
“networking layer” should not know or care about UI concepts like Activities etc, and
similarly, the Activity code should not attempt to do networking stuff directly. By having
physically separate modules, it makes it easier to visualize the architectural layers of
the application and to understand where a change in the code needs to go.
How should you structure your code into separate directories/packages/namespaces?
Another way to phrase that question: How should you modularize your code?
Even if your medium-sized app is small enough that you don’t need physically separate modules,
you likely still need to organize your code into virtual modules by using namespacing,
eg. Java package names. The first and easiest thing you can do to prevent any sufficiently large
codebase from becoming a huge unmaintainable mess is to keep the code modular.
Keep separate things separate and only keep related things together.
This is not a controversial idea. Everyone knows about
“Separation of Concerns” (Soc).
I’m sure we can all agree that SoC is a good idea, however where we may start disagreeing
very quickly once we dig into the details, is exactly what “concerns” should we separate?
How do you decide where to draw the boundary lines between the classes/components of your code?
A very common pattern that I see in Android, AngularJS and other platforms, is to organize
classes by their “type”. For example many, if not most, AngularJS sample apps split the
.js files into directories like these:
controllers
directives
services
As another example, let’s take a hypothetical Android “TODO list app”, which might be split
up into directories like this:
adapters
TaskListAdapter
interfaces
LoginResultHandler
model
Task
LoginResult
presenters
AddEditTaskPresenter
LoginPresenter
TaskListPresenter
utils
LoginAPI
TodoDatabase
views
LoginActivity
TaskListActivity
AddTaskActivity
EditTaskActivity
(Note: my class names above are contrived, a real application will likely need more and different classes.
My point here is the directory naming: adapters, views, etc.)
To me the above naming approach seems absurdly arbitrary, because it gives you no useful insight or
visibility into the structure, features, size or scope or any other characteristic of the code.
It only tells you what kind of components (e.g. activities, services, adapters) were used, which
is pretty uninteresting by itself. You might as well separate the classes alphabetically or by date
or by size or any other equally meaningless aspect.
The logical areas / features of the application, namely “Login”, “List tasks” and “Add task” are
scattered all over the place. If I need to make a change to the “Add Task” code, the structure of
the packages don’t assist me at all, in fact they only obscure the structure of the application unnecessarily.
An analogy I like to use: how do we apply SoC when we organize the books in a library? Would it make
sense to organize all the books in a library by the color of their cover? Or by their size?
Thickness? Alphabetically by title or author? No, of course not: books are mainly arranged by subject.
Why would I need LoginActivity to be in the same package or namespace as the completely unrelated
TaskListActivity, while their related partner classes, say LoginPresenter and TaskListPresenter
respectively, are in a separate package?
Java packages in conjunction with protected or
package-private
access control (or C# namespaces in conjunction with the internal keyword) provide a mechanism
to isolate and hide related code that should not be accessed externally (albeit a slightly weak
boundary when compared with using physically separate modules, especially in C# where there is no
package-private concept). Consider this when separating code by using packages - do the classes in
the same package really need implicit mutual visibility? In other words, do they really belong together?
It makes a lot more sense to structure the root level of the code according to the separate logical
units, or “modules”, of the app:
data
Task
TodoDatabase
edit
EditTaskActivity
AddTaskActivity
AddEditTaskPresenter
login
LoginActivity
LoginAPI
LoginPresenter
LoginResult
LoginResultHandler
list
TaskListActivity
TaskListAdapter
TaskListPresenter
(Of course, you’re still free to arbitrarily namespace the levels below that into whatever sub-packages
you like, like views, services, utils etc.)
So how did I decide on these directories? Isn’t this also arbitrary? No, the code is now divided into
three logically independent modules: login, add/edit and list. (The data module is also separated
out because it’s shared by both the edit and list modules.)
A module is a logical standalone unit of the application. For example, at least in principle,
the “Add/edit task” functionality can exist and operate independently without having to consider
the “Login” and “List tasks” functionality at all. If I’m a developer tasked to work on the
“Edit task” functionality, I know where I have to focus my attention in the code. I don’t need
to build a mental model of the login or list code in order to understand and work on the edit code.
In John Papa’s Angular Style Guide, he describes the
LIFT and
Folders-by-Feature Structure
guidelines for naming the directories in a project:
“Create folders named for the feature they represent… Do not structure your app using
folders-by-type. This requires moving to multiple folders when working on a feature and
gets unwieldy quickly as the app grows to 5, 10 or 25+ views and controllers (and other features),
which makes it more difficult than folder-by-feature to locate files.”
LIFT principle: structure your app such that you can
Locate your code quickly
Identify the code at a glance
keep the Flattest structure you can
Try to stay DRY (Don’t Repeat Yourself)
In this post, I’ve only considered using directories/packages as a way to divide code into logical
modules, but in a larger application (especially when working with a team or even multiple teams)
the same concepts would apply when deciding how to break the application up into physically
separate modules, e.g. separate .jar or .dll files. I will discuss modularization more in
future posts, e.g. how do we define a module, what are the benefits of modularization,
how does modularization relate to coupling and cohesion.
% setopt EXTENDED_GLOB
for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
done
Re-open the iterm2 window to see if all the dotfiles are set up correctly (i.e. zprezto modules are loading without errors).
Set the theme (I use steeef built-in theme), modules (like git) etc in .zpreztorc:
% vi $ZDOTDIR/.zpreztorc
For example, to change the theme in .zpreztorc from the default, look for the following line and change sorin to steeef:
zstyle ':prezto:module:prompt' theme 'sorin' # <-- change 'sorin' to 'steeef'...
After setting up vi key bindings, ^R for history substring search stopped working. View the current key bindings - this confirms ^R is currently bound to redisplay instead of history-incremental-search-backward:
% bindkey -L | grep '\^R'
bindkey "^R" redisplay
I added this line to my ~/dotfiles/.zshrc file to enable ^R history search again: