The smallest git tutorial you’ll ever need

Let me preface with this: this is over-simplified for someone just getting started with git, who does not have the time to learn all the intricacies of git, and covers the most common workflow I’ve encountered, that is:
– download code from a remote repository
– make changes
– commit and send the changes back
– get the latest from that remote repository

So, here goes:

First you’ll need to install git is it is not aleady installed.

Checkout a project

git clone http://github.com/psq/spider.git

Commit

Edit files as you see fit, then when time comes to commit your changes back in:

git status

will show you what files you’ve modified. Or added. If you added any files, add them to the files controlled by git (this also works with a new directory and will recursively add everything)

git add README.txt

Then commit all

git commit -a -m "added readme"

-m option adds a messages, -a adds all modified files to the commit

Upload your changes

Then push your changes back to the original repo

git push origin master

Download the latest version

And finally, to get any updates from the master repo (you may need to do this before doing the push above)

git pull origin master

This is overly simplified on purpose, but will give any beginner time to dive in deeper when time permits.

See this previous post for some helpful git shortcuts

Simplicity is the Ultimate Sophistication

As Saint Exupery said,

A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away.

And Joshua Porter adds:

Simplicity is treading a line: knowing what to keep and what to throw away. It comes across as magic when it works, because none of the complexity is transferred to users, only simplicity.

Nothing to add, really (emphasis mine)

(from Five Principles to Design By)

after_method

It started innocently enough. I was writing a Rails Plugin, and needed to call a Class Method on a Model. No problemo, right? In init.rb just call the method (To register a renderer in this case).


  Site.register_template_handler(".erubis", ErubisTemplate)

The method goes on and adds some date to a Class Variable. I try it and it worked…

