h

Being Agile

Pete Hodgson's blurgh

Stormcloud Will Watch Over the Unicorns.

| Comments

Hipster geeks crack me up. A nice ancillary benefit of being in this industry is I get to read blog posts about interesting technical stuff which also include phrases such as:


…we developed a new monitoring script, called Stormcloud, to kill Unicorns when they ran out of control…

…Monit would still monitor the master Unicorn process, but Stormcloud would watch over the Unicorns…

…child death during request processing … would cause that request and all requests queued in the mongrel to send 500 “robot” errors until the mongrel had been restarted…

No need to fear, children. Stormcloud will watch over the unicorns. And if all else fails, a mongrel will send 500 robot errors.


In case you were wondering, the blog post these come from is about Twitter’s app server infrastructure.

TickTock: A Dirt-simple Stopwatch Class for Actionscript

| Comments

I just threw together a really straightforward stopwatch class, for use when profiling operations in ActionScript code. You can either use it in an old-skool procedural way:
var tt:TickTock = new TickTock();
tt.start();
doSomeWork();
tt.stop();
trace( "That took "+tickTock.elapsedTimeInMilliseconds+" millisconds" );
or in a fancy-pants, functional, closure-y way:
var tt:TickTock = TickTock.measure( function(){
  doSomeWork();
});
trace( "That took "+tickTock.elapsedTimeInMilliseconds+" millisconds" );
Being primarily a ruby guy, I prefer the fancy-pants approach ;) The class, along with a little sample app, is up on GitHub now.

Why Do We Estimate Effort?

| Comments

I listened to a really good podcast yesterday on Kanban. One of the topics discussed was the fact that with Kanban estimating story points is optional. Most of my agile experience is with Scrum, so my initial reaction was one of mild disbelief. How can a team perform work without estimating effort! But when you think about it, why do we have this vaguely obsessive focus on story points in Scrum? Surely in other areas there are teams that get by perfectly well without having to determine up-front how much effort each item of work is going to require. What is the value in estimating? Here’s what I came up with:

  • Tracking velocity
  • Deciding on the scope for an iteration
  • Prioritizing stories (what will give us the most bang for the buck)
  • Release planning

I’m focused on the fine-grained estimations for individual stories here, so I’m just going to skip past the release planning stuff. My rationale being that for release planning you’re mainly going to use more course-grained estimates for a whole set of features, rather than estimating every single story. As to the value of story points for priotization purposes, I wonder whether there are many times where the decision is based on how much effort a story would take. Even if that was a factor on occasion, I would argue that the estimation process could be done ‘just in time’ for the relevant stories in the course of a brief conversation.

Really it seems that the main value in estimating story points is to allow a team to sign up for the appropriate amount of work for an iteration. If a team is using a Kanban approach then this isn’t really required. A team can just pull work through until they have enough releasable stories. At any point they can decide to make a release with whatever stories are complete at that time. The restriction of a hard timeboxed iteration just isn’t required.

So what are we left with? Tracking velocity. Is that actually useful enough to justify the cost of the estimation effort? I wonder. In my own experience it seems that estimating is a relatively painful part of the agile process. Most engineers just find it hard to do it well.

Hidden benefits?

While reflecting on the estimating and planning sessions I’ve done with teams in the past, I came up with one very valuable side-effect of the estimation process. In order to estimate well a team will need to discuss in detail what’s involved in a story. That can often reveal previously unrecognized dependencies, ambiguous or contradictory requirements, and so on. Perhaps there are other processes that would play a similar role if estimating were not being done? For example if a team is doing feature-driven development then they will probably flush out these kinds of issues as they are defining the acceptance criteria for a story. I’ve not worked on a team that doesn’t do story point estimations, so I’m not sure on this one.

It’s interesting to reflect that most of the benefit of estimating effort is done in order to support the agile process itself, rather than the actual creation of software. If a team wasn’t doing agile, it wouldn’t really need to estimate. In that sense it could be considered waste.

Primitive Obsession Obsessions

| Comments

After seeing the Primitive Obsession code smell crop up in a few different places recently I got to thinking about it in the context of static and dynamic languages.

Essentially this code smell refers to using a primitive data type (int, string, etc), or a cluster thereof, where you could instead be using an explicitly defined type. Probably the most common variant of Primitive Obsession would be a method like:

def is_point_within_bounds( x, y )
# ...
end

