Jekyll2018-08-02T07:11:51-04:00http://jameskbride.com/Jim KirkbrideSoftware developer, dad, geek. Not necessarily in that order.
Standing Teams - Pros and Cons2017-09-03T00:00:00-04:002017-09-03T00:00:00-04:00http://jameskbride.com/2017/09/03/standing-teams<p><em>Bring the work to the team, not the other way around.</em></p>
<p>This is the main concept behind “standing teams”, and there are certainly merits worth considering behind it. I’ve been part of many teams over my career as a software developer, including one which ended up becoming a standing team for a few projects. Having said that I have some observations on the the merits of standing teams, both positive and negative, that I’d like to share.</p>
<p>Before diving into standing teams however, let’s take a step back and talk about how teams are most often formed and some of the effects of this model.</p>
<h3 id="the-standard-model">The “Standard Model”</h3>
<p>Frequently, when a new project is identified, prioritized, and finally green-lit a team of individuals is gathered and formed specifically for that project. That is, the project is created first, followed by the creation of the team, which I’ll refer to here as the “Standard Model”. Most of the time this involves scouring the region for available contractors who have the skillsets required by the project, or if is it an in-house project, pulling individuals from other projects and putting them all together for the new effort.</p>
<p>Once the team has been assembled a period of time follows in which the members of the team learn about the project, each other, and how they’ll work together to deliver the project. This is frequently referred to as <a href="https://en.wikipedia.org/wiki/Tuckman%27s_stages_of_group_development">“Forming, Storming, Norming, and Performing”</a>.</p>
<p>The first three phases of team development can often be turbulent, as people who haven’t worked together previously learn the dynamics of the new group and the project domain, and the team velocity may not be consistent. Once the team hits the “Performing” phase of its development velocity tends to increase and become more consistent, until it eventually levels out and becomes somewhat predictable. This is of course the goal, as project leadership needs a way to provide some kind of estimate for how long it will take to complete and deliver features.</p>
<h3 id="the-standing-team">The Standing Team</h3>
<p>The Standard Model has been around since the dawn of software development, and it is still used today for a variety of reasons, some more dubious than others. One thing people noticed about this model however, is the aforementioned turbulence of the team forming, storming, and norming. <em>“Rather than undergoing that turbulence on every project”</em>, they said, <em>“wouldn’t it be great if we could skip straight to performing?”</em></p>
<p>One way to accomplish this is to keep the team together from one project to the next. When one project is completed the entire team simply begins the next one together. No need to break up an already performing team, no need to spend time and effort building a new team. With this model, the idea is that the team will already have formed, stormed, and normed, and so they can move straight into performing on the new project.</p>
<h3 id="pros">Pros</h3>
<p>There are definite benefits to this model that can make it appealing, especially for members who are looking for some stability, and for project leaders who want high performing teams right out of the gate.</p>
<ul>
<li><strong>Forming, Storming, Norming: Been There, Done That:</strong> This one definitely has value; a team that moves to a new project together already knows how to work together. In my experience on a standing team we were able to skip the usual hiccups in personality conflicts, disagreements on style and approach, and adjustments to our roles. We had worked together for so long that these were simply not issues anymore. Even better, we got along well and enjoyed working together. All of this combined to make us a tight-nit, functioning team.</li>
<li><strong>Hit the Ground Running:</strong> Given that we knew how to get the work done we were able to focus on the problem at hand and ramp up quickly, even though the domain was different from our previous project. In fact, in one engagement our new Product Owner was amazed to see how quickly we were able to break down work, estimate, and implement user stories. Having worked together already we knew how to go about our business and could focus on delivery.</li>
<li><strong>Skillsets are a Known Quantity:</strong> Due to our long association there was no question about what everyone on the team was good at. We knew what we knew, and what we didn’t know. We also knew that certain individuals were better at some tasks, and to pair with them when that focus was needed. Need a focus on front-end? Pair with Cory. Need to crank up velocity? Pair with Jonathan. Need an assessment of the architecture and its pitfalls? Talk to John. Need to figure out how to test something? I’m your guy. Because we paired everyone also started improving in these areas as our knowledge was shared around.</li>
</ul>
<h4 id="cons">Cons</h4>
<p>The Standing Team model is not without its downsides, and unfortunately they were less than obvious.</p>
<ul>
<li><strong>Welcome to the echo chamber:</strong> After working with the same team for a while you start looking at problems with a similar lens. This is fine in terms of methodology and style, but less than ideal when tackling new problems in new domains.<br /><br />It turns out that introducing new members to the team is important for many of the same reasons that diversity in the workplace is important; different backgrounds and experiences make for more creative teams with more and different ideas, and a generally richer team experience.<br /><br />As an example of this, when our team moved from a project with an agricultural and hardware focus to one more focused on search and big data we stumbled and had to learn how to adjust in this world. At one point two members left the team, and one of the incoming replacements had experience in big data. He brought a wealth of knowledge to the table, and this provided a significant boost in our ability to tackle this new domain.</li>
<li><strong>Everyone is An Expert or No One Is:</strong> This is the flip-side of the pro mentioned about, “Skillsets are a Known Quantity”. Everyone on the team knew what we knew, <em>and what we didn’t know</em>. When the team moved from the Big Ag space to the Big Data space we all knew that none of us had experience in this area, and that we had an uphill battle to fight. The Standing Team model was now working against us; it didn’t matter that we had worked well together on the previous project. Even though we worked together to remedy this deficiency we still had a knowledge and experience hole to fill. Having a new member brought in with that background ultimately served the team well.</li>
<li><strong>Stagnation of Individual Growth:</strong> This is probably the most insidious side-effect of Standing Teams. The longer the team works together, the less likely individuals are to be challenged to grow and adapt to new situations.<br /><br /> I was the tech lead for the standing team that I was a part of, and while I like to think that I tried to push the members of my team in positive ways, ultimately I probably stood in the way of their continued growth. I could see that the individuals on my team had grown to the point that they were each ready in their own right to move on to lead roles, but as long as the team stayed together they wouldn’t have the opportunity or impetus to make this change. In terms of my own growth I also knew that I had become extremely comfortable in the existing team dynamic, and that I had to find a way to push myself outside of my own comfort zone as well.<br /><br />The team eventually split up, and while we still work together it’s at different clients and different projects. I think this is for the best, as everyone needs to be exposed to new team dynamics, environments, and challenges.</li>
</ul>
<h4 id="conclusions">Conclusions</h4>
<p>As I said, the Standing Team model has merits, but there are other considerations besides high performance and the ability to hit the ground running. Without mitigating actions, such as rotating members of the team or even disbanding the team after 2-3 projects, team growth and adaptability both suffer under this model.</p>Jim KirkbrideBring the work to the team, not the other way around.Commenting on Comments2016-09-05T00:00:00-04:002016-09-05T00:00:00-04:00http://jameskbride.com/2016/09/05/commenting-on-comments<p>There are a number of schools of thought when it comes to comments. Some of them favor liberal application, and like an over-seasoned dish too many comments or the wrong comments can make is much more difficult to quickly process the meat of the codebase.</p>
<p>Let’s go over some of the common anti-patterns of comments and how to avoid them.</p>
<h3 id="the-created-by">The Created by</h3>
<pre>
/**
* Created by randomdeveloper
**/
public class SomeClass {}
</pre>
<p>This is a common pattern which is more often than not introduced by your IDE. It’s an anti-pattern because projects of any significant size will have multiple developers, who will probably touch every piece of code multiple times. Does it really matter who created the file at that point? If it does matter then let version control do the work for you.</p>
<p>The fix: Change your IDE settings to remove this template when creating new files. Rely on your version control to record who created the file, and when, based on your commit.</p>
<h3 id="the-cruft">The Cruft</h3>
<pre>
public String reverseString(String aString) {
//if (aString == null || aString.length() == 0) {
// throw new IllegalArgumentException("Must be a valid string");
//}
char[] charArray = aString.toCharArray();
StringBuilder builder = new StringBuilder();
for (int i=charArray.length-1; i>-1; i--) {
builder.append(charArray[i]);
//System.out.println(builder.toString());
}
return builder.toString();
}
</pre>
<p>Comments such as the ones above are common in many legacy codebases for any number of reasons. Maybe there are a lot of junior developers on the project, maybe there was a rush to get the work done and no one could take the time to clean things up before they pushed the code. For whatever reason, these comments made it in to version control somehow. The result is a shift in the signal/noise ratio towards the noise end of the spectrum.</p>
<p>The fix: Simply remove the dead code and let the code speak for itself.</p>
<h3 id="the-demarcation">The Demarcation</h3>
<pre>
public void godMethod() {
//Call the OS
... More code ...
// Read the file
... More code ...
// Save to the database
... More Code ...
// Call the web service ...
}
</pre>
<p>This is one of my favorite (most-hated) commenting anti-patterns. You’ll notice that in the code above there is a kind of stream of consciousness development occurring. The method is commenting a step-by-step recipe for how the work is getting done. It’s an indicator that there are multiple responsibilities and concerns being addressed in one place. This is a bad thing, because code that does multiple things at once is hard to change, hard to debug, and hard to test.</p>
<p>One of my favorite refactoring techniques is to pull apart huge methods like this and extract smaller methods (and eventually classes) at each of the demarcation lines. Eventually you’ll be able to inject in dependencies that handle the behavior that used to be part of this method, making it easy to change, debug, and test.</p>
<p>The fix: Extract methods and classes to act as collaborators from the code between each demarcation and name them according to what the comment previously stated. Remove the comments.</p>
<h3 id="the-outdated-method-signature">The Outdated Method Signature</h3>
<pre>
/**
* @param The message to send.
**/
public void sendMessage(Context context, String message) {...}
</pre>
<p>Notice here that the param list in the Javadoc doesn’t match the param list in the method signature. You’ll see this type of comment a lot in Javadocs, especially in codebases which are under active development. Tearing the comments out may not be an option in this case if the comments are for a public-facing API. Instead you’ll need to be vigilant about updating the comment and naming the parameters to be as plainly obvious about their usage as possible.</p>
<p>The fix: Maintain the comment, name classes, methods, parameters appropriately.</p>
<h3 id="the-internal-documentation">The Internal Documentation</h3>
<pre>
public class GodClass {
/**
* The context for doing things.
**/
private Context context;
/**
* This method does some of the things.
**/
private void doSomeOfTheThings() {
}
}
</pre>
<p>Commenting on the internals of a class is another indication that the code is not well understood. Private members and methods shouldn’t need documentation; instead the code should be organized and named as to make it blindingly obvious what it’s purpose is. Javadocs especially should be avoided on private implementation.</p>
<p>The fix: Remove internal comments on private members and methods. Refactor and rename until the code is more clear.</p>
<h3 id="the-log-block">The Log Block</h3>
<pre>
public class GodClass {
public void doSomeOfTheThings(List<String> params) {
//for (String param : params) {
// System.out.println("Param: " + param);
//}
... more code ...
}
}
</pre>
<p>Commented blocks of code such as the one above are usually artifacts of previous debugging sessions when someone was trying to figure out the state of the code at runtime. Rather than using an actual debugger they wrote variables out to the output, and then decided that that was a useful thing to do and left code in place, albeit commented out. It is still noise however, and shouldn’t exist in the production code.</p>
<p>The fix: First, insure there is an adequate level of tests covering the code which can serve as documentation and a regression suite all in one. Second, convert commented out blocks of code such as these into actual logging using a log framework such as log4j. You can control the log level of these statement, allowing fine-grained logging to take place.</p>
<h3 id="the-defect-fix">The Defect Fix</h3>
<pre>
public class GodClass {
public void doSomeOftheThings() {
//JIRA-1218 - This fixes the NPE
if (context == null) {
context = new Context();
}
}
}
</pre>
<p>This is one of those situations where it sounds like a good idea at first, until you realize how brittle and ephemeral this solution is. On the one hand you’re documenting where a fix has been applied. On the other, the code will continue to evolve until eventually (read: sooner than you think) this comment will be meaningless as the code changes out from under it. A cousin to this anti-pattern is to create a test which contains the issue reference in its name (public void fixForJIRA1218), which is just as bad for similar reasons.</p>
<p>The fix: Write a test that forces and records the expected behavior, rather than its implementation. Remove the comment. Insure that the commit message of the fix includes any issue tracking information (JIRA ticket #, etc).</p>
<hr />
<p>As you can see the theme here is generally “remove the comment, add tests, fall back on your version control tools”. Another aspect of this theme is to slow down and take your time. If you feel the need to add a comment because you don’t understand what’s happening then take the time to understand it, and to make the code understandable. This will pay off well in the long run.</p>Jim KirkbrideThere are a number of schools of thought when it comes to comments. Some of them favor liberal application, and like an over-seasoned dish too many comments or the wrong comments can make is much more difficult to quickly process the meat of the codebase.Pair Programming Patterns - Part 2 - Team Practices2016-03-03T00:00:00-05:002016-03-03T00:00:00-05:00http://jameskbride.com/2016/03/03/pair-programming-patterns-part-2<p>In my previous post on Pair Programming I talked about the <a href="/2016/02/26/pair-programming-patterns-part-1.html">individual practices</a> that make pairing more effective. Effective pair programming at the team level is an art, and some consideration should be given to how it should be conducted as well.</p>
<h3 id="pair-switch-regularly">Pair Switch Regularly</h3>
<p>One of the mistakes I’ve seen with pairing is regarding how long someone should pair together. Pair switching too often causes a lot of context switching, both in terms of potentially checking out and building code, and (more importantly) mental context switches. A lot of people talk about having to “get in the zone” in order to be productive as a developer. There is a period of time which is required before all of the distractions are cleared from one’s mind before they can really focus in on the problem; believe it or not this is just as true for pair programming. Although many people claim they can’t reach this level of concentration while pairing, this has not been my experience. It is just as true for a pair as it is a lone developer. The trick is to enter that zone together.</p>
<p>The other end of this spectrum is not pair switching enough. This is often referred to as being “pair married”. On the one hand you’ve paired with someone often enough to know their rhythms, which allows you to get a lot done. On the other hand, pairing with same person all the time for can get old quickly. A lot of bad habits can be picked up this way, and pairing with one person all the time can lead to thinking your way into a rut. A major benefit of pairing is a fresh set of eyes on the problem and a new perspective. Pairing with the same person all the time eliminates a lot of this benefit.</p>
<p>Pairs should switch on a regular basis, neither too frequently, nor too infrequently.</p>
<h3 id="pairs-should-switch-regardless-of-whether-a-story-is-done-or-not">Pairs Should Switch Regardless of Whether a Story Is Done Or Not</h3>
<p>Another good pairing habit is to switch pairs regardless of the state of the current story in play. This doesn’t mean both devs switch off of what they’re working on, however. What it does mean is that one dev switches out, while the other dev acts as the anchor for the story. This allows the continuation of knowledge and knowledge transfer to the next dev to occur. If the team follows this pattern then after a while everyone gets familiar with the whole codebase.</p>
<p>Some developers might balk at not seeing a story through to completion. I’ve been that developer at times. It can be frustrating to put so much work into a story only to pair switch out and watch someone else complete what you were working on.</p>
<p>Having said that, I recognize this behavior for what it is: <em>ego</em>.</p>
<p>Wanting to complete something yourself is a very me-centric point of view. It says “I did all this work, I should be the one to complete it.”, or (more insidiously) “This was difficult, the rest of team may have a hard time, so I should just do it myself”. Ego is a big driver of discontent, and it has no place in the codebase.</p>
<p>Another reason pairs should switch regardless of the state of the story is that quite often, after working on a particularly difficult piece a pair will simply be too close to the code. They could very well be overlooking an aspect of the code that someone else coming in fresh may immediately recognize, allowing the story to continue anew. Alternately if a story is long running and the pair is frustrated it may be beneficial to allow a developer to swap out and to work on something fresh. This eases the frustration, while again letting another member of the team tackle the problem, perhaps from a different angle.</p>
<p>Rather than insisting that they be the ones to complete a story, team members should give up their attachment to the code, and trust that the team as a whole can and will handle delivering it successfully.</p>
<h3 id="dedicated-pairing-stations">Dedicated Pairing Stations</h3>
<p>This is an often overlooked necessity. Often, organizations think two devs can just sit down in front of one of their workstations and begin working effectively. The first thing that developers who are pairing for the first time discover is that it becomes more difficult if there is only one keyboard and mouse, one monitor, or even just space for one dev to sit comfortably. Logistically, pairing is made easier by providing a second mouse, keyboard, and monitor, in a space big enough for two people. This allows each dev to easily be able to reach the controls, see the code, and be comfortable next to each other.</p>
<p>Another consideration is that a lone dev’s workstation is keyed to their identity, credentials, and workspace. This means that if that dev is out sick or leaves the company then the work on that machine is not available to the rest of the team until they come back or IT grants access to the machine again. Ideally, machines/VMs are established that are accessible by the entire team via shared credentials. This allows pairs to easily switch between workspaces and to carry on regardless of the status of one team member.</p>
<h3 id="pair-planning">Pair Planning</h3>
<p>If the team knows that a member of the team is going to be out or even leaving the team, then pairing should be conducted accordingly. Someone should pair with that developer to insure knowledge transfer and an easy transition. If there are two or more new members joining the team then having them pair together is a bad idea. No one likes to flounder or feel like they don’t know what they’re doing. Instead, more experienced members of the team should pair up with them to give them a smooth onboarding experience.</p>
<p>If there is a mix of junior and senior developers in the team they should be mixed together in pairs. All junior and all senior pairs is usually not ideal (at least initially). If there are experts in parts of the codebase then these experts should be paired up with non-experts to spread that knowledge, and the experts should be forced out of their comfort zones and into parts of the codebase that they might not be familiar with, but that another team member is.</p>
<h3 id="pair-retro">Pair Retro</h3>
<p>This is a pattern that can help developers new to pairing become better at it, and to help developers who have been pairing for a long time to remember what it was like to pair for the first time again. The pair retro is a mini-version of a standard sprint retro. The pair talks about what went well (We really knocked that story out!), what didn’t go so well (Hey Senior Dev, I didn’t get to touch the keyboard very much!), and how to improve (I’ll try to give up control more often, and you’ll be a little more aggressive at the controls.). This is a great pattern for new teams, and especially for new pair partners. After a while (probably sooner than you think) it will become unnecessary as devs will become more used to pairing and will norm on pairing habits, but in the beginning it can be an invaluable learning tool.</p>
<hr />
<p>These are some of the practices that over the years I’ve found to engender effective pairing at the team level. I hope this has been useful, and happy pairing!</p>Jim KirkbrideIn my previous post on Pair Programming I talked about the individual practices that make pairing more effective. Effective pair programming at the team level is an art, and some consideration should be given to how it should be conducted as well.Android TDD Series: Test-Driving Data-Access Part 2 - ContentProviders2016-02-28T05:49:00-05:002016-02-28T05:49:00-05:00http://jameskbride.com/android-series/2016/02/28/android-tdd-series-test-driving-data-part-2-contentproviders<p>In my last entry in this series I spoke about <a href="/android-series/2016/02/13/android-tdd-series-test-driving-data-part-1-sqliteopenhelper.html">test-driving the SQLiteOpenHelper</a>. We learned how to test the creation of a database for an application, and now we need to be able to interact this that database. Android provides more than one method to access the database, including accessing it directly via a query on the SQLiteOpenHelper, but here we’re going show how to create and test a <a href="http://developer.android.com/reference/android/content/ContentProvider.html">ContentProvider</a>, which will provide a more indirect and encapsulated method of access.</p>
<p>There are a number of reasons to implement a ContentProvider in your app. First, it gives you the ability to allow other applications to access your data. Beyond that it provides a cleaner, more maintainable design. Rather polluting your view classes with direct calls to the database, you can instead make calls to a <a href="http://developer.android.com/reference/android/content/ContentResolver.html">ContentResolver</a> (more on this later), which hides all of the gory details about how that data is retrieved. Finally, by implementing a ContentProvider we can enable thread-safe data access in Activities and Fragments via the <a href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html">LoaderManager Callbacks</a>. These last two points, cleaner design and the LoaderManager Callbacks, are the reasons we will be implementing a ContentProvider.</p>
<p>The ContentProvider is a major component in Android, so if you’ve never worked with one before I highly recommend you read the <a href="http://developer.android.com/guide/topics/providers/content-provider-basics.html">ContentProvider Basics</a>. You may also be interested in learning how to access some of the already-provided ContentProviders, including the <a href="http://developer.android.com/guide/topics/providers/contacts-provider.html">ContactsProvider</a>, or the <a href="http://developer.android.com/guide/topics/providers/calendar-provider.html">Calendar Provider</a>.</p>
<h2 id="general-usage">General Usage</h2>
<p>As I mentioned earlier the ContentProvider is never accessed directly in our application. Instead, developers will use a combination of a <a href="http://developer.android.com/guide/topics/providers/content-provider-basics.html#ContractClasses">Contract Class</a> and the ContentResolver.</p>
<h3 id="contract-class">Contract Class</h3>
<p>The Contract Class provides a consistent set of domain-specific fields and properties to be passed to the ContentResolver, namely the required URIs and database fields, which is the language the ContentResolver speaks in. The URIs are important, as they provide the ContentResolver with the means to determine which ContentProvider to make requests to, and potentially how many records to apply CRUD operations to. The Contract class will also expose common projections (otherwise know as the ‘select [fields]’ portion of a SQL select statement), and common sort orders.</p>
<p>See the example below for one implementation of a Contract class (also available on <a href="https://github.com/jameskbride/grocery-reminder/blob/master/app/src/main/java/com/groceryreminder/data/ReminderContract.java">Github</a>):</p>
<div class="highlighter-rouge"><pre class="highlight"><code>package com.groceryreminder.data;
import android.content.ContentResolver;
import android.net.Uri;
import android.provider.BaseColumns;
public class ReminderContract {
public static final String REMINDER_AUTHORITY = "com.groceryreminder.data.ReminderContentProvider";
public static final Uri REMINDER_CONTENT_URI = Uri.parse("content://" + REMINDER_AUTHORITY);
//snip
public static final class Reminders implements BaseColumns {
public static final String DESCRIPTION = "description";
public static final String[] PROJECT_ALL = {_ID, DESCRIPTION};
public static final String SORT_ORDER_DEFAULT = "";
public static final Uri CONTENT_URI = Uri.withAppendedPath(ReminderContract.REMINDER_CONTENT_URI, "reminders");
}
}
</code></pre>
</div>
<p>Usage of this class in conjunction with the ContentResolver in an Activity or Fragment might look something like this:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>ContentValues values = new ContentValues();
values.put(ReminderContract.Reminders.DESCRIPTION, "value");
getContentResolver().insert(ReminderContract.Reminders.CONTENT_URI, values);
</code></pre>
</div>
<p>Notice that calling the ContentResolver does not expose any of the details of how the data is stored. You’re not communicating directly with a database helper of any sort, there is no mention of SQLite, you’re simply inserting some values. This means that if you wanted to change the implementation of the ContentProvider and store the data remotely instead, none of your view-related code would have to change. You’re also do not have to worry about what thread this call is made on, as the ContentResolver handles that for you as well.</p>
<h2 id="implementing-a-contentprovider">Implementing a ContentProvider</h2>
<p>Implementing a custom ContentProvider involves creating a class which extends ContentProvider and adding the required configuration in the AndroidManifest.xml file. When we create our new ContentProvider there are a number of abstract methods which must be implemented:</p>
<ul>
<li><code class="highlighter-rouge">public boolean onCreate()</code> - A hook to allow you to perform whatever setup is necessary to interact with your data source. In our case this method will be used to a a handle on our SQLiteOpenHelper which we’ll use to interact with our database. Note: This method is called on main thread, so you’ll need to be careful not to implement long-running operations here.</li>
<li><code class="highlighter-rouge">public String getType(Uri uri)</code> - Provides the mime type of the content to callers (not covered here).</li>
<li><code class="highlighter-rouge">public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)</code> - The primary query method which allows read access to the underlying data. Returns a Cursor to walk through the result set.</li>
<li><code class="highlighter-rouge">public Uri insert(Uri uri, ContentValues values)</code> - The primary insertion method to add new data, which should return the URI of the new record. Note that there is a <code class="highlighter-rouge">bulkInsert()</code> method, but the underlying implementation calls this method.</li>
<li><code class="highlighter-rouge">public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)</code> - The primary update method, which should return the number of records updated (not covered here).</li>
<li><code class="highlighter-rouge">public int delete(Uri uri, String selection, String[] selectionArgs)</code> - The primary deletion method, which should return the number of records deleted.</li>
</ul>
<p>You should be aware that there is also an implied contract when implementing these methods, which is that any time data is <em>changed</em> any interested observers should be notified. This means a notification should be sent whenever insert, update, or delete successfully completes an operation. Without this notification downstream clients of this class, such as the LoaderManager Callbacks, won’t function properly.</p>
<h3 id="enough-talk-lets-write-some-code">Enough Talk, Let’s Write Some Code!</h3>
<p>We’re about to get into the nuts and bolts of implementing this class. If you’re short on time you may want to simply check out a production example, which you can find in my <a href="https://github.com/jameskbride/grocery-reminder">GroceryReminder App</a> on Github.</p>
<h4 id="creating-the-provider">Creating the Provider</h4>
<p>First, we need to implement our <code class="highlighter-rouge">onCreate()</code> method. This only returns a boolean, so initially it will be simple:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class ReminderContentProviderTest {
private ReminderContentProvider provider;
@Before
public void setUp() {
provider = new ReminderContentProvider();
}
@Test
public void whenTheProviderIsCreatedThenItShouldBeInitialized() {
assertTrue(provider.onCreate());
}
}
</code></pre>
</div>
<p>Now to get that test passing:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>public class ReminderContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return true;
}
//snip
}
</code></pre>
</div>
<p>Dead simple, right? Let’s get to the meat and look at the <code class="highlighter-rouge">insert()</code> method next.</p>
<h4 id="inserting-data">Inserting Data</h4>
<div class="highlighter-rouge"><pre class="highlight"><code>@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class ReminderContentProviderTest {
private ReminderContentProvider provider;
@Before
public void setUp() {
provider = new ReminderContentProvider();
provider.onCreate();
}
@Test
public void whenTheProviderIsCreatedThenItShouldBeInitialized() {
ReminderContentProvider = new ReminderContentProvider();
assertTrue(provider.onCreate());
}
@Test
public void givenAReminderContentTypeAndContentValuesWhenARecordIsInsertedThenAURIWithRecordIDShouldBeReturned()
{
ContentValues values = createDefaultReminderValues();
Uri expectedUri = provider.insert(ReminderContract.Reminders.CONTENT_URI, values);
assertNotNull(expectedUri);
assertEquals(1, ContentUris.parseId(expectedUri));
}
private ContentValues createDefaultReminderValues() {
//Helper method which populates our ContentValues object for insertion.
return new ReminderValuesBuilder().createDefaultReminderValues().build();
}
}
</code></pre>
</div>
<p>We now have a test that is checking for a proper URI to be returned from the insert. Let’s implement that method now.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>public class ReminderContentProvider extends ContentProvider {
private ReminderDBHelper reminderDBHelper;
@Override
public boolean onCreate() {
reminderDBHelper = new ReminderDBHelper(getContext());
return true;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase writableDatabase = reminderDBHelper.getWritableDatabase();
long id = writableDatabase.insertWithOnConflict("reminders", null, values, SQLiteDatabase.CONFLICT_NONE);
Uri insertedUri = ContentUris.withAppendedId(uri, id);
return insertedUri;
}
//snip
}
</code></pre>
</div>
<p>Notice this test drove us to introduce our ReminderDBHelper (created in the previous post). We now perform a proper insertion of data. We’re missing functionality however, which is the notification to our observers that we made a change. Let’s write a test for that.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@Test
public void givenAReminderContentTypeAndContentValuesWhenARecordIsInsertedThenObserversAreNotified()
{
//Calling another helper method to create some values to be inserted
ContentValues values = createDefaultReminderValues();
ShadowContentResolver contentResolver = Shadows.shadowOf(provider.getContext().getContentResolver());
Uri expectedUri = provider.insert(ReminderContract.Reminders.CONTENT_URI, values);
List<ShadowContentResolver.NotifiedUri> notifiedUriList = contentResolver.getNotifiedUris();
assertThat(notifiedUriList.get(0).uri, is(expectedUri));
}
</code></pre>
</div>
<p>Here we’re leaning on Robolectric to get access to the list of notified URIs, which are normally not available to us in the vanilla Android framework. This allows us to test for functionality which would otherwise be untestable. Now the production change.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase writableDatabase = reminderDBHelper.getWritableDatabase();
long id = writableDatabase.insertWithOnConflict("reminders", null, values, SQLiteDatabase.CONFLICT_NONE);
Uri insertedUri = ContentUris.withAppendedId(uri, id);
//This line handles the notifications
getContext().getContentResolver().notifyChange(insertedUri, null);
return insertedUri;
}
</code></pre>
</div>
<h4 id="querying-data">Querying Data</h4>
<p>There are a number of tests that need to written to fully cover the <code class="highlighter-rouge">query()</code> method, but in the interest of time we’ll cover basics here. Let’s write our first query test.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@Test
public void whenRemindersAreQueriedThenTheRequestedSelectionShouldBeUsed() {
ContentValues otherRecord = new ReminderValuesBuilder().createDefaultReminderValues().build();
String expectedDescription = "test";
ContentValues recordToQuery = new ReminderValuesBuilder().createDefaultReminderValues().withDescription(expectedDescription).build();
provider.insert(ReminderContract.Reminders.CONTENT_URI, otherRecord);
provider.insert(ReminderContract.Reminders.CONTENT_URI, recordToQuery);
String selection = ReminderContract.Reminders.DESCRIPTION + " = 'test'";
Cursor cursor = provider.query(ReminderContract.Reminders.CONTENT_URI, ReminderContract.Reminders.PROJECT_ALL, selection, null, null);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals(expectedDescription, cursor.getString(1));
cursor.close();
cursor = null;
}
</code></pre>
</div>
<p>This is pretty straight forward. We insert some data, query for a particular record and expect to get it back. Now let’s implement the production code.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables("reminders");
Cursor cursor = queryBuilder.query(reminderDBHelper.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
//Cannot currently test-drive this line: minSdk must be 19, currently set to 15
cursor.setNotificationUri(getContext().getContentResolver(), ReminderContract.Reminders.CONTENT_URI);
return cursor;
}
</code></pre>
</div>
<p>The magic here is that we are using the <a href="http://developer.android.com/reference/android/database/sqlite/SQLiteQueryBuilder.html">SQLiteQueryBuilder</a> to actually build our query, instead of trying to manually put it together. Note that for more complex queries we can pass multiple tables as a comma-delimited String to <code class="highlighter-rouge">queryBuilder.setTables()</code> in order to perform joins.</p>
<h4 id="deleting-records">Deleting records</h4>
<p>As with the query method a number of tests should be written to cover everything, and again we’ll simply go over the basics. The test:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@Test
public void givenASelectionIsProvidedWhenAReminderIsDeletedThenADeletionWillOccur() {
String testDescription = "test";
ContentValues values = new ReminderValuesBuilder().createDefaultReminderValues().withDescription(testDescription).build();
provider.insert(ReminderContract.Reminders.CONTENT_URI, values);
String selection = ReminderContract.Reminders.DESCRIPTION + " = ? ";
String[] selectionArgs = new String[] {testDescription};
int count = provider.delete(ReminderContract.Reminders.CONTENT_URI, selection, selectionArgs);
assertEquals(1, count);
}
</code></pre>
</div>
<p>Now the production code:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>public class ReminderContentProvider extends ContentProvider {
private static final int REMINDER_LIST = 1;
private static final int REMINDER_ITEM_ID = 2;
private static final UriMatcher URI_MATCHER;
private static final String REMINDERS_URI_LIST_PATH = "reminders";
static {
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URI_MATCHER.addURI(ReminderContract.REMINDER_AUTHORITY, REMINDERS_URI_LIST_PATH, REMINDER_LIST);
URI_MATCHER.addURI(ReminderContract.REMINDER_AUTHORITY, "reminders/#", REMINDER_ITEM_ID);
}
//snip
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase writableDatabase = reminderDBHelper.getWritableDatabase();
int deletedCount = 0;
switch(URI_MATCHER.match(uri))
{
case REMINDER_LIST:
deletedCount = writableDatabase.delete("reminders", selection, selectionArgs);
break;
case REMINDER_ITEM_ID:
String id = uri.getLastPathSegment();
String whereClause = ReminderContract.Reminders._ID + " = " + id;
deletedCount = writableDatabase.delete("reminders", whereClause, selectionArgs);
break;
}
if (deletedCount > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return deletedCount;
}
}
</code></pre>
</div>
<p>There is a lot going on here, actually way more than the test actually called for. Trust me, the rest of this functionality was also test-driven just in case you’re wondering. The important things to note here are the usage of the URI_MATCHER, which controls whether or not a single record should be deleted or multiple, the actual deletion, and the returned deletionCount.</p>
<h3 id="configuration-and-caveats">Configuration and Caveats</h3>
<p>You should now have a pretty good idea of the basic operations for a ContentProvider. You’ve also seen how to use a ContentResolver and a Contract Class to access data via a ContentProvider. The last thing that we have to do is to add the required entries in the AndroidManifest.xml. Unfortunately we cannot test-drive this functionality; instead a functional test is required, as this will load the app in an emulator, where the AndroidManifest.xml is loaded. We haven’t touched on functional testing in this series yet, but my favored framework is Espresso, which I’ll try to cover in a later entry. For now, I’ll show you the entry to be added to the manifest file.</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="utf-8"?></span>
<span class="nt"><manifest</span> <span class="na">xmlns:android=</span><span class="s">"http://schemas.android.com/apk/res/android"</span>
<span class="na">xmlns:tools=</span><span class="s">"http://schemas.android.com/tools"</span>
<span class="na">package=</span><span class="s">"com.groceryreminder"</span><span class="nt">></span>
<span class="nt"><application</span>
<span class="na">android:name=</span><span class="s">".injection.ReminderApplication"</span>
<span class="na">android:allowBackup=</span><span class="s">"true"</span>
<span class="na">android:icon=</span><span class="s">"@mipmap/ic_launcher"</span>
<span class="na">android:label=</span><span class="s">"@string/app_name"</span>
<span class="na">android:theme=</span><span class="s">"@style/AppTheme"</span> <span class="nt">></span>
<span class="c"><!-- snip --></span>
<span class="nt"><provider</span> <span class="na">android:name=</span><span class="s">".data.ReminderContentProvider"</span>
<span class="na">android:authorities=</span><span class="s">"com.groceryreminder.data.ReminderContentProvider"</span>
<span class="na">android:enabled=</span><span class="s">"true"</span>
<span class="na">android:exported=</span><span class="s">"false"</span><span class="nt">></span>
<span class="nt"></provider></span>
<span class="nt"></application></span>
<span class="nt"></manifest></span>
</code></pre>
</div>
<p>There are four things we must do here:</p>
<ul>
<li>Add the provider node.</li>
<li>Set the <code class="highlighter-rouge">android:name</code> attribute, which must match the ContentProvider class name relative to the base package.</li>
<li>Set the <code class="highlighter-rouge">android:authorities </code>attribute. You might recognize that this matches exactly to the ReminderContract.REMINDER_AUTHORITY value we created above, and that this value is used for URI matching in the <code class="highlighter-rouge">ContentProvider.delete()</code> method. <em>IMPORTANT</em>: If there is a mismatch between the AUTHORITY values your ContentProvider will not be accessible from your application.</li>
<li>Set the android:enabled attribute to true, to allow the provider to be used at all.</li>
</ul>
<hr />
<p>This concludes the tutorial on implementing your own ContentProvider. As you’ve seen there is a lot that needs to happen here, but once you’ve implemented one or two of these you’ll quickly become familiar with the operations. You’ll also quickly see the benefits of creating this class after reading my next entry, which will cover implementing the LoaderManager Callback methods in your view classes.</p>James KirkbrideIn my last entry in this series I spoke about test-driving the SQLiteOpenHelper. We learned how to test the creation of a database for an application, and now we need to be able to interact this that database. Android provides more than one method to access the database, including accessing it directly via a query on the SQLiteOpenHelper, but here we’re going show how to create and test a ContentProvider, which will provide a more indirect and encapsulated method of access.Pair Programming Patterns - Part 1 - Individual Practices2016-02-26T00:00:00-05:002016-02-26T00:00:00-05:00http://jameskbride.com/2016/02/26/pair-programming-patterns-part-1<p>There are a number of XP development practices that are considered controversial, and pair programming is one of them. I’ve written about pairing <a href="/2014/05/31/Why-Your-Four-Year-Old-Is-The-Ultimate-Pair-Programmer.html">previously</a>, and there are a lot of other great resources on the subject, including more than one <a href="https://www.youtube.com/watch?v=W4RbECwDJ10">amusing video</a> on the challenges of pairing.</p>
<p>A lot of people give up on pairing before they ever really give it a chance. They’ve heard horror stories from other devs who apparently had a terrible time with it, and can give you 100 reasons why the practice simply won’t work for them. It seems that people either love or hate pairing, for a variety of reasons. For the ones that hate it they’ll tell you that there is simply too much pressure working right next to someone. They’ll tell you they had a terrible pair partner who had bad body odor. They’ll tell you that they can only work alone, and won’t even bother giving you a reason as to why they can’t be bothered to work next to someone else.</p>
<p>As for the devs who enjoy it and end up being very productive in this mode I’ve noticed a number of common behaviors that make pairing more effective, and these are what I’m going to talk about here.</p>
<h3 id="enabling-line-numbers">Enabling Line Numbers</h3>
<p>Grunt and point went out of style with the Neanderthal. A behavior I see in a lot of developers who are new to pairing is to see a potential issue and then to point and cry out something to the effect of “Ah, there is the problem right there!” Meanwhile, their pair partner is still scratching their head in confusion trying to figure out where the other developer is pointing on the screen (This is impossible to follow if you are pairing remotely!). One of the first things I do when I configure an IDE is to enable line numbers. This allows you have a much more accurate conversation with your pair partner. It now becomes “Ok, line 42 is the problem.”, and the other developer immediately knows what you’re talking about. They can go directly to line 42 without trying to follow your finger and your line of sight.</p>
<h3 id="give-up-the-keyboard">Give Up the Keyboard</h3>
<p>I’ve developed a habit over the years when I’m pairing. Essentially, as soon as I see my pair partner reach for the controls I immediately lift mine off of the keyboard and mouse. This helps to prevent the awkward moments in pairing in which both devs are trying to drive at the same time. This is more than just a muscle memory reaction, it’s also a way of thought that you don’t always have to be in control. It’s the acknowledgement that someone else is allowed to have input as well.</p>
<h3 id="suggest-dont-dictate">Suggest, Don’t Dictate</h3>
<p>Effective pairing is bringing two minds together to solve a problem. Both minds need to have an equal say in matters, which means agreement needs to be reached on what an appropriate solution looks like. This means one dev can’t simply shut the other down, as that can quickly lead to discontent and disengagement. This is the kind of behavior that leaves a bad taste in someone’s mouth for pairing.</p>
<p>Having said that I’ve recognized in myself to be aggressive when it comes time to develop a solution. I see a way forward and go for it. This doesn’t work in a pair; you have to be willing to hear what your partner is saying, and vice versa. Therefore, when you are part of a pair your tendency should be to suggest potential solutions rather than to dictate them. Leave the door open to discussion, and allow for the possibility that there might be a better solution waiting to be discovered by both involved parties.</p>
<h3 id="thinking-out-loud">Thinking Out Loud</h3>
<p>Experienced pair partners all have at least one thing in common: they think out loud. They don’t keep their thoughts to themselves, because it leaves the other developer in the dark. Thinking out loud spreads the brainpower around. Some of the best pairing experiences I’ve had started when I’m talking my way through a problem, and my partner starts riffing on this and provides their own ideas. Pretty soon we’re working through the problem quickly, and before you know it we have a solution.</p>
<p>Developers new to pairing often have to learn to open up and “let their brain out” so to speak. They’re used to working in silence. After they’ve been pairing for a while though thinking out loud just becomes second nature. Good pairs communicate constantly. They’re discussing ideas, talking about the best way to fix a bug, figuring out a better design, or learning something new. There isn’t an effective way to pair and <em>not</em> think out loud.</p>
<h3 id="let-your-partner-finish-their-thought">Let Your Partner Finish Their Thought</h3>
<p>While thinking out loud is definitely a good thing, so is letting your pair partner finish their thoughts. This applies to code as well and not just conversation. If your partner is currently driving and they’re in the middle of writing some code, let them finish instead of grabbing the keyboard and mouse away to fix what you consider a glaring error. After all, you want to be able to finish your thoughts without receiving an interrupt signal too, don’t you?</p>
<h3 id="pay-attention">Pay Attention</h3>
<p>It’s funny, one would think this goes without saying. After all, this is the dev’s job right? Surprisingly, a lot of devs new to pairing seem to tune out unless it is their turn at the keyboard. The pair will kick a build and out comes the phone. One dev will start driving and the other will very obviously not be paying attention. It stops being pairing at some point and just becomes two people who happen to be sitting together with one of them doing the work. For pairing to be effective both devs need to be fully engaged in the process. Both devs should be actively contributing to the code and to the conversation.</p>
<h3 id="acknowledge-the-awesome-in-someone-else">Acknowledge the Awesome in Someone Else</h3>
<p>Another simple, should-be-obvious tip that is often overlooked. It’s easy to say “OK, we finished this piece of work, let’s grab the next one and move on”, when in reality what should be happening is saying “Hey, you really saved us a ton of time with that refactor, great job!”. We need to be willing to acknowledge when someone other than ourselves does something awesome. I’m not talking about giving empty praise, I’m talking about recognizing someone outside of our mind when they deserve it. Attitude matters a lot when you’re (living) pairing, and people appreciate a good attitude. Take time to take joy in your work, and in the work of others. If you’re not taking joy in what you and others do then why <em>are</em> you doing it?</p>
<hr />
<p>Pairing at the individual level is not at all easy when you first get started. It is not exactly encouraged by the existing developer culture, though it is more accepted theses days than it used to be. Hopefully the points I’ve discussed will help to make your pairing experiences more enjoyable and effective. In my next entry in this series I’ll talk about pairing at the team level, and how to engage many pairs efficiently.</p>Jim KirkbrideThere are a number of XP development practices that are considered controversial, and pair programming is one of them. I’ve written about pairing previously, and there are a lot of other great resources on the subject, including more than one amusing video on the challenges of pairing.Software Craftsmanship Doesn’t Equal “Faster” - And That’s OK2016-02-21T00:00:00-05:002016-02-21T00:00:00-05:00http://jameskbride.com/2016/02/21/software-craftsmanship-doesnt-equal-faster-and-thats-ok<p>I have a <a href="http://djdaugherty.com/">friend</a> who likes to talk about testing, specifically TDD, using a car analogy (What would a good software development story be without a bad car analogy?). He likens TDD to breaks and seatbelts. The car functions without breaks and seatbelts and you can go really <em>really</em> fast. With breaks and seatbelts though you can go really really fast <em>safely</em>. What does this mean? It means that just because you can go 90mph it doesn’t mean you’re going to want to go 90mph around a 90 degree curve, you’re going to want to slow down enough to make it around the curve. The same thing applies in software development and TDD. TDD allows you to make changes relatively quickly, while at the same time knowing that you’re not going to break anything in the code and splatter yourself against that 90 degree curve.</p>
<p>Now I like this analogy as far as it goes, but I don’t feel like it tells the whole story. For one thing, TDD is only one aspect of Software Craftsmanship. For another I don’t feel like the concept of “fast” has a singular dimension. Going fast isn’t always going 90mph. In fact, going 90mph is usually incredibly dangerous in most situations. Fast also doesn’t always equate to your ability to go from 0 to 90mph in four seconds if you can’t sustain that pace. Is going “fast” even valuable?</p>
<p>Instead of talking about going “fast” in only one dimension, let’s talk about it more holistically, obviously with another bad (s/car/vehicle) analogy.</p>
<h3 id="a-bad-vehicle-analogy">A Bad Vehicle Analogy</h3>
<p>Let’s say we have two teams that are going to take a trip around the world. Each team has a vehicle and an unlimited supply of parts to use on the trip. Sounds like your standard “Around the World in 80 Days” story so far, right? At this point we’re going to throw the teams a couple of curve balls. First, they don’t know their exact route ahead of time. They know in general that it is a worldly trip, so they’re bound to hit a couple of rough patches along the way, but their actual route might change from day to day based on certain conditions. They can use the parts they have to add functionality to their vehicle to allow them to cross various obstacles. There is an ocean in the way of their trip? They can add wings and allow the vehicle to fly a short distance, or maybe they’ll choose to make it sea-worthy instead. Second, they have to disassemble and reassemble their vehicle every day before they can continue their journey, and it still has to function. Third, they’re not allowed to remove functionality because (and this is the important part) the sponsors who pay for the trip are going to use their vehicle to make the same trip after they are done. This means that the vehicle has to be able to cross all the same obstacles again. This also means the team doesn’t get to cross an obstacle, rip out the parts afterwards, and simply continue on.</p>
<p>On to the teams.</p>
<p>At the start of the trip one team tears across the starting line and they’re making good time initially. They add features to their vehicle as they come across obstacles. When it comes time to go off-road they add better shocks and tires. When it rains they add heavy-duty windshield wipers. When they hit a muddy patch they add four-wheel drive. They don’t bother creating a checklist or instructions for adding the features because what they have done so far is simple; they figure they’ll remember what they did and be able to put the vehicle back together easily from memory each day.</p>
<p>As for the team, each person takes turns navigating when they come across landscape that they are familiar with. One person drives on the roads, another person captains when it comes time to cross a body of water, another person pilots when it is time to fly. All is well in the beginning, and they are moving “fast”.</p>
<p>The other team starts at the same time, and makes equally good time until they hit their first obstacle. Instead of simply adding the required feature to their vehicle and moving on they check to make sure the new feature will actually get them past the obstacle, and they record what they did on a checklist and set of instructions. They repeat this at each obstacle. They also spend some time making sure that it is easy to add and remove parts to make changing the vehicle easier.</p>
<p>Another difference this team has from the first team is that no one person is responsible for navigating. When the landscape changes there are at least two people who are responsible for navigating, and this responsibility rotates periodically. As the other team isn’t following these patterns this team falls behind in the beginning.</p>
<p>As the trip continues each team follows their own practices. After a couple of weeks though something has changed, and the first team is not moving nearly as fast as they did in the beginning. What happened? Why isn’t the first team moving “fast” anymore?</p>
<p>It turns out that when it comes time to reassemble their vehicle each day the team occasionally forgets how to put it together. Worse, sometimes they think they assembled it correctly, but when it comes time to use a feature they created to cross an obstacle the vehicle malfunctions and breaks down. They can’t cross that ocean because the gears to change the vehicle from a car to a boat didn’t work right. They now need to frequently spend time fixing things.</p>
<p>The members of the first team also have issues. There are long stretches of landscape that only one person knows how to navigate, and after a while they get tired, or sick. When another member steps up to take over for a while they make mistakes and get stuck in the sand, or they burn out a motor when they try to go really fast to “keep the pace”, something the other team members know not to do in those stretches.</p>
<p>As for the second team, when it comes time to reassemble their vehicle they follow the checklist and instructions, which they’ve been updating along the way. When they have to add a new feature it takes a little longer, but they know that when the trip is over the vehicle will be usable. The vehicle breaks down much less frequently, and they make steady progress.</p>
<p>As for the members of the team, because they’ve been pairing and rotating the responsibility for navigating, any of the team members can cross a given stretch of landscape. They learn from each other’s mistakes, and they can navigate with confidence even if someone gets tired or sick. They also don’t try to push their pace so hard that they become too tired, because they know that will only cause more mistakes to be made, and will slow them down in the long run.</p>
<p>Both teams eventually cross the finish line of the trip. I’d like to tell you that second team, which took its time doing things right, finished first, but that isn’t what happens. The first team realized they were falling behind and started working around the clock, frantically trying to fix what’s broken and driving constantly. The team is exhausted and broken by the end of the trip, but they come in first. They hand their vehicle over to their sponsor, who is happy to get their hands on it.</p>
<p>The second team comes in shortly after the first. They’re tired, but in good spirits and confident in what they’ve built. They hand over their vehicle to the sponsor as well, who is less than happy that it took so long to complete the trip.</p>
<p>The sponsors now start using the vehicles to make the trip themselves, and quickly discover a difference between the vehicles. The first one breaks down frequently, costing time and money to fix. The second vehicle works as expected, and only breaks down once or twice.</p>
<h3 id="epilogue">Epilogue</h3>
<p>Which team “won”? Was going “faster” worth it? Did the first team win because they crossed the finish line first? Sure, the sponsors were happy that the first team got done faster, because it cost them less money for the initial trip, but was that an actual cost-saving when compared to the repair costs afterwards?</p>
<p>When we talk about software development we should ask ourselves what “fast” means, and what the value of “fast” is. After all, “fast” is relative term which means different things to different people. Was it valuable to be done quickly? Many would argue that this is true, and maybe they would be right in the short term. Does going fast mean not taking time to safely make changes and upgrades to your software? What does going “fast” mean if what you’re building isn’t fully-functional when you’re done?</p>
<p>The practices I described above (TDD, pairing, and continuous integration) are just a few of the techniques a craftsman uses to build software. These are not tools that necessarily help you to go “faster” in the sense of going 90mph. They are, however, tools that let you go faster in the sense that you’ll save time by not having to go back and fix things repeatedly, and you’ll be able to deliver code working software early, often, and reliably. Think about this the next time someone tells you they need you to go “faster”.</p>Jim KirkbrideI have a friend who likes to talk about testing, specifically TDD, using a car analogy (What would a good software development story be without a bad car analogy?). He likens TDD to breaks and seatbelts. The car functions without breaks and seatbelts and you can go really really fast. With breaks and seatbelts though you can go really really fast safely. What does this mean? It means that just because you can go 90mph it doesn’t mean you’re going to want to go 90mph around a 90 degree curve, you’re going to want to slow down enough to make it around the curve. The same thing applies in software development and TDD. TDD allows you to make changes relatively quickly, while at the same time knowing that you’re not going to break anything in the code and splatter yourself against that 90 degree curve.Automated Testers are Antithetical to Good Engineering2016-02-15T00:00:00-05:002016-02-15T00:00:00-05:00http://jameskbride.com/2016/02/15/automated-testers-are-antithetical-to-good-engineering<p>The role of the Automated Tester, like many things, was created with the best of intentions. In an attempt to acknowledge the importance and effectiveness of the automated test suites which now forms the backbones of many large-scale (purportedly) agile projects which utilize scrum and XP practices (notably Iterative Development, TDD, and Continuous Integration) the industry has created a role which supports the idea of automated testing while attempting to marry it with the continued existence of a separate QA department.</p>
<p>Despite these good intentions the introduction of this role harkens back to the bad old days of waterfall development, in which everything everything fell neatly into one of a number of familiar phases: Ideation, Requirements Gathering, Design, Development, Testing, Deployment, Maintenance, etc. In this case we are once again separating Development and Testing into distinct activities. Developers are no longer required to wear as many hats, as a new member of the team would be responsible for wearing The Testing Hat. Now, instead of having armies of off-team QA Testers who follow scripts to repetitively, manually (read: prone to human error) test functionality organizations now have armies of on or (worse) off-team Automated Testers who write reams of often poorly written, unmaintainable, and flaky functional/e2e tests.</p>
<p>Introducing this role means that the organization has implicitly said to developers “Don’t worry about writing the right tests, that is the Automated Tester’s job”. Whether this was their intent or not is irrelevant. By adopting this strategy the organization is making one of two statements. They are either saying “Developers can’t be trusted to write the right tests for their own software”, or they’re saying “Developers have more important things to do than to write their own tests”. Either of these statements is an indication that <em>something is rotten in state of Denmark</em>.</p>
<h3 id="give-a-tester-a-hammer-and-everything-looks-like-an-end-to-end-test">Give a tester a hammer and everything looks like an end-to-end test.</h3>
<p>Automated testers frequently relegate themselves to the functional/e2e test layers, and therefore make it their business to write more of these tests. Understand, this is through no fault of their own, as they are simply performing the job assigned to them. The organization has requested that they write more tests, so they write more tests in “their” section of the codebase, which is itself antithetical to the concept of Collective Code Ownership.</p>
<p>Unfortunately this is often counterproductive and does nothing more than to create an inverted test pyramid. This causes the build to run longer, which increases the length of the feedback cycle, which in turn makes introducing new functionality take longer. As we all know time is money, and the longer it takes to develop features the longer the project takes, and the longer the project takes the more budget it burns.</p>
<p>Furthermore, functional/e2e tests can often be slow and flaky due to the need to wait on UI interactions, outside dependencies that often have a degree of latency, and other issues that arise in a production-like environment. The long run times and flakiness can drastically reduces the effectiveness, reliability, and therefore value of huge suites of functional/e2e tests.</p>
<h3 id="automated-testers-and-tdd-are-like-water-and-oil">Automated Testers and TDD are like water and oil.</h3>
<p>No matter how you look at it the introduction of the Automated Tester to a project works against Test-Driven Development.</p>
<p>Let’s examine the situation. Let’s say that an organization is attempting to be forward-thinking and tries to deliver working software frequently. They practice Iterative Development and have a concept of a sprint. In this scenario perhaps the Automated Tester works with the Product Owner and developers in a Three Amigos meeting. They agree to the requirements, and the Automated Tester writes one or more functional/e2e tests before (or while) the developers begin their own coding. Sounds good right? Heck, it even sounds like it lines up with TDD. After all, there will be failing tests that will (hopefully) pass when the developers are done.</p>
<p>Here’s what happens in actuality. The Automated Tester goes off to write their tests with some kind of design in mind. The UI will behave this way, or the service will have this contract. The developers go off to begin their own Test-Driven approach to meet the requirements. They don’t get too far before they realize that the contract they came up with doesn’t work. Different parameters need passed to the service. A different approach to the UI is required. The hooks the Automated Tester is relying on need to be changed to meet the technical requirements. The tests that the Automated Tester created don’t pass, and need to be re-written to account for the actual behavior and technical requirements.</p>
<p>Because we’ve separated the functional/e2e tests from the rest of the development we have effectively knee-capped the “Driven” part of Test-Driven. We have already come up with a design that probably doesn’t match reality, because the developers who are responsible for implementing the functionality were not the ones who wrote the first failing tests. They have also made assumptions about what the design should be before allowing a single test to drive that design in the first place.</p>
<p>For those developers who are not practicing TDD, now that the role of the Automated Tester has been introduced some developers may interpret this as a license to once again “throw it over the wall” so to speak. They will no longer feel the pressure to properly cover their own code with tests at the right level. Instead, they can rely on the Automated Tester to cover the behavior of the functionality in the higher-level tests, and nevermind that any number of corner cases may not be covered at this level (or if they are they are represented as additional slow, expensive tests which shouldn’t be in the e2e layer to begin with). Again this harkens back to the bad old days when developers would churn out some production code and simply pass it on to QA, who would then either pass it or throw it back over the wall to the developer again.</p>
<p>Let’s also consider the point at which the tester’s code is integrated in the codebase. Should this before before the developer begins? How far ahead of development do they need to be? Should their code compile for functionality that doesn’t exist yet? Should it be commented out? Ignored? At what point do we consider this code rot? How about after the developer’s work? Are these post-development tests valuable? Are they duplicating tests which have been written in lower layers of the system as faster, more reliable unit or integration tests? Should the tester add their tests to a separate codebase altogether, divorced from the regular build? Experience has shown me that this drastically increases the feedback loop time. How about on another branch? How often does this branch get merged? Who’s responsibility is it to do the merging? The developer’s? The tester’s? As you can see even the nuts and bolts of how the Automated Tester conducts their work comes into question.</p>
<h3 id="we-dont-need-automated-testers-we-need-developers-who-can-write-tests">We don’t need Automated Testers, we need developers who can write tests.</h3>
<p>Some of you are probably thinking that I’m being uncharitable to Automated Testers, that I’m not accounting for skilled developers who happen to be in that role, or who have an affinity for writing tests. I acknowledge that these individuals exist, but my experience has been that they are by and large in the minority. I would also encourage these individuals to consider moving into development roles, as there is no shortage of a need for developers who know how to write tests and testable code.</p>
<p>Projects would be better served by moving tests from the slower functional/e2e test layer down to the integration and unit test layers, and putting them back in the hands of the developers. Developers are the ones positioned to know what tests should be written, and in what layers. They’ll be able to determine if a test is best written as a unit test, an integration test, or if required an e2e test.</p>
<p>Developers are ultimately responsible for the functionality of the software, and as such they should be the ones to insure that their own code works the way they say it does.</p>Jim KirkbrideThe role of the Automated Tester, like many things, was created with the best of intentions. In an attempt to acknowledge the importance and effectiveness of the automated test suites which now forms the backbones of many large-scale (purportedly) agile projects which utilize scrum and XP practices (notably Iterative Development, TDD, and Continuous Integration) the industry has created a role which supports the idea of automated testing while attempting to marry it with the continued existence of a separate QA department.Android TDD Series: Test-Driving Data Access Part 1 - SQLiteOpenHelper2016-02-13T12:54:00-05:002016-02-13T12:54:00-05:00http://jameskbride.com/android-series/2016/02/13/android-tdd-series-test-driving-data-part-1-sqliteopenhelper<p>It’s been a while since my <a href="/android-series/2015/10/18/android-tdd-series-dagger-and-mockito.html">last post</a> in my Android TDD series, and I think it is time for the next entry. Previously we discussed test-driving view classes in Android, including Activities and Fragments. This laid the foundation for displaying content to the user. Having done that we can now focus on providing that content.</p>
<p>Data access in Android is not overly complex, however there are several core components you’ll need to understand and be able to write tests for. In the upcoming entries for this series we’ll focus on data access layer and it’s components. These will include (from the “bottom” of the stack up): SQLiteOpenHelper, ContentProviders, and the LoaderManager callback mechanisms. Each of these components will get you a step closer to providing data to the view layers.</p>
<p>Out of the box Android supports using a SQLite database to store and manage data. While you have <a href="https://realm.io/news/realm-for-android/">other</a> <a href="http://ormlite.com/">options</a> <a href="http://greenrobot.org/greendao/documentation/introduction/">available</a> for data access I can’t say I have any experience with these. Furthermore, it is always good to have a foundational knowledge of what the framework is actually doing, and the SQLiteOpenHelper provides basic facilities for database management.</p>
<p>Lets examine the <a href="http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html">SQLiteOpenHelper</a>. This class is responsible for creating and upgrading your database. It also gives you an optional hook for opening the database. We are primarily going to be interested in the first two use cases, creating and upgrading your database. The first step we will take is to create a class which extends SQLiteOpenHelper (I’ll use an example from my open-source app, <a href="https://github.com/jameskbride/grocery-reminder">The Grocery Reminder</a>):</p>
<div class="highlighter-rouge"><pre class="highlight"><code>package com.groceryreminder.data;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class ReminderDBHelper extends SQLiteOpenHelper{
public ReminderDBHelper(Context applicationContext) {
super(applicationContext, "some name", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
</code></pre>
</div>
<p>Notice we are overriding two methods here to satisfy the implementation of the abstract class, SQLiteOpenHelper. The first is the <code class="highlighter-rouge">onCreate()</code> method, which is where we will implement the logic to create our database. Lets look at how we can set up our first test for this class.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>package com.groceryreminder.data;
import android.database.sqlite.SQLiteDatabase;
import com.groceryreminder.BuildConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import static org.junit.Assert.assertEquals;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class ReminderDBHelperTest {
private static final String REMINDER_DATABASE_NAME = "grocery_reminder.sqlite";
private ReminderDBHelper dbHelper;
@Test
public void whenTheDBHelperIsCreatedThenTheDatabaseNameShouldBeSet() {
ShadowApplication context = Shadows.shadowOf(RuntimeEnvironment.application);
dbHelper = new ReminderDBHelper(context.getApplicationContext());
assertEquals(REMINDER_DATABASE_NAME, dbHelper.getDatabaseName());
}
}
</code></pre>
</div>
<p>Our first test expected that the database name is set correctly. This is accomplished in the constructor of the ReminderDBHelper, which calls the super class constructor. Lets get that test passing.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>//snip
public class ReminderDBHelper extends SQLiteOpenHelper{
//snip
private static final String REMINDER_DATABASE_NAME = "grocery_reminder.sqlite";
public ReminderDBHelper(Context applicationContext) {
super(applicationContext, REMINDER_DATABASE_NAME, null, 1);
}
//snip
}
</code></pre>
</div>
<p>Now that we have given our database a name lets move on to test-driving the creation of the tables we’re interested in.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@Test
public void whenTheDBHelperIsCreatedThenTheRemindersTableShouldBeCreated() {
ContentValues reminderValues = new ContentValues();
//Here ReminderContract.Reminders.DESCRIPTION is a column name in the database.
reminderValues.put(ReminderContract.Reminders.DESCRIPTION, ReminderContract.Reminders.DESCRIPTION);
insertReminderValues(reminderValues);
SQLiteDatabase readableDatabase = dbHelper.getReadableDatabase();
//Here ReminderContract.Reminders.PROJECT_ALL is an array of Strings representing the database columns we need
Cursor cursor = readableDatabase.query("reminders", ReminderContract.Reminders.PROJECT_ALL, "", null, null, null,
//ReminderContract.Reminders.SORT_ORDER_DEFAULT is a String representing the ORDER BY clause in a SQL query, minus
//the ORDER BY.
ReminderContract.Reminders.SORT_ORDER_DEFAULT, null);
assertTrue(cursor.moveToNext());
assertEquals(1, cursor.getInt(0));
assertEquals(ReminderContract.Reminders.DESCRIPTION, cursor.getString(1));
cursor.close();
cursor = null;
}
private void insertReminderValues(ContentValues reminderValues) {
SQLiteDatabase writableDatabase = dbHelper.getWritableDatabase();
writableDatabase.insert("reminders", "", reminderValues);
}
</code></pre>
</div>
<p>So, we’re doing a lot in this test. First, you’ll notice that nowhere in this test do we actually call <code class="highlighter-rouge">onCreate()</code>. This is because the <code class="highlighter-rouge">onCreate()</code> method is called when the SQLiteOpenHelper is created via the constructor as part of the Android framework. The next thing you’ll notice is that we get a handle on a writeable database to insert values into it, and finally we perform a query on a readable version of the database to get the values back out. This is how we test that the table we are about to create actually exists. Now we’ll implement the <code class="highlighter-rouge">onCreate()</code> method.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>//snip
private static final String CREATE_REMINDERS_TABLE_SQL =
"CREATE TABLE reminders (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
" description varchar(200) " +
" )";
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("ReminderDBHelper", "Creating the reminders table.");
db.execSQL(CREATE_REMINDERS_TABLE_SQL);
}
//snip
</code></pre>
</div>
<p>We now have a table called reminders two fields: id and description and our test should now pass. A very similar operation can be performed for the <code class="highlighter-rouge">onUpgrade()</code> method, with the exception that you’ll need to pass in a writeable database and call <code class="highlighter-rouge">onUpgrade()</code> directly (see <a href="https://github.com/jameskbride/grocery-reminder/blob/master/app/src/test/java/com/groceryreminder/data/ReminderDBHelperTest.java">ReminderDBHelperTest</a> for a full example).</p>
<p>This is the essential pattern for testing the an implementation of the SQLiteOpenHelper, which is the first step in providing data access in Android. The next step we will take will be implementing a ContentProvider, which acts as a standard interface and wrapper to hide data access implementation details from the rest of the app.</p>
<p>Thanks again and happy database creation!</p>James KirkbrideIt’s been a while since my last post in my Android TDD series, and I think it is time for the next entry. Previously we discussed test-driving view classes in Android, including Activities and Fragments. This laid the foundation for displaying content to the user. Having done that we can now focus on providing that content.Stop Talking Yourself Out of Good Ideas2016-01-10T00:00:00-05:002016-01-10T00:00:00-05:00http://jameskbride.com/2016/01/10/stop-talking-yourself-out-of-good-ideas<p>So this past week I attended <a href="http://www.codemash.org/">Codemash</a>, and as always it was a real blast. Lots of great speakers, lots of great attendees, and just an overall great atmosphere (It doesn’t hurt that it is at an awesome water park either!). While I wasn’t speaking a number of my peers were, and on topics that I’m pretty familiar with. This got me to thinking. Why in the world didn’t I submit talks on any of these subjects? I certainly know enough to have given some of these talks! Android and TDD? Yes I could’ve done that, I’ve certainly made it through the fire on that one! Using Feature Toggles? We used them profusely on my previous project, I have a thing or two to say on them. The Command/Query design principle? Check. I told myself that no one wanted to hear me talk about those things, and besides, I have sooo many other things I was doing.</p>
<p>Rewind a couple of Codemashes back when I had an idea to create a speaker feedback site. I said to myself <em>“Why doesn’t Codemash (or any number of other conferences) have an easy way for attendees to provide feedback to the speakers?”</em> I know I would love to have something like this as a speaker, because honestly I could really use it. I immediately followed this thought up with <em>“That’s probably a waste of time, someone has probably done it already, and besides, no one is complaining about this”</em>. I didn’t follow up on the idea after that thought. This year I heard no fewer than half a dozen people state they wished something like this existed.</p>
<p>So why <em>didn’t</em> I submit anything? Why <em>didn’t</em> I build the feedback system? It’s not like I haven’t been a speaker before, and it’s not like I haven’t built things before. So what was it?</p>
<p>The problem was that I listened to that voice in the back of my head, the one that said I wasn’t good enough, that I didn’t have anything valuable to contribute. I listened to this quiet, fearful, voice that didn’t want me to put myself out there. This is the voice that says it’s easier to play it safe, to be <em>comfortable</em> where I am. This is the voice that is afraid that I’ll be criticized for my work, that I’ll be deemed <em>less than worthy</em>.</p>
<p><em>This little, small-minded, fearful voice is full of shit.</em></p>
<p>Maybe you’re like me. Maybe you have had any number of good ideas, good opportunities to grow, good things you could share with the world. Maybe you’ve got that little voice in your head too, the one that is telling you to simply take it easy, the one that is telling you that you don’t know enough, or that no one wants to hear what you have to say.</p>
<p>I’m here to tell you stop listening to that voice and to follow up on your good ideas.</p>
<p>Take those ideas and run with them. Don’t think about what might happen if you fail. You know more than you give yourself credit for, and are capable of more than you believe. Give the talk, build the thing, and I’ll do the same.</p>Jim KirkbrideSo this past week I attended Codemash, and as always it was a real blast. Lots of great speakers, lots of great attendees, and just an overall great atmosphere (It doesn’t hurt that it is at an awesome water park either!). While I wasn’t speaking a number of my peers were, and on topics that I’m pretty familiar with. This got me to thinking. Why in the world didn’t I submit talks on any of these subjects? I certainly know enough to have given some of these talks! Android and TDD? Yes I could’ve done that, I’ve certainly made it through the fire on that one! Using Feature Toggles? We used them profusely on my previous project, I have a thing or two to say on them. The Command/Query design principle? Check. I told myself that no one wanted to hear me talk about those things, and besides, I have sooo many other things I was doing.Grocery Reminder - An Open-Source Android App2015-11-01T09:36:00-05:002015-11-01T09:36:00-05:00http://jameskbride.com/android-series/2015/11/01/grocery-reminder-open-source-android-appI'd like to announce that my first Android app, the <a href="https://play.google.com/store/apps/details?id=com.groceryreminder&hl=en" target="_blank">Grocery Reminder</a>, has been made Open Source, and released under the MIT License. You can find the source on my <a href="https://github.com/jameskbride/grocery-reminder" target="_blank">Github</a> account.<br /><br /><h2>Why Open-Source?</h2><div>Some of you are probably asking why I decided to make my first app Open-Source. After all, I put significant time and effort into this project. The truth of the matter is that I created the app as part of a contest with my current employer in order to learn more about Android development. In terms of how useful the app has been, let's just say it let me scratch an itch and my wife uses it on a regular basis, which is good enough for me. </div><div><br /></div><div>Beyond that I learned quite a bit about Android over the six months or so that it took me to develop it, and I've been able to leverage what I've learned in order to write a series of posts on <a href="/android-series/2015/05/28/android-tdd-series-setup.html">Android and Test-Driven Development</a>. I did this to show that TDD and Android were not water and oil, and that it is more than possible to write test-driven mobile apps. I'll continue to use this code for examples for the remainder of the Android TDD series, which I hope will benefit Android developers in one way or another.</div><div><br /></div><div>Releasing this app as Open-Source software is an extension of the goals I mentioned above; I'm putting this code out there in the hopes that others will learn from it. Whether that is learning a better way of developing and test-driving Android apps or simply learning from my mistakes is up to each developer to decide. </div><div><br /></div><div>So there it is. The code is out there and I encourage you to check it out, hack on it, maybe even issue a pull request or two. I look forward to any feedback you might have, and happy hacking!</div>James KirkbrideI'd like to announce that my first Android app, the Grocery Reminder, has been made Open Source, and released under the MIT License. You can find the source on my Github account.Why Open-Source?Some of you are probably asking why I decided to make my first app Open-Source. After all, I put significant time and effort into this project. The truth of the matter is that I created the app as part of a contest with my current employer in order to learn more about Android development. In terms of how useful the app has been, let's just say it let me scratch an itch and my wife uses it on a regular basis, which is good enough for me. Beyond that I learned quite a bit about Android over the six months or so that it took me to develop it, and I've been able to leverage what I've learned in order to write a series of posts on Android and Test-Driven Development. I did this to show that TDD and Android were not water and oil, and that it is more than possible to write test-driven mobile apps. I'll continue to use this code for examples for the remainder of the Android TDD series, which I hope will benefit Android developers in one way or another.Releasing this app as Open-Source software is an extension of the goals I mentioned above; I'm putting this code out there in the hopes that others will learn from it. Whether that is learning a better way of developing and test-driving Android apps or simply learning from my mistakes is up to each developer to decide. So there it is. The code is out there and I encourage you to check it out, hack on it, maybe even issue a pull request or two. I look forward to any feedback you might have, and happy hacking!