Setting up a Mac for Development

Recently I got a new Mac and setting up for development is always fun, so I decided share some of the setups I do on a new Mac.

Is a Mac a good machine for development?

I think so and also know folks that think Linux is better, some are more use to Windows. In the end I think is not the OS which makes a better development machine (although there’s space for some debate here) but how you deal with it. Take a look on The Productive Programmer by Neal Ford for some other tips.

What to keep in mind

As you setup a machine for development some things you should keep in mind. First is you want to lower the keyboard to mouse time. Taking your hands off the keyboard to point to a link in a webpage and then going back is time consuming, a developer goes from the IDE to the browser lots of time during the day.

Make the computer do what you’re thinking without much effort, few keystrokes should take or do what you want. Going through menus, mouse, chasing windows on the desktop are also time consuming, unproductive and (for me) annoying.

If you do twice, think about how to do with one keystroke. If you caught yourself repeating something, think in a way to automate it (if makes sense). Apple has AppleScript and Automator which you can use to make simple scripts for mundane things.

Keep your projects and files organized, this goes for every developer. Not knowing where the files are leads you to browsing around to find them, avoid that. I have a Projects directory and an alias gp that goes to this folder, plus gp project takes me direct to the project folder. If you have some suggestion please do so (use the comments), I’m keen to know how you make your environment more smart and fast.

Now, some of the things I do on my Mac for development.

Disabling the Dashboard

I tried to use, make some meaningful use of it but never achieved, it just sit there. In Lion it turned to be a little more annoying as it shows on Mission Control view. Disabling the Dashboard is pretty easy, go to the terminal and issue this command:

defaults write com.apple.dashboard mcx-disabled -boolean YES

And restart the Dock:

killall Dock

Get iTerm 2

OS X has its Terminal application but iTerm 2 has some features that I really like, one is the Hotkey Window which you can trigger by a keyboard shortcut and it come and goes easily.

One tip for Lion users, if you use multi desktops set iTerm 2 to be available in All Desktops. You can achieve this by control + click on iTerm icon in the Dock and selecting Options – Assign To – All Desktops. This way when you invoke Hotkey Window it will not shift from desktop to desktop.

Get QuickSilver

QuickSilver is a very powerful application for action at distance. Some of you might know Alfred (check the app store), in Linux the Gnome Do and on Windows I recall Launchy.

On a Mac I prefer QuickSilver, mind that it is not just a Application launcher it can do a lot more than launch applications.

Get Dropbox

I use dropbox for a lot of file transferring and storage, specially when I change machines it helps to avoid the USB stick protocol.

Get Caffeine

A development machine that keeps dimming the monitor, going to screensaver and sleeping because you took more than five minutes to type doesn’t help you. Caffeine when on don’t let this happen, it’s way more easy than changing Energy Saver configurations.

Get iStat Menus

This one is paid. I use to keep and eye on CPU, Memory, Hard drive access and Network usage. Also it can replace the battery level indicator and the date menu on the Mac. This is a habit that I’ve acquired working with Linux for long time and Bubblemon.

Get Xcode

Although I don’t develop for Mac, Xcode is needed because it brings a lot of libraries for development that it’s needed for a dev.

Get Home Brew

Or another package manager for Mac as MacPorts. You will need to install other packages into your Mac. Unless you’re a fan of compiling everything you need something similar to apt-get to your Mac.

Get GleeBox

I can’t image myself using a browser without GleeBox. It makes easier to find links, form items, issue bookmarkslets on a page and more. Is one more application to lower the keyboard to mouse time.

Turn on keyboard access to all controls

In the System Preferences go to Keyboard then keyboard shortcuts and turn All Controls. Now you can use tab to navigate through windows buttons and fields.

If you use Safari, turn “Tab” for links

It doesn’t come with the “Tab” to links enabled by default, just to go to its preferences advanced and turn Press Tab to highlight each item on a webpage.

Get a real Text/Code editor

I use Vim and usually is the first thing that I install in any computer that I use. MacVim is the Vim for a Mac. Also I don’t like the menu if you also don’t like add to your ~/.gvimrc:

set guioptions=-T

Learn some common shortcuts of OS X

One of the good things about Apple software is it tries to be consistent over the keyboard shortcuts. The famous Command + , in almost every software that runs on a Mac takes you to the preferences of the app.

Another good one is Command + ? which takes you to the help menu, plus there’s a search that can show you a entry on the menu. If the app doesn’t not provide a shortcut for the action you’re trying to make you can use this one to go there.

Changing PATH variable in a more organized way.

This is more a note to self than a full post. This week I’ve been configuring my new laptop and again I had to configure the PATH variable for some applications and scripts.

Usually you will create a .bash_profile at your home folder and change the PATH like this:


PATH=~/bin:/some/new/application/bin:${PATH}

export PATH