I would call this variant Primitives Travelling in a Pack. You’ll probably see these two x and y values hanging out together all over the place. Often this variant will be addressed with the Introduce Parameter Object refactoring, leading to something like:

class Point < Struct.new(:x,:y)
end

def is_point_within_bounds( point )
# ...
end

This is a pretty uncontroversial refactoring. It tends to make the code easier to read, and is often the initial stage in the ‘budding of’ of a full-fledged class (I believe I have the wonderful GOOS book to thank for that term). Once the class is there, it often becomes a locus for a little cluster of methods, often pulled in from surrounding client code. This is a powerful way of letting your design evolve based on needs.

There are other more subtle variants of Primitive Obsession. Some people would say that two methods like:

public class Rental {
  void increaseRentalPeriod( int numWeeks ) {
   //...
  } 

  int getRentalPeriod() {
   //...
  }
} 

would be better refactored to:

public class WeekSpan {
    public int numWeeks;
}

public class Rental {
  void increaseRentalPeriod( WeekSpan period ) {
   //...
  } 

  WeekSpan getRentalPeriod() {
   //...
  }
} 

Applying this refactoring can again be the first step in budding off a new class. However I would say that the main advantage of this refactoring is the explicit typing which it adds when in a statically typed language. Before refactoring there was an implicit typing going on that said “ints in this context actually represent a time period, in weeks”. After the refactoring that typing has been made explicit. One outcome of that is that type errors which were previously implicit are now explicit, and will be caught by the type system. Before the refactoring you could have written client code like

someRental.increaseRentalPeriod( numDaysToIncreaseRentalBy() );

and your compiler wouldn’t utter a squeak, despite the fact that you’re passing in a number of days, rather than the number of weeks which the method expects. With the explicit WeekSpan type, that error wouldn’t sneak through.

This explicit typing also helps with future refactoring. If we later decided that it would be better to represent the rental period using a number of days rather than a number of weeks we could use a automated refactoring tool to trivially replace all instances of WeekSpan with DaySpans (or we could just refactor WeekSpan itself into a generic TimePeriod). If we didn’t have the explicit WeekSpan class then we’d be reduced to manually searching for all the instances of the primitive int type which happened to actually be representing a time period in weeks.

This is all good stuff, and makes an awful lot of sense in a static language. However, I personally am not convinced that introducing these single-field data types makes as much immediate sense in a dynamically typed language. Both of the typing advantages are lost in a dynamic language. We don’t know the type of anything until runtime so we can’t check for type violations (however our unit tests help with that), and our refactoring tools can’t take advantage of static type information.

The other advantages of introducing these non-primitive types remain, but I would err towards the YAGNI principle. Leave the primitives where they are, and make a mental note that they might need some attention in the future. Once you see a need to move to a next step in the budding off process (e.g. moving a method into the nascent data type), then that’s the time to apply the refactoring. Doing so just for the sake of having an explicit type smacks of premature optimization to me.

Postscript

It’s interesting to note that some languages (such as Google’s Go) allow you to declare an explicit type which simply aliases a primitive. For example in Go you could write

type WeekSpan uint;

This might be the best of both worlds. You get the explicit typing and attendant type safety, without the potential overkill of creating an new single-field class. If you later discovered that budding off a new class was required it would be trivial to refactor that semi-primitive WeekSpan type into a full fledged WeekSpan class.

Encapsulating User Interaction Events in Flex

| Comments

When developing the presentation layer in a Flex application I like to follow an MVC/MVP pattern. I also like to keep my views nice and skinny, with as much logic as possible in the controller/presenter. However, I do like to encapsulate some of the details of the UI itself within the view, and so I shy away from exposing raw user interaction events (button clicks, list selections, etc) outside of the view. Instead I like to have the view capture those events and translate them into what I call user action events, which represent higher-level, user-centric interactions. So instead of publishing a ‘list item selected’ event, the view publishes a ‘blog post selected’ event. For example, here what a typical event handler would look like in a view’s MXML file:

private function onListItemDoubleClick(event:ListEvent):void {
  dispatchEvent( new Event(EVENT_postSelected) );
}

This allows small user experience tweaks (e.g. double clicks to select vs single clicks) without affecting clients of the view. More importantly it helps the view expose a consistent, user-centric level of abstraction - its interface talks in terms of user actions, not UI minutia. A view’s controller would register listeners for these user action events via the generic IEventDispatcher::addEventListener(…) exposed by the view, and process them appropriately in the registered listener callback:

