Monday, 23 November 2015

Book Summary: Head First Design Patterns, by Eric Freeman and Elisabeth Robson

Below is a summary of the main Design Patterns and Design Principles covered in the Head First Design Patterns book. Excellent book by the way! A must read for all software engineers.

Design Patterns

Strategy
  • Encapsulates interchangeable algorithms/behaviours and uses delegation to decide which one to use.
  • Allows the algorithm to vary independently from the clients that use it.
Observer
  • Defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are updated and notified automatically.
Decorator
  • Wraps another object dynamically and provides additional behaviour for it.
  • Provides a flexible alternative to subclassing for extending functionality.
  • Doesn't alter the interface but adds responsibility.
Factory Method
  • Defines an interface for creating an object, but lets subclasses decide which class to instantiate.
  • Lets a class defer instantiation to subclasses.
Abstract Factory
  • Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
Singleton
  • Ensures a class has only one instance, and provides a global point of access to it.
Command
  • Encapsulates a request as an object, thereby letting you parameterise other objects with different requests, queue or log requests, and support undoable operations.
  • Decouples an object making a request from the one that knows how to perform it.
Adapter
  • Wraps an object and provides a different interface to it.
  • Converts the interface of a class into another interface the clients expect.
  • Lets classes work together that couldn't otherwise because of incompatible interfaces.
Facade
  • Wraps a bunch of objects to simplify their interface.
  • Provides a unified interface to a set of interfaces in a subsystem.
  • Defines a higher-level interface that makes the subsystem easier to use.
Template Method
  • Encapsulates algorithms.
  • Defines the skeleton (/steps) of an algorithm in a method, deferring some steps to subclasses.
  • Subclasses decide how to implement steps in an algorithm (without changing the algorithm's structure).
Iterator
  • Provides a way to traverse/access the elements of an aggregate object sequentially without exposing its internal structure.
  • Takes the job of iterating over an aggregate and encapsulates it in another object.
Composite
  • Provides a structure to hold both individual objects and composite objects.
  • Lets clients treat individual objects and collections/compositions of objects uniformly.
State
  • Allows an object to alter its behaviour when its internal state changes.
  • Encapsulates state into separate classes and delegates to the object representing the current state.
Proxy
  • Wraps another object to control access to it.
  • Acts as a representative for another object.

Design Principles

Encapsulate what varies – Identify the aspects of your application that vary and separate them from what stays the same. Take the parts that vary and encapsulate them.

Program to an interface, not to an implementation.

Composition over inheritance – Favour composition over inheritance.

Loose coupling – Strive for loosely coupled designs between objects that interact.

Open-Closed – Classes should be open for extension, but closed for modification.

Dependency inversion
  • Design upon abstractions. Do not depend on concrete classes.
  • High-level components should not depend on low-level components; rather, they should both depend on abstractions.
  • No variable should hold reference to a concrete class.
  • No class should derive from a concrete class.
  • No method should override an implemented method of any of its base classes.
Principle of least knowledge
  • Talk only to your immediate friends.
The Hollywood Principle
  • Don't call us, we'll call you.
  • High level components call low level components, and not vice-versa.
Single responsibility
  • A class should have only one responsibility.
  • A class should have only one reason to change.

Sunday, 4 October 2015

Android: How to pass data from DialogFragment to Activity

So you've started a DialogFragment from within an Activity and want to request an action or pass data from the DialogFragment to the Activity. The best, cleanest way I find to do so is by means of local broadcasts. Here's how...

First, define a BroadcastReceiver in your Activity as follows:

private class LocalBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // safety check
        if (intent == null || intent.getAction() == null) {
            return;
        }

        if (intent.getAction().equals("SOME_ACTION")) {
           doSomeAction();
        }
    }
}

Second, declare an instance of LocalBroadcastReceiver in your Activity, as follows:

private BroadcastReceiver localBroadcastReceiver;

Third, instantiate the BroadcastReceiver in the activity's onCreate(Bundle) method:

localBroadcastReceiver = new LocalBroadcastReceiver();

Fourth, register for the activity to listen out for the local broadcasts in the activity's onResume() method:

LocalBroadcastManager.getInstance(this).registerReceiver(
        localBroadcastReceiver,
        new IntentFilter("SOME_ACTION"));

Fifth, unregister the broadcast receiver in the activity's onPause() method:

LocalBroadcastManager.getInstance(this).unregisterReceiver(
        localBroadcastReceiver);

Sixth and final, send the broadcast from wherever makes sense in your DialogFragment, as follows:

LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(
    new Intent("SOME_ACTION"));

Sunday, 27 September 2015

Android: How to check that the device's internet connection is able to transfer data

