Modern Android Application Architecture & Development: Part 2 – Architecture Basics, Project Organization and Clean Code

In continuation of the series of posts with our friends on the Nordstrom Technology team we’re going to be creating a simple StackOverflow client utilizing the technologies discussed in Part 1 – Tools & Libraries.

The image to the right is the final screen that will be presented to the user.

You can access part 1 on GitHub at:
Screen Shot 2015-06-10 at 2.18.16 PM

git clone https://github.com/Liffft/StackRX.git
cd StackRX
git checkout stack_rx_1_architecture_basics

Before we jump into code let’s take a look at the anatomy and organization of the project.

StackRX Client Application vs StackRX Services

As mentioned in Part 1 we completely decouple the service layer from the view layer.  Projects that combine these become extremely unwieldy, limit code reusability and are much harder to test.

Android specific logic will never exist within the service layer.  Keep in mind that another team may use the service layer for their project so keep it clean.
Screen Shot 2015-06-10 at 2.24.36 PMTo create the services project simply right click File–>New–>New Module

In the editor be sure to select ‘Android Library’. Also make sure the library is included in your app build.gradle as a dependency

dependencies {
compile project(‘:stackrx-services’)
}

The services build.gradle should include any libraries shared between the application front-end and the services layer.

build.gradle (app)                                                                      build.gradle (services)

Screen Shot 2015-06-10 at 2.26.44 PMScreen Shot 2015-06-10 at 2.26.36 PM

Notice how we have the new Material Design cardview library only in the app dependencies but the services library contains Roboguice which is used both in the services and app.

Package Structure

Android applications are often organized by object type but we organize by feature.

Screen Shot 2015-06-10 at 2.29.52 PM

We do this for the following reasons:

  •  As projects get more complex, standard naming is imperative.  As we progress in the project development you will notice that all packages resemble each other in both the unit tests, client code and service layer.  This prevents problems like a fragment package with 30 fragment files with no context or classes being in packages for no rhyme or reason.
  • Coming into a large Android project can be hell.  As a new developer getting your first commit can be overwhelming.  However if the application is broken into features it’s much easier to get started.  Need to make changes to the shopping page?  Most likely it will be in the shop->fragment package. Some oversight will be needed for shared objects.
  • We will touch on this further, but fragment classes should be as small as possible.  Complex things such as adapters should be moved into their own packages and classes when possible.  This leads to more testable code in general.

Let’s Write Clean Code Together.  Android Code Best Practices.

We’ve spent a lot of time thinking of ways to keep our code base as uniform and readable as possible.  Following good practices from day #1 will reduce code complexity, tech debt and refactoring time.  Many projects race to release but are so disorganized and non-uniform a rewrite is almost necessary afterwards.

Code Grouping and Organization

Android Studio supports regions; a little known feature that really helps organize classes.

Pulling open StackRXActivity (or any other classes in the view layer) you will see our code regions defined:

Screen Shot 2015-06-10 at 2.32.35 PM

Figure 1                                                                       Figure 2

These are just like pragma marks in other languages.  To collapse the regions hit

Command->Shift->Minus

to grow the region

Command->Shift->Plus

The categories above are the same for every fragment, adapter, activity etc.

This won’t be crystal clear initially, but I’ll explain each region and its purpose.

INJECTED CLASSES

This section is for dependency Roboguice injected classes

@Inject UserSession
private UserSession mUserSession;

INJECTED VIEWS

This section is for injected Roboguice views.  There should be no view.findByViewId’s littered throughout the code

@InjectView(R.id.drawer_layout)
private DrawerLayout mDrawerLayout;

LOCAL CONSTANTS

Local constants are immutable constants pertaining to the class.  If they are string constants and used in other classes they should live in an AppConstants

private static final String TAG = QuestionFragment.class.getSimpleName();

CLASS VARIABLES

Local class variables.  We tend to perserve the ‘m’ prefix.

private QuestionFragment mQuestionFragment;

CONSTRUCTOR

Any constructors associated with the class

public StackRXActivity () {}

LIFE CYCLE METHODS

All life cycle methods.  For fragments and activities order matters.  Ex: onCreate should never be after onDestroy

onAttach(Activity)
onCreate(Bundle)
onCreateView(LayoutInflater, ViewGroup, Bundle)
onActivityCreated(Bundle)
onViewStateRestored(Bundle)
onStart()
onResume()
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()

@Override
protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
}

WIDGET

Widget is used as a catch-all for widgets within the screen.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
}

LISTENERS

Listeners are all component type listeners in the view (OnClickListener, OnTextChangeListener)
Listeners should always be separate classes and never be inline in the life cycle methods.  Also set the listener in the code and never implement or extend on the class level.

private class OnLoginButtonClickListener extends View.OnClickListener {
        @Override
        public void onClick (View v) { }
}

EVENTS

Events are triggered by the EventBus.  All fragment/activity level uses of the event bus are captured here

public void OnButtonSelectEvent(ButtonSelectEvent buttonSelectEvent) { }

LOCAL METHODS

Local methods pertaining to the fragment

public void AddItemToList(String item) {
...
}

OBSERVERS

Observers are listening for observables that have sent down a single typically from network calls

private class GetQuestionObserver implements Obvserver {
…
}

ACCESSORS

Getters and setters the class

public void getItemCount () {
       return itemCount;
}

<b>INNER CLASSES</b>

Inner classes that are not discussed above


private class SomeInnerClass {
}

Variable Naming

Let Android Studio name your variables for you! Rather than using a shorthand like  "adaptor" or "qda" for a “QuestionDetailAdapter” simply start typing the first letter of the class name to have it automatically named that.

We use the m prefix on all class level variables.  While this is always up for debate, you never have any of the time wasting this.variableName on constructors.

Ex:

public QuestionDetailAdapter(Context context) {
       context = context;      // no!
       mContext = context;  // nice!
}

You can configure Android Studio to automatically prepend the ‘m’ right when you type the variable name

Android Studio-->Preferences-->Edit-->Code Style-->Java-->Code Generation-->Field-->Name Prefix-->m

Layout Naming Conventions

Too many projects do not name layouts or layout ids consistently.  Our convention is as follows:

The layout name always matches the class exactly.  This makes it is incredibly clear which layout file is for which class.

Ex: QuestionFragment.java → question_fragment.xml

Variable naming should always match the layout name appended with what it is and its type.

How many times have we seen:

R.id.question or R.id.sign_in

This gives no context.

Instead:

R.id.question_fragment_question_list_view or

R.id.question_fragment_sign_in_button

Do you have any other tips / tricks for keeping your project sane and beautiful?  Drop us a comment!  Stay turned for Part 3:  Dependency Injection, RxJava, DAO’s and more!

Thanks for reading. If you have any questions or would like to know more about working with the Nordstrom Technology team feel free to shoot us an email!

2 thoughts on “Modern Android Application Architecture & Development: Part 2 – Architecture Basics, Project Organization and Clean Code

Leave a comment