public class Controller
{
  //... 

  public function bindToView(view:IView):void {
    _view = view;
    //...
    _view.addEventListener( View.EVENT_postSelected, onPostSelected );
  }
  
  //...

  private function onPostSelected(event:Event):void {
    //... process user action here
    //...
  }
}

One thing to note in passing (we’ll come back to it) is the ugly fact that while bindToView(…) is dealing with an abstract interface (IView), it still needs to reference the concrete View implementation in order to get to the View.EVENT_postSelected constant. In real terms the controller class has a dependency on the concrete view implementation.

Back to the story. I want to make sure that my controller processes these user actions correctly, which for me means I need good unit test coverage of the listener callbacks which the controller registers. These callbacks are private methods, so therefore I need some way of simulating the occurrence of these user actions within the unit tests for my controller. Typically when unit testing a controller I arrange for it to be bound to a stub implementation of the view. To simulate these user actions I could have that stub implementation derive from EventDispatcher. During test setup the controller would be bound to the stub view, and as part of that process would subscribe to these user action events. Subsequently my test code could artificially fire the appropriate event within a test case using EventDispatcher::dispatchEvent(…) in order to simulate a given user action occurring.

public class StubView extends EventDispatcher implements IView
{
  // other stub stuff here
}

public class ControllerTests 
{

  [Before]
  public function setUp():void {
    // instantiate controller, instantiate stub view, bind controller to stub view, etc...
  }

  [Test]
  public function doesSomethingWhenPostSelected():void {
    // ... set up test
    simulatePostSelected();
    // ... verify expectations
  }

  // .. other tests

  private function simulatePostSelected():void {
    _stubView.dispatchEvent( new Event( View.EVENT_postSelected ) );
  }
}

This has always felt a little hacky to me, and I started to wonder if that feeling indicated a design flaw (I find that when something feels wrong when writing tests it often points towards a design deficiency). So recently I started experimenting with another approach. Instead of the controller registering event callbacks on the view directly with addEventListener(…), the view exposes methods which do the registration on the controller’s behalf. I call these interest registration methods. Instead of the controller calling view.addEventListener( SOME_EVENT_TYPE, my_callback ), it calls view.addUserActionListener( my_callback ).

 // ... in the view MXML
 // ...
 public function addPostSelectedListener(listener:Function):void {
   addEventListener( EVENT_postSelected, listener );
  }

// ... in the controller
// ...
  public function bindToView(view:IView):void {
    _view = view;
  //...
    _view.addPostSelectedListener( onPostSelected );
  }

In production code the view implements these interest registration methods in the same way as the controller did before - by calling addEventListener(…) with the appropriate event type and the callback supplied by the caller. The code is the same, it’s just moved from the controller to the view.

The effect this has is quite powerful however. The fact that events are used as the mechanism for invoking the callback is hidden within the view. This becomes interesting when you come to test your controller. Instead of subscribing to events, your stub implementation of the view can implement the interest registration methods by just holding the callback in a instance variable. When the test wants to simulate a user action it can ask the view for the registered callback and call it directly, bypassing the Flex eventing mechanism entirely.

public class StubView implements IView
{
  public var postSelectedListener:Function;
  public function addPostSelectedListener(listener:Function):void {
    postSelectedListener = listener;
  }

   // .. the rest of IView implemented here
}

public class ControllerTests
{
  // ... every thing else as before

  private function simulatePostSelected():void {
    _stubView.postSelectedListener( new Event( 'ignored' ) );
  }
}

What’s more interesting is the effect this change has on the interface exposed by the view. Previously we had a view which exposed implementation details - the fact it was handling client callback registration using EventDispatcher), and most tellingly the string constants which identify different event types. We also had different levels of abstraction being exposed in the same interface. Typically the other parts of the view interface worked on the high level of user actions, not on the low level of events being fired of a particular type. With the migration to the interest registration methods we have a consistent level of abstraction, and we can hide all the messy implementation details of the eventing mechanism. Those annoying public event type strings become private and hidden away within the view; an implementation detail. We can even totally encapsulate the fact that the view inherits from EventDispatcher. The explicit interface also feels more typesafe to me. It’s impossible to accidentally register for an invalid event code, and it’s immediately obvious from the view’s interface which user actions it reports.