Checking whether an Android device is connected to the internet is straightforward. Sadly, checking whether the device's internet connection is actually working and able to transfer data is not so straightforward. We'll cover both things in this tutorial.

Firstly, here's the method to check whether the device has an internet connection:

boolean isActiveNetworkConnected(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

    return networkInfo != null
        && networkInfo.isAvailable()
        && networkInfo.isConnected();
}

Now, how to check that the internet connection is actually able to transfer data? One way to do this is to ping a web location of your choice, as follows:

boolean isGoogleReachableWithPing() {
    try {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("/system/bin/ping -c 1 www.google.com");

        int exitValue = process.waitFor();

        return exitValue == 0;
    } catch (Exception ex) {
        return false;
    }
}

Sadly, the ping command works on some Android devices but not on others (see here for discussion). An alternative approach is to use the InetAddress class, as follows:

boolean isGoogleReachableWithInetAddress() {
    try {
        InetAddress inetAddress = InetAddress.getByName("www.google.com");

        return inetAddress != null && !inetAddress.equals("");
    } catch (Exception ex) {
        return false;
    }
}

Putting all these methods together, what you want is this:

boolean isActiveNetworkConnectedAndWorking(Context context) {
    return isActiveNetworkConnected(context)
        && (isGoogleReachableWithPing() || isGoogleReachableWithInetAddress());
}

You can find all of the above-mentioned methods in the NetworkInspector class in the android-utils repository.

Saturday, 1 August 2015

Book Review: The Nomadic Developer, by Aaron Erickson

Decent book on what it means to be a technology consultant and how it does (or should) differ from the role of a contractor. I'm not a technology consultant so I was reading it from an outside perspective and found the contents of the book useful still. I liked some of the general tips in the book. For example, the importance of personal appearance, being good at interviews, always learning, being easy to work with, having energy for the job, and maintaining a strong network of people inside and outside of your current employment.

Here's some quotes from the book which stood out for me in particular:

"Seniority isn't measured in years at the company, but in the number and quality of relationships developed over time."

"Starting your network when you suddenly need a new position is not the best time."

"With respect to appearance generally, this tip really comes down to the fact that people would rather work with folks who are physically, mentally, and emotionally well than people who are not."

"One of the things that separates a contractor from a consultant is the former is there to do a specific job for a specific amount of time. The latter, the consultant, is there to provide other humans with advice and guidance in addition to doing work."

"Without any discernible process, there is no way to track with consistency the accuracy of estimates, progress against a plan, or any other metric that would allow you to know how a project is doing."

"Being willing to be fired because you stand up for what you believe is right (pushing back timelines, ensuring quality, and so on) is a powerful thing."

Saturday, 7 March 2015

Go To: Software Superheroes, by Steve Lohr

I bought this book back in 2002 and only got around to reading it in 2015! Good thing too as it probably wouldn't have made much sense back then! Good book on the evolution of software and programming from the 1950s through to the 2000s I thought. I liked the last few chapters in particular which chronicled the birth of the internet and web programming and then the introduction of Java and lastly the growth of Apache and the open source community.

Sunday, 23 November 2014

Android, SQLite: EXPLAIN QUERY PLAN method for UPDATE queries

If you're using the SQLiteDatabase.update(String table, ContentValues values, String whereClause, String[] whereArgs) method for updating records in your local database, here are a couple of helper methods to compose and execute EXPLAIN QUERY PLAN commands for analysing your UPDATE queries:

/**
 * Composes and executes an EXECUTE QUERY PLAN command
 * for the UPDATE query that would be composed from the parameters provided.
 * 
 * @see {@link SQLiteDatabase#update(String, ContentValues, String, String[])} for a description of this method's parameters.
 */
private static void explainQueryPlanForUpdateStatement(SQLiteDatabase database, String table, ContentValues contentValues, String selection, String[] selectionArgs) {

  final StringBuilder sb = new StringBuilder();
  sb.append("EXPLAIN QUERY PLAN UPDATE ");

  sb.append(table);

  sb.append(" SET ");

  final Set keys = contentValues.keySet();

  boolean firstKey = true;

  for (String key : keys) {
    if (!firstKey) {
      sb.append(", ");
    }

    sb.append(key);
    sb.append(" = ");

    if (contentValues.get(key) == null) {
      sb.append("NULL");
    } else if (contentValues.get(key) instanceof Boolean) {
      Boolean value = (Boolean) contentValues.get(key);

      if (value.booleanValue()) {
        sb.append("1");
      } else {
        sb.append("0");
      }
    } else if (contentValues.get(key) instanceof Number) {
      sb.append(contentValues.get(key).toString());
    } else {
      sb.append("'");
      sb.append(contentValues.get(key).toString());
      sb.append("' ");
    }

    firstKey = false;
  }

  if (!TextUtils.isEmpty(selection)) {
    sb.append(" WHERE ");
    sb.append(selection);
  }

  executeExplainQueryPlanStatement(database, sb.toString(), selectionArgs);

}