… For the first request only :( After that, the data is gone from the class! What gives???

Well, there is a very convenient mechanism that reloads all your models, views and controllers so you don’t have to restart your app every time you make a change. Except here. Once the class gets unloaded, BAM! There goes the Class Variable and my carefully registered renderer.

First Solution

The code responsible for unloading and reloading all the models, views, and controllers is Dispatcher.reset_application!, so why not piggy back on reset_application! ? So using alias_method_chain, after a few iteration, here’s what I came up with:


  class << Dispatcher
    def register_erubis_template
      Site.register_template_handler(".erubis", ErubisTemplate)
    end
    def reset_application_with_erubis_registration!
      returning reset_application_without_erubis_registration! do
        register_erubis_template
      end
    end
    alias_method_chain :reset_application!, :erubis_registration
  end
  Dispatcher.register_erubis_template

Since reset_application! is not called till the second request, I had to also call the registration method once, which is why I created a register_erubis_template method.

It now worked. That was nice. But, then I started implementing a second plugin, which needed the same code. Not very DRY.

So I wrote down what ideally I wanted to end up with:


after_reset_application {
  Site.register_template_handler(".erubis", ErubisTemplate)
}

So next time I have the same problem, I can just reuse the same after_reset_application call with any other code I need to run after all the classes get unloaded.

Lots of aborted attempts

Foolishly, I thought it would be quite easy to transform what I had into something reusable. A little dose of Monkey Patching here and there, a bit of Meta Programming, and there you have it. Well, I did not keep all the many iterations I tried, here are just a few that did not work for one reason or an other (I did not try to find out why, just moved on to the next attempt)


  Dispatcher.alias_method_chain :reset_application!, #{feature}
  Dispatcher.class_eval do
    def reset_application_with_#{feature}!
      returning reset_application_without_#{feature}! do
        register_#{feature}
      end
    end
  end

def after_reset_application(feature, &block)
  patch = <<-end_eval
    class << Dispatcher
      def register_#{feature}
        proc
      end
      def reset_application_with_#{feature}!
        returning reset_application_without_#{feature}! do
          register_#{feature}
        end
      end
      alias_method_chain :reset_application!, #{feature}
    end
  end_eval
  eval patch#, &block, __FILE__, __LINE__
  Dispatcher.send "register_#{feature}"
end

Use the singleton-class, Luke! Use the singleton-class!

Then I retrieved a post from Ola Bini that I had read some months back: The ruby singleton class and I started to make some progress after I understood that to define methods, I needed to do it on the singleton class, not the class itself, because even though it did not fail, it did not accomplish much. And finally arrived at:

To retrieve that singleton class:


class << Dispatcher; self end

So now, I finally arrived at this code:


require 'dispatcher'

def after_reset_application(feature, &block)
  class << Dispatcher; self end.class_eval do
    define_method("register_#{feature}", &block)
    define_method("reset_application_with_#{feature}!") {
      returning Dispatcher.send("reset_application_without_#{feature}!") do
        Dispatcher.send("register_#{feature}")
      end
    }
    alias_method_chain :reset_application!, "#{feature}"
  end
  Dispatcher.send("register_#{feature}")
end

after_reset_application("erubis_registration") {
  Site.register_template_handler(".erubis", ErubisTemplate)
}

The key reasons why this works is that it is adding the methods to the singleton class, not the class itself. It is using send to be able to build the method names, and using alias_method_chain to be able to monkey patch reset_application! as many time as needed. I had to add a parameter to after_reset_application for the same reason, so it can be called more than once. And it uses define_method because you can give it a block, plus you can define the method name from variables.

All good, except that it is still not very DRY. What if I want to use the same technique on a different class? A different method?

The final version (for now?)

This one was easy, just add a few parameters, deal safely with ?, ! and = and there you go


def after_method(klass, target, feature, &block)
  # Strip out punctuation on predicates or bang methods since
  # e.g. target?_without_feature is not a valid method name.
  aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
  class << klass; self end.class_eval do
    define_method("register_#{feature}", &block)
    define_method("#{aliased_target}_with_#{feature}#{punctuation}") {
      returning klass.send("#{aliased_target}_without_#{feature}#{punctuation}") do
        klass.send("register_#{feature}")
      end
    }
    alias_method_chain target, "#{feature}"
  end
  klass.send("register_#{feature}")
end

Then, to implement after_reset_application:


require 'dispatcher'

def after_reset_application(feature, &block)
  after_method(Dispatcher, :reset_application!, feature, &block)
end

And to use:


after_reset_application("erubis_registration") {
  Site.register_template_handler(".erubis", ErubisTemplate)
}

Phew! The block gets called once the first time, and every time the classes need to be reloaded.

Don’t listen to your users, watch them

While looking for something else, I found this gem sitting around: First Rule of Usability? Don’t Listen to Users written by Jakob Nielsen.

Even though this was written almost 5 years ago, the main thesis is very valid in this web 2.0 age.

To make your web application more usable, don’t listen to how people tell you they want to do things (but do listen to what they want to do though). You are much better off watching them approach your application for the first time. Study how they get to know the various components or stumble on what you think should be a no brainer. Don’t hesitate to iterate, or experiment with different approaches. And when in doubt, simplify!

According to Jakob studies, asking people what they did is asking for trouble as you get filtered, rationalized reports that might lead you in the wrong direction.

The key is to find the right questions to ask when you can’t watch your users. For example if

“… 50% of survey respondents claim they would buy more from e-commerce sites
that offer 3D product views. Does this mean you should rush to implement 3D on
your site? No. It means that 3D sounds cool…”

Truly, you haven’t seen that many 3D interfaces, so avoid the cool factor. Instead, if there are similar features available in other apps, ask them for the one they keep going back to. By the same token, asking them why they like it might not yield the right answer either.

“The more a design supports users in easily and efficiently doing what they want to do, the more they like the design.”

Take del.icio.us for example, not much fancy design, but the functionality is there. Although you can achieve the same goal with a cooler design and better usability, take a look at www.blinklist.com.

So when designing your app, focus on the user first, and wrap a design around it to improve usability, not the other way around. In the end, though, design and usability go hand in hand and you can’t do one without the other and they build on each other to create a masterpiece.

Just Enough is More

To quote Milton Glaser: “Less is not necessarily more. Being a child of modernism I have heard this mantra all my life. Less is more. One morning upon awakening I realised that it was total nonsense, it is an absurd proposition and also fairly meaningless. But it sounds great because it contains within it a paradox that is resistant to understanding. But it simply does not obtain when you think about the visual of the history of the world. If you look at a Persian rug, you cannot say that less is more because you realise that every part of that rug, every change of colour, every shift in form is absolutely essential for its aesthetic success. You cannot prove to me that a solid blue rug is in any way superior. That also goes for the work of Gaudi, Persian miniatures, art nouveau and everything else. However, I have an alternative to the proposition that I believe is more appropriate. ’Just enough is more.’”. Emphasis mine.

This is timeless and fortunately, it seems that more and more people are realizing that this can also apply to software! I love it :)

My gratitude goes to Jason Kottke for having this quote available on his site.