Two simple Bash functions can make this more elegant, I have:

unset partial_path
_push_to_path () {
	if [ -z ${partial_path} ]; then
		partial_path=${1}
	else
		partial_path=${partial_path}:${1}
	fi
}
_export_path () {
	export PATH=${partial_path}
	unset partial_path
}

And then you can on your .bash_profile:

_push_to_path "~/bin"
_push_to_path "/some/new/application/bin"
_push_to_path $(launchctl getenv PATH)
_export_path

This is a little more organized and easy to maintain. Note the last line, on OS X you can add back the system path by asking launchctl to give you the system environment entry for PATH.

That’s it.

Jumping Abstractions

This is not more than a thought experiment, if you not into software philosophy probably this will be too boring. Abstraction is a ubiquitous word in software development, layer abstraction, storage abstraction, and so on. Abstraction is defined as the act of abstract and this word has some curious definitions:

“to consider apart from application to or association with a particular instance”
“remove, separate”

In software development we often use abstraction with meanings similar to these. Remove or separate from something, in example, abstract the fact that you deal with computer memory. Separate your storage implementation details in order to deal with it like has a common idiom to persist data. Abstract the data structure and deal with objects, objects by definition are abstractions that actually have data and behavior but these are removed from your eyes (the API) so you can construct more abstractions by aggregating them.

My thought experiment is that software development is nothing more than abstracting to a user level acceptance. The interesting part is that this level changes over time, specially because we can reach more powerful abstractions given the growth of hardware capacity and new interfaces with users. If these words seem too abstract (pun intended), let me try to make a more concrete example.

Games are a good example, in the beginning they were text based, that was the interface we had, that was the capacity that we had to deliver it. Humans, played these games and like it, even with a great distance from the simple letters on the screen to their imagination. This phenomenon is well understood and used in the form of books.

Hardware evolved and games turn to have a more graphical interface, moving pixels got people excited, then 2D graphics, 3D and so on. As other softwares, browsers, social networks and even accounting. Whatever users are able to deal in an abstract level we try to reach, we try to develop interfaces that will match current user acceptance to deal with such abstraction. Might be the case that holographic interfaces (once invented) will be the only acceptable interface to browse the internet.

Keeping this line of thought, we can think about our current infra-structure to develop software. We have virtual machines that try to abstract the hardware, the hardware actually has software that tries to abstract itself, like how to write on the hard disk, access the memory or ask for the CPU to compute an instruction. Several levels of abstraction have to be in place for a piece of software be useful to a user, when this user is not an engineer inside the chain of making abstractions.

Thinking about this chain, we can see there’s a limited number of abstractions that a developer to deal with, it is not feasible for a developer implement from the lowest layer to today’s UI. Meaning that development nowadays needs at least some lower layers working and well defined in order to produce higher ones. On software evolution we see that more and more layers are being defined and more and more people are involved directly or indirectly. Correctness of lower layers is important in order to achieve stability on higher ones. As my friend Aravind SV wrote: “In my view, abstractions are one way of handling complexity within a system. Another way of abstraction is to actually hide it, by moving to smaller, totally independent sub-systems, which communicate with each other through well-defined interfaces.”

There are a couple of questions that pop into my mind. With the quality of software developed nowadays is possible to have better abstractions in the future? Is all software doomed by its inherent complexity? Hardware is physics business, high cohesion on these rules, are we reaching the limit of our ability to develop software since it has no fixed rules?

Like firmwares, our current software has to be reliable and error tolerant to some level, if not, it will not be possible to grow new structures with foundations cracking. Businesses, not knowing this, if not thinking about quality of software they produce, are only producing stuff that will be replaced by other business software, the revenue that comes today will not resist evolution.

By Chance Metric

Inspired by my recent readings of The Philosophy of Computer Science, plus some Grady Booch On Architecture listening and finally Pat Kua We do “TDD.” Oh really?, got me to a point where I consider not doing TDD not only a fail in follow best practices of software development but also not developing software at all only random (brownian motion) execution on a computer.

Let’s think about unit tests. Unity tests not only guide the real implementation but also specifies inputs and outputs of methods in a class, the whole set of tests of a class specifies the class itself. If we take a unit with a little more rigor, meaning that complex business rules are splited in its small steps and clear collaboration, can the tests be clear enough to look like a very detailed specification?

Taking this idea further, using unit tests with this specification meaning, what we think as implementation now becomes too low level. Our tests are defining, behavior, dependencies (mocked or stubbed), data structures of input and output, how far are these from the “real” implementation? Is now the real implementation something that could be auto-generated? If so, not using tests to guide your software is equivalent of writing bytecode directly?

Actually, as for now, if such compiler is created, turning our unit tests into implementation we would be back where we started on the mechanics of software development, although one level higher on abstraction. So, my feeling is that we should keep these two, implementation and its tests on the same level and not use one automated solution. It might be the case in the future this happens, still the mechanics will be conserved, having code, a specification with strict rules and grammar, turned into executable.