/**
 * Executes sql using database
 * and prints the result to logs.
 * 
 * @param database the {@link SQLiteDatabase} instance to use to execute the query.
 * @param sql is an EXPLAIN QUERY PLAN command which must not be ; terminated.
 * @param selectionArgs the values to replace the ?s in the where clause of sql.
 */
private static void executeExplainQueryPlanStatement(SQLiteDatabase database, String sql, String[] selectionArgs) {

  final Cursor cursor = database.rawQuery(sql, selectionArgs);

  if (cursor.moveToFirst()) {
    final int colIndexSelectId = cursor.getColumnIndex("selectid");
    final int colIndexOrder = cursor.getColumnIndex("order");
    final int colIndexFrom = cursor.getColumnIndex("from");
    final int colIndexDetail = cursor.getColumnIndex("detail");

    final int selectId = cursor.getInt(colIndexSelectId);
    final int order = cursor.getInt(colIndexOrder);
    final int from = cursor.getInt(colIndexFrom);
    final String detail = cursor.getString(colIndexDetail);

    Log.d(TAG, sql);
    Log.d(TAG, String.format("%d | %d | %d | %s", selectId, order, from, detail));
  }

  cursor.close();

}
UPDATE: These methods are now contained in the QueryPlanExplainer class in this repository.

Saturday, 22 November 2014

Android, SQLite: EXPLAIN QUERY PLAN method for SELECT queries

If you're using the SQLiteDatabase.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) method for performing your local database queries (or one of the similar SQLiteDatabase query methods), here are a couple of helper methods to compose and execute EXPLAIN QUERY PLAN commands for analysing your SELECT queries:

/**
 * Composes and executes an EXECUTE QUERY PLAN command
 * for the SELECT query that would be composed from the parameters provided.
 * 
 * @see {@link SQLiteDatabase#query(String, String[], String, String[], String, String, String, String)} for a description of this method's parameters.
 */
private static void explainQueryPlanForSelectStatement(SQLiteDatabase database, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {

  final StringBuilder sb = new StringBuilder();
  sb.append("EXPLAIN QUERY PLAN SELECT ");

  if (columns == null || columns.length == 0) {
    sb.append(" * ");
  } else {
    boolean firstColumn = true;

    for (String column : columns) {
      if (!firstColumn) {
        sb.append(", ");
      }

      sb.append(column);

      firstColumn = false;
    }
  }

  sb.append(" FROM ");
  sb.append(table);

  if (!TextUtils.isEmpty(selection)) {
    sb.append(" WHERE ");
    sb.append(selection);
  }

  if (!TextUtils.isEmpty(groupBy)) {
    sb.append(" GROUP BY ");
    sb.append(groupBy);
  }

  if (!TextUtils.isEmpty(having)) {
    sb.append(" HAVING ");
    sb.append(having);
  }

  if (!TextUtils.isEmpty(orderBy)) {
    sb.append(" ORDER BY ");
    sb.append(orderBy);
  }

  if (!TextUtils.isEmpty(limit)) {
    sb.append(" LIMIT ");
    sb.append(limit);
  }

  executeExplainQueryPlanStatement(database, sb.toString(), selectionArgs);

}

/**
 * Executes sql using database
 * and prints the result to logs.
 * 
 * @param database the {@link SQLiteDatabase} instance to use to execute the query.
 * @param sql is an EXPLAIN QUERY PLAN command which must not be ; terminated.
 * @param selectionArgs the values to replace the ?s in the where clause of sql.
 */
private static void executeExplainQueryPlanStatement(SQLiteDatabase database, String sql, String[] selectionArgs) {

  final Cursor cursor = database.rawQuery(sql, selectionArgs);

  if (cursor.moveToFirst()) {
    final int colIndexSelectId = cursor.getColumnIndex("selectid");
    final int colIndexOrder = cursor.getColumnIndex("order");
    final int colIndexFrom = cursor.getColumnIndex("from");
    final int colIndexDetail = cursor.getColumnIndex("detail");

    final int selectId = cursor.getInt(colIndexSelectId);
    final int order = cursor.getInt(colIndexOrder);
    final int from = cursor.getInt(colIndexFrom);
    final String detail = cursor.getString(colIndexDetail);

    Log.d(TAG, sql);
    Log.d(TAG, String.format("%d | %d | %d | %s", selectId, order, from, detail));
  }

  cursor.close();

}

UPDATE: These methods are now contained in the QueryPlanExplainer class in this repository.