There are some drawbacks to this approach. Because we’re abstracting away the details of the event dispatching mechanism we’re also hiding some of the advanced facilities that mechanism provides. For example the approach as described doesn’t allow a client of the view to unregister its interest, which would usually be accomplished using IEventDispatcher#removeEventListener(…). I would argue that this is a reasonable price to pay. If that functionality is required in some situations it would be straightforward to add, and because it would be explicitly added as a new method in the view’s interface it would be clear that the view was expecting clients to use that method.

All in all I’m very happy with how this experiment turned out. By paying attention to the ‘smells’ that my tests were exposing I discovered a valid issue with the way different parts of my code interacted. I would argue that changing that interaction to make the tests cleaner does seem to have lead to a cleaner design overall.

Ruby Facets: The Mash Method

| Comments

I keep meaning to write up some of the useful gems (if you’ll pardon the pun) which are hidden in the super-handy Facets gem. Today I’ll cover Enumerable#mash.

Let’s say you have a list of Users, and you’d like to create a hash which lets you look up the Users based on their login. You might write something like:

def create_login_hash_for( users )
  user_login_hash = {}
  users.each do |user|
    user_login_hash[user.login] = user
  end
  user_login_hash
end

With Enumerable#mash, you can trim that down to:

def create_login_hash_for( users )
  users.mash do |user|
    [user.login,user]
  end
end

This is much more succinct. More importantly, it expresses the intention more clearly.

Partial Commits With Git

| Comments

I’ve been using git for a few months now. Like all the best dev tools it has slowly permeated my workflow to the point where I’d feel pretty crippled without it. In fact, I don’t think I would ever go back to a centralized system like svn at this point. In a pinch I’d fall back to using git locally and then using the appropriate git-to-foo integration to push my local changes from my git repo to whatever the centralized repository was.

So, git is great. However, there’s one practice which is common amongst git users which I am still uncomfortable with (even though I do it myself on occasion). I’m referring to the practice of staging some, but not all, of the changes in your working tree to the index, and then committing that partial change set. For example, let’s say I’ve been hacking away on my stamp collector application. I added the ability to ‘tag’ stamps (folksonomy now being mainstream enough to appeal to your average philatelist). While I was working, I also fixed a couple of badly named methods that I happened to come across during my other changes. With git I can decide to commit these changes separately, through judicious use of the index. I can say ‘add changes to files x and y to the index, but leave out z for now’, then commit, then add the changes to file z to the index, and then commit that change. If I want to get really fancy I can even add some of the changes to a file to the index, but not all changes. This way I can seperate my changes into two logical commits, one for the feature addition of tagging stamps, and one for the miscellaneous method name cleanup.

This is definitely one of those features that is very cool once you realize the power it offers. It means someone else reviewing my commits will have an easier time, and it even means that I could roll back my feature addition change but still keep the method name cleanup work. Still, I would submit that this can be a Bad Idea.

Why does this concern me? Because any such partial commits haven’t been tested before being commited. At this point you might be thinking “Well, don’t know about you, but I run my tests before each commit”. The point here is that the tests run before you commit are run against your working tree, which in the world of git isn’t necessarily the same as your commit. In the Good Old Days of svn, the changeset in your working tree was always the same as the changeset in your commit. With git and the index (aka the stage, aka the cache, don’t get me started on that) that’s not the case. Your working tree may contain changes to files x, y and z, but you’ve decided to only commit the changes to files x and y. Or even more extreme, you’ve decided to commit the changes to file x but only some of the changes to file y (maybe the other changes where related to your method renaming binge). So you’re running your tests against one set of code (your working tree, with changes to x, y, and z), but your commit is another set of code. I think that ninety nine times out of a hundred this distinction won’t matter. Your “technically untested” commit would still have passed the tests anyway. Plus, what you’re almost certainly following it up straight away with another commit which will be the same as your working tree. What are the chances that someone will manage to stumble upon an invalid state like that. Probably really low. But still, kinda scary I think. It seems a bit like saying “well, this race condition is really unlikely to happen, right…”. I’d rather not have to even think about that. Another thing to consider is the ‘cool’ use case that someone could decide to revert one commit but not the other.At that point you have code sitting on head that hasn’t been tested.

One solution to this would be to ban the use of commits that don’t include all changes in the working tree. Yeah, right. Not likely, and not helpful. Staging is definitely a useful way to add more structure to your change history, and not something I’d like to leave behind.