The end of the cycle maybe will be the time where no more software development would be necessary, where all pieces are coded and software will adapt itself over business requirements. It might be created as physical chips with preloaded software that can be assembled and only very high level description would be necessary to make it work, in example: “10% discount on products if it’s the client birthday.” Can’t think about this with the feeling of again being back to the same point.

When I read Pat’s post and recall the phrase “We only test the happy path.” I think, “What about the rest?” How the rest of the implementation is there anyway if not specified? In absence of tests we might think that the implementation not tested is free to do anything. Maybe a division by zero actually increments a variable instead of raising an error, who knows? That’s how it sounds to me, like any other path than the called “happy” will be a guess. It gets more worrying, any refactoring or modification of the code that doesn’t change the ins and outs of the happy path is a mutation on the “by chance” path, and actually turning the whole thing into a big pile subject to natural selection as single nucleotide mutations are for DNA.

Unit test coverage, could be interpreted as “by chance” metric. Coverage of 30% means, 30% implemented and 70% is by chance. As if you ran a compiler and it only compiled 30% of your instructions right, the other 70% is shuffled and inserted randomly. You get a 30% certainty and 70% bag fun of surprises.

One might argue that all code was written by the developers so, even if not tested, it has to maintain some logic reasoning and flow. Well, where this can be true for some cases in other cases I saw developers actually randomly guessing code. Writing and changing it until the point that gives some expected result, I saw code programmed by chance more than I would like.

I feel more and more that not doing TDD can only be explained by a developer thinking that he knows so well the domain and so well the language that he can write down a solution without any flaw. Action that is doomed to fail, as humans make lots reasoning errors and are subject to cognitive biases. History shows that even the mathematician Euler made a mistake. So if a technique that can help you avoid mistakes and better, can alert you if mistakes were made by others, is at your reach and you just ignore it justifying that is not needed cause you can write without mistakes, you should be better than Euler. And stakeholders pay for software with 30% of coverage are likely to buy 70% of problems.

null ⊨ null (null’s what they mean to you?)

The title is a play with semantic consequence and goes a on little incidental complexities of code. Given the definition of semantic consequence we are asserting that a null is a semantic consequence of a null if no interpretation of null turns null to be false. Confusing? Let me explain, here’s simple example:


public Type method(OtherType arg) throws Exception;

What this method does? Possible guesses are:

  • Given a OtherType argument the method can return Type.
  • Given a some scenario instead of returning the method throws Exception.

Since we are talking about nulls, we should consider other scenarios:

  • Given a null argument the method can return null
  • Given a OtherType argument the method can return null

Now a method could behave in four different ways. I don’t know a developer who likes to handle nulls, the reason is that adding an unrelated if on the code is unpleasant. But most fail in correcting the behavior ASAP. Here’s an example:

public Type method(OtherType arg) throws Exception {

if(arg == null) return null;

//... awesome things happen if you provide a non null argument.
}

Not only this code has this unrelated if but it’s forwarding the same scenario up to the caller. Eventually some layer has to handle this and that’s when the problems start to get worse. Check this code:


public Type method(OtherType arg) throws Exception {
  DependencyKiller dk = new DependencyKiller();
  ResultingType result = dk.notSureHowWasImplemented(arg)

  if(result != null) {
    return somethingInteresting(result);
  }
  return null;
}

This reflects common situations on big code bases where nulls exists freely. This method took a decision based on the fact that it could get a null, but what this means? (OBS: I’m using not meaningful names on purpose) We can guess that something interesting it will be done only if not sure returned a result that is not null, multiply these assumptions by a factor of ten and the feeling of not understanding what we are talking about is predominant.

Going back to our semantic consequence, the meaning of a null will hold true if and only if all interpretations of its meaning don’t turn our consequence into false. More clearly, all usages of null have to have the same meaning to the developers in order to this code make sense. Is this possible? Unlikely.

Because each handling/forwarding of the null will change its meaning, on the code above returning null means that something interesting did not happen, add one more layer and the meaning could change again. This will lead, most of times, to a situation where the developer find himself/herself with a unexpected NPE (NullPointerException) and nulls are not allowed anymore, the handling now means an Exception or returning an empty object.

Nulls are part of the language, what the options do we have? Actually the last developer, who handled the null and stopped the chain, did the right thing. One that expects a List could get an empty List, that would be harmless for most cases. There’s also the Null Object Pattern.

In the end, what matters is avoiding use a wildcard inside your code, such things are dangerous and often result in a more complex, hard to maintain and problematic code. The borders of your application (DB or other external entry) should handle the null soon, turn it into a type, maybe an UnkownType without behavior, but a type anyway, after all they are a Special Case.