I wonder if a better solution could be achieved with the judicious use of commit hooks. What if we had a pre-commit script that would take the change set that was about to be committed (NOT whatever is in the working tree) and run tests against that tree. If the tests fail the commit fails. Now we would be left in a place of greater confidence than before. We wouldn’t even need the discipline to run the tests by hand, because even if we forgot then git would be running them for us anyway. To be honest I’m not sure of the feasibility of creating this kind of setup. I’d love to find out more about how feasible it would be.

Option number 3 would be to have a CI pipeline such that you don’t ever commit changes to a branch that others can touch until the CI system has had a chance to run tests against your commit. Instead, you would always be commiting changes to a private branch. The CI system would detect your commit, run a build, and then merge your changes into a shared branch if and only if your commit passed muster. I don’t think this would prevent commits in the middle of a batch of commits being pushed to your private branch from bein un-tested, but it would prevent the system ever getting into a state where the shared head is untested. This is an idea I’m planning to blog about more at some point in the future.

In conclusion, while I find myself sometimes taking advantage of this powerful feature of git, I always feel a little nervous doing so, and try and take extra care.

An Inverted Include? For Ruby

| Comments

I’ve always found it a slightly hard to read ruby which uses Enumerable#include?(), especially when the Enumerable your testing against is a literal or a constant. For example, let’s say you’re checking an input parameter to guard against invalid input. You might write something like:

unless VALID_COMMANDS.include?( command_param )
  whine_to_user()
  return
end

This makes sense, but it seems backwards to me. I don’t care whether some array has a value in it so much as I care whether a value is in some array. Obviously that’s just two ways of saying the same thing, but the latter seems to capture the intent much more to me. I think it would be easier to understand this:

unless command_param.in?( VALID_COMMANDS )
  whine_to_user()
  return
end

This evening it (finally) dawned on me that this would be ridiculously trivial to implement:

class Object
  def in?( enumerable )
    enumerable.include?(self)
  end
end

In fact, this was such a trivial fix that I’m now left wondering (a) whether this is already in ActiveSupport or Facets or whatever and I just haven’t found it yet and (b) whether there’s some huge flaw in this that I’m not spotting…

Flex Patterns: Presentation Adapter

| Comments

Flex Patterns: Presentation Adapter

Encapsulate the logic for presenting a domain object, and provide an object for skinny views to perform data-binding against.

Problem

When using Presentation Model our goal is to bind UI elements in your Skinny View directly to individual components of the Presentation Model. This requires translating information in Domain Model instances into a presentation-specific form. At the same time we need to be able to map back from that presentation-specific form to the underlying domain model instance in order to present user interactions in terms of our domain model.

Context

We are developing a UI component in a Flex application using some form of MVC/MVP. This UI component will be displaying information about a domain object, e.g. a list of Users. We are using the Presentation Model pattern or similar, so we want Skinny Views.

Forces

  • We need to transform information from a Domain Model class into something suitable for display
  • We want to keep formatting logic out of the view, using Flex databinding from view controls to a Presentation Model
  • We want to keep formatting logic out of the Domain Model, because it’s presentation-specific, and not the responsibility of the domain model.
  • Clients of our UI component expect to interact with it using instances of the Domain Model class. For example, clients should be able to pass in a list of Domain Model instances to display, and the UI component should publish events which refer to Domain Model instances.

Solution

We can use a Presentation Adapter (PA) to wrap a domain object (an instance of a Domain Model class). The PA provides a presentation-specific formatting of some or all of the information represented by that domain object. The PA also exposes a reference to the domain object itself. This allows UI component code to map from the PA back to the domain object is represents when reporting user interactions back out to clients of the UI component.

Example

Let’s say we are creating a Post Listing component which lists a collection of blog posts, and allows the user to select specific posts from that list. Our Presentation Model needs to include a collection of posts to list, and our View will contain some kind of list control which will be bound directly to that collection of posts. We want each post to be listed in the UI using a specific format, which will include the post title and the number of comments associated with the post. The application’s Domain Model contains a BlogPost class, and our component is expected to expose an interface which talks in terms with BlogPost instances. The client of the Post Listing component will supply a collection of BlogPost instances which it wishes to be displayed in the list. When a user selects a post the component’s client expects to receive a ‘post selected’ event which includes the BlogPost instance that was selected by the user. In other words, the client does not need to know anything about the Presentation Adapter we will be using.

We’ll create a PostPA class which will act as a Presentation Adapter for the listing. It will expose a label field. The Presentation Model can hold a list of these PostPAs (one for each BlogPost supplied to the Post Listing component), and the View’s list control can be bound directly to that list of PostPA instances.

We also need some simple formatting logic which transforms a BlogPost instance into the appropriately formatted string which will eventually be shown in the list control. That formatting logic should live within the Post Listing component, as it’s presentation-specific. In fact it’s likely that the formatting is specific to this particular UI component. The Presentation Adapter is a good place to put this formatting logic (although there are alternatives which I’ll see below in the Variants section).

public class PostPA
{
 private var _post:BlogPost;
 
 public function PostPA( post:BlogPost )
 {
  _post = post;
 }
 
 public function get label():String
 {
  return _post.title + " ["+ post.comments.length+" comments]";
 }
 
 public function get post():Post
 {
  return _post;
 }

}

We also need to map from BlogPost instances to PostPA instances, and vice versa. We’ll put that logic in our Presentation Model. core UI logic can supply the Presentation Model with a collection of BlogPost instances, and the view will be updated with a list of corresponding PostPA instances.

public class Model extends EventDispatcher
{
 function Model(){
  _postPAs = [];
  _selectedPostIndex = -1;
 }
 
 private var _selectedPostIndex:int;
 private var _postPAs:Array;
 
 public function get selectedPost():Post
 {
  if( _selectedPostIndex < 0 )
   return null;
  else
   return _postPAs[_selectedPostIndex].post;
 }
 
 public function set selectedPostIndex(index:int):void
 {
  _selectedPostIndex = index;
 }
   
 public function set posts(posts:Array):void
 {
  _selectedPostIndex = -1;
  _postPAs = posts.map( function( post:Post, i:int, a:Array ):PostPA {
   return new PostPA(post);
  });
  dispatchEvent(new Event("postPAsChange"));
 } 
 
 public function get posts():Array
 {
  return _postPAs.map( function( postPA:PostPA, i:int, a:Array ):Post {
   return postPA.post;
  });
 }
 
 [Bindable (event="postPAsChange")]
 public function get postPAs():Array{ return _postPAs; }
 
}

Our Post Listing component needs to send an event whenever a user selects a post, and that event needs to reference the BlogPost instance that was selected. To that end, the Presentation Model also exposes methods which allow the view to update the selected post based just on a list index, while the core UI logic can ask for the underlying BlogPost instance which was selected. Now, when the list control sends an event saying an item has been selected the View can update the Presentation Model appropriately and then signal the core UI logic. That logic can then ask the Presentation Model for the selected BlogPost, and dispatch a ‘post selected’ event, including that BlogPost instance in the event.

Variants

The decision on where and when the presentation formatting logic is done defines several variants on this pattern.

Dynamic Presentation Adapter

Presentation formatting logic lives in the PA class, and the formatting is performed on-the-fly as the view requires it.

Static Presentation Adapter

Presentation formatting logic still lives in the PA class, but the formatting is done at construction time. Depending on usage patterns this could be more or less performant than the Dynamic Presentation Adapter variant.

Dumb Presentation Adapter

Presentation formatting logic lives within the Presentation Model which is creating the Presentation Adapter. In this case the Presentation Adapter itself becomes a simple value object with no logic, or even just a dynamically created object.

Related Patterns

Generally a Presentation Adapter will be used in the context of a Presentation Model, where the Presentation Model contains instances of one or more Presentation Adapters (collections or otherwise). A Presentation Adapter is a specific form of the GoF’s Adapter Pattern.

Alternative Patterns

Instead of a Presentation Adapter one could use a Transformer/Mapper, where a single Mapper instance performs the presentation-specific formatting for a whole class of domain objects. This Mapper is attached to the UI control as part of the binding mechanism, and does the formatting on the fly. The Mapper could be a simple Function, or an instance of a specialized Mapper class.

How Much Code Did I Just Delete?

| Comments

Today I had the great pleasure of deleting a huge chunk of old code from my application. Using git it’s surprisingly easy to figure out exactly how much code:
 
git checkout -b deletion_task

# ... delete lots of code...
# ... time passes...

git add -i
git commit
git co master
FILES_DELETED=`git diff --summary master deletion_task | grep "^ delete" | wc -l`
LINES_DELETED=`git diff --summary master deletion_task | grep "^ delete" | awk '{ print $4 }' | xargs cat | wc -l`
echo -e "$FILES_DELETED files deleted.\n$LINES_DELETED lines deleted."