There has long been a grip on digital technology, so tight that it has choked much of it. It is the grip of the tinkering geek. Slowly though, this grip is being loosened and the tinkering geek is becoming less and less relevant to technology and to society. And I say good riddance.
The tinkering geek, by definition loves to tinker. They want to be able to open something up, hack it together, use it for something for which it wasn't originally intended. The tinkering geek wants to run Linux on a toaster or use their iPhone as a remote for everything in their house. The tinkering geek is also who designs and makes a lot of digital products.
Now you may think that these people are the sort of people you want working on designing and building this stuff. They know the subject, they have interesting ideas, they know what they want. The reality is these are the worst people to design anything. For all that they do know, they don't know the most important thing: what does a regular person want?
We are brainwashed from childhood that open is good, choice is good, freedom is good. And yes, to a degree all of those are good. But too much openness leads to unhappiness, too much choice leads to confusion and too much freedom leads to anarchy. There's a reason I don't have the freedom to walk down the street killing everyone I see.
Closed isn't inherently bad. Design by committee is open, design by a single person is closed. I can guarantee that the design by committee will produce a worse product. Open is good in some places and bad in others. Lets take software for example. Tell me a good piece of open source software that is a backend product eg server software, framework etc. There are 100s out there that are best in their class. Now tell me a good piece of open source software aimed at regular people. Not all that many.
Closed also leads to things that open can't. Apple's ecosystems are often considered closed. OS X only runs on Macs, iPhone OS only runs on iPhone, iPod touch and iPad. Compare this to Windows or Android which runs across 1000s of hardware configurations. Well, if we do compare then we'll see that Apple's ecosystems are generally more stable because they have more control.
One example of a closed ecosystem in our products is Code Collector Pro and codecollector.net. By controlling the whole stack we will be able to implement stuff faster than competitors and even add some things that others aren't able to do at all. If we chose to be completely open and let it work with everything, it is more work for us, more code (increasing the chance of bugs) and doesn't really do anything quite as well.
Now I'm not saying everything in the world should be completely closed. I believe that some things need to be open, but most of these are things for people creating products to take advantage of, not for users to care about. A user doesn't care if a file format is an open standard. What they do care about is "can I save this at work and open it at home" and "will I be able to open it in a few years time".
There was a great TED talk a few years ago on the "Paradox of choice" by a psychologist called Barry Schwartz. You should really watch the full video, but in a nutshell he points out that choice makes people unhappy and reduces your freedom. You don't want to spend choosing, you want to spend time doing. The best way to give users what they want is to have a few distinct choices rather than a large range of slightly different choices.
Apple is a prime example of this. Say I want a computer, here is the general thought process:
To the last question if you say power you get a 13" MBP, if you say price you get a MacBook and if you say portability you get a MacBook Air. Yes there is then the case of choosing which model, but again that comes down to a question of price vs power. The rest is just tweaking.
You want to take away the pressure of choice, you want to choose for them. 99 potential customers may want A and 1 may want B. Ignore the one that wants B. Don't even give users the choice between A and B. Sure you've made 1 person unhappy, but you've made 99 people happy.
The only time you should give the choice to your customers is if there is a really significant minority. Say it was 60 people wanted A and 40 wanted B. That is when you should consider whether adding the choice between A and B outweighs having 66% more people buy your product
The problem is that many people who make the decisions about whether to add a choice are tinkerers and often think "we'll I'd like to tinker around so others might". This leads to the technology we have today which does a hell of a lot of stuff, but which most people don't care about.
Bullshit. I hear this a lot and that is all it really is. Lets look at 2 quotes from a post by Cory Doctorow on BoingBoing.
The original Apple ][+ came with schematics for the circuit boards, and birthed a generation of hardware and software hackers who upended the world for the better. If you wanted your kid to grow up to be a confident, entrepreneurial, and firmly in the camp that believes that you should forever be rearranging the world to make it better, you bought her an Apple ][+.
The idea that having a product that you can tinker with is what allows you to be creative or confident is silly. Technology is a tool. Knowing what is in it and hacking around with it is something a small minority have any interest in or find useful. Far more people care about using tools than what makes them.
Sure, tinkering can be fun to many people, but making tinkering easier for a few could make it a worse tool for everyone else. Lets take the example of the iPad. It could be made easier to tinker with, if you added screws to it to take it apart. However, adding screws increases costs, reduces aesthetics and, if you are also going to lay things out best to those wanting to tinker, could increase the size of the product. How many people would want the ability to take something apart over a cheaper, smaller more aesthetically pleasing product? VERY few.
Buying an iPad for your kids isn't a means of jump-starting the realization that the world is yours to take apart and reassemble; it's a way of telling your offspring that even changing the batteries is something you have to leave to the professionals.
This is just crazy talk. Sure, you could allow user replaceable batteries, but again like above it leads to a worse product. You have to add a mechanism for the battery to go in, to keep it in place and to encase the actual battery itself. This leads to more weight, more parts so more chance for failure and higher costs and also less space for the actual battery, so lower battery life. Now how many people would choose an easily (because you will be able to do it yourself if you really wanted to) user replaceable battery over a lighter, cheaper, more reliable product with greater battery life? Again, VERY few people.
Now let's think about something fundamental to economics: what are we buying? Contrary to popular belief, we are rarely buying a product. What we are buying is experience and knowledge. When I buy a mobile phone, I am paying for the experience and knowledge of the people that designed it and assembled it. I could, if I really wanted go and design and build my own. But my time is worth more to me than that.
An even better example is visiting a doctor. Why do I go and see a doctor rather than treat myself? Because they have done 5+ years of learning and experience. They know a hell of a lot more than I do. Sure I could go on the internet to find out why I'm ill, but is it really worth it if I'm wrong?
People are willing to pay for stuff that makes their life easier, that means they don't need the knowledge and experience themselves. This is why people pay a mechanic to fix their car or pay a chef in a restaurant to cook a greta meal or pay a company to replace a battery.
As much as some people like to try and convince you that tinkering is key to our freedom, our progress and our existence, they really mean "tinkering is key to my hobby". You don't need to tinker to learn something. Most of my learning was done through reading, watching and listening. Sure it is a way to learn, but it is far from the only way.
People who want to tinker will find a way to tinker, even if it is harder. I can still open an iPhone if I want to, I can still install different software. It just isn't easy and for that I am grateful, because it means that what came out of it was a product that I care less about how it works and more about what I can do with it. The sooner we get more products like this, the sooner we can have technology that is made for the majority, not the minority of tinkering geeks.
511 days. That is how long it has been between Code Collector Pro 1.3's release and the release of 1.4 (the geek inside of me now makes me wish I'd waited until tomorrow for a nice round 512 days). Yet despite this large amount of time, CCP 1.4 is admittedly lacking in new features. It has a lot of user interface re-design and bug fixes but in terms of new features, the most significant is probably being able to see the dates a snippet was added and last modified.
So why has it been so long between the two releases, and why has there seemingly been so little changed? This blog post is to answer those two questions.
Put simply, finishing my Computer Science degree got in the way. I release CCP 1.3 in November 2008. At this point my first dissertation deadline was approaching fast and so after I released 1.3 I had to focus on that (my dissertation contributing to over a third of the marks for my entire degree). My final deadline for my dissertation was late-April 2009 and from then until the end of May I had exams to revise for and take. Finally, come the 28th of May 2009, I was free and able to go full time with M Cubed.
But wait? That was 9 months ago, what have I been doing in the intervening time? Well first off I joined up with Fabio to start the design side of M Cubed which required management. And also I had to work on Minim 2.0 which was a complete re-write. Both of these required more time than I was expecting at first and so it was January before I could start work on CCP 1.4, which then took longer than I was expecting itself.
So why is there so little new feature wise in CCP 1.4? Well, put bluntly the code in 1.3 sucked. I have talked about why in a previous post, but in a nutshell it had a lot of 10.4 era code and was designed by someone much less experienced in software than me: me circa 2 years ago.
After hardly touching the code for over a year, when I came back to it I found I needed to re-write lots of it. In fact about 60% of the code in CCP has either been re-written or moved around between 1.3.6 and 1.4. A lot of old code was deleted with more modern alternatives put in its place. Essentially this re-write will make it easier to add newer features in 1.5 and 2.0. So while it doesn't add much now, it will allow me to add better features in the future at a faster pace with hopefully fewer bugs.
So make sure you checkout Code Collector Pro 1.4. While there isn't much new, there is a lot of stuff that has been massively improved. There's also a screencast showing some features that have been around for quite a while, but many people don't seem to know about.
A while back I wrote a post on how I was pushing towards making my apps much more manageable, by separating my once monolithic app delegates and nibs into various view and window controllers. Yesterday Justin Williams wrote a post on his blog about Getting Started with Core Data, Bindings and NSViewController.
Cocoa has changed a lot over the years. I started programming on 10.3, when Xcode was a version 1.0 and Bindings, KVO and KVC were the new hotness. Over subsequent releases we gained Core Data, Objective-C 2.0, NSViewController, Garbage Collection and much more. I strongly believe that any modern Cocoa app should be using Core Data, Objective-C 2.0, Garbage Collection and NSViewController. Bindings should also be used where appropriate (I'll define where I think this is later).
Justin's post included a project he'd worked on, implementing core data tutorial application from CocoaDevCentral using several window and view controllers rather than one monolithic class and nib. The way he built his version was quite interesting, as it was differently to how I would have approached the task. As it was a relatively simple project, I thought it would be of benefit to some to provide an alternate way of building the same app. I don't think there has been two Cocoa developers giving two different ways of implementing an entire app before.
You can download the source for my version here. I also recommend downloading Justin's version. I'll first outline how Justin's implementation works and then go into how my implementation works and how it differs from Justin's.
But first it would make sense to outline the application. It is a simple blogging app. It consists of a main window containing a splitview. On the left is a list of posts, with an add button below. On the right are the details of the current post: the title, author, category and body. The author and category are chosen from a list which can be edited by clicking the edit button next to the field. This brings up a panel allowing editing of the author and category lists.
The data model is as shown below:

Justin has structured the application as 3 window controllers, 2 view controllers and the app delegate:
And that is all there is to Justin's implementation. It is very simple and most of the processing is pushed off to Core Data and NSArrayController.
I built my implementation with the same structure as my 3 existing apps. Rather than relying on core data and bindings completely, I use KVO manually and have a model controller that wraps around core data. I have a similar set up in terms of controllers: 3 window controllers, 2 view controllers and the app delegate. But I also have 9 extra classes, my model controller, 2 classes to simplify core data and 6 model classes generated by MOGenerator.
The following two classes I group together as M3CoreData. They are classes I've built that make CoreData cleaner and simpler to access.
And finally there are the 6 classes generated by MOGenerator. I've learned to swear by MOGenerator for my core data applications, it is removes all the hassle that you would otherwise have if you used Xcode's built in tool for generating model classes for core data entities. The only change from the generated code is an awakeFromInsert method in M3Post that sets the creation date.
One thing I like to do is abuse the responder chain (please don't call the police!). In larger applications I make sure every view and window controller on screen is in the responder chain. This has the advantage of being able to put methods where they belong, rather than where you can access them. For example, the newPost: method is in the window controller. In some of my apps I have it in the side bar controller, because that is all that cares about adding a post.
You can then connect you actions to the first responder proxy in the NIB. It will traverse the responder chain and find the appropriate class and then invoke the method. You can then control whether the method can be invoked by overriding respondsToSelector, which will give you menu validation control.
This is how the editAuthors: and editCategories: methods in the app delegate are called. The buttons in the details view are connected to these methods via the first responder proxy. As the app delegate is in the responder chain it will be the one receiving the methods (as nothing else futher up the chain implements them).
Bindings are a contentious issue. Some people love them, some people hate them. The fact is that they are incredibly useful and can save a LOT of code. To give one example, the new inline inspector in CCP 1.4 was initially all handled in code. Unfortunately this required a lot of logic for handling no selection, multiple selections etc. In the end I just replaced the code with bindings to an NSArrayController and managed to delete around 100-150 lines of code.
But bindings aren't useful in all cases. Over the years I've kept changing how I use bindings. I used to use them everywhere, then went through a phase where I didn't use them at all, but have now settled on a good middle ground, where I use them where they work best. So where is that?
There are a lot of people who avoid some of the new technology in Cocoa. Some don't like Core Data because it seems like voodoo (if you learn a little bit more you'll actually find that it is quite simple, yet incredibly powerful) and some dislike Garbage Collection because of experiences with other garbage collectors (in reality the GC in Obj-C not only saves you the pain of memory management but also of threading, while also potentially being faster than a retain/release system).
You should always be looking at the new technology that comes in each release of Cocoa, most of it can save you 100s, if not 1000s of lines of code if you can adopt it. It can also make the code you do have much easier to manage. It seems odd that most people would agree it is insane to write and use an alternative to something like NSTextView, yet will write and use an alternative to some more modern technology in Cocoa.
As with many of my blog posts, it is often a tweet or another blog post that made me want to write my thoughts. In this case it is both:
Just accidentally blew away 16 files' & days' worth of work with hg. Looked up, TIme Machine had just finished. Lost < 1 min. of work.
That tweet prompted Wolf Rentzsch to write this post about how Time Machine is your version control "safety net". To me both of these are shocking. It seems that the tweeted mishap may have been user error, but it made me look into how the various user interfaces help protect the user.
For a long while I was opposed to VCSs, mostly due to faffing around with subversion and getting nowhere. With DVCSs I've become an addict. The issue is that DVCSs also try to be clever. Their primary goal is to protect you from yourself, to make sure your code and its history are safe. Essentially your commit history should be like a stack. 99% of the time you push onto the stack, rarely you need to pop off a stack. You can read the contents of the stack as you want. But you shouldn't be able to modify the internals of the stack.
This is why I consider the many rebase plugins/commands in DVCSs to be harmful. I feel that rebase should be viewed as a mixture of goto, premature optimisation and Jeremy Kyle all rolled into one ie don't touch it unless you know what you're doing and are wearing many layers of protection, and even then it probably isn't such a good idea. Some people swear by rebase, but I feel that you shouldn't be messing with what should be treated as sacred.
This is where we get onto UI. I've never really given much thought to command line UIs, but comparing git, Mercurial and Bazaar I've found subtle differences in the UI that make it harder or easier for a user to perform a destructive action. These really fall into 3 categories: confirmations, making it hard to destroy and separating destructive actions.
In the case of the tweet at the start, I looked into the command that was performed: hg update -C . It offers no confirmation dialogue, it just cleans out the items that have changed. It doesn't make it hard to destroy changes and it is a one character option which means it is easy to do. I'm not sure about git but the equivalent in Bazaar would be bzr revert --no-backup. Of course there's no real reason to run --no-backup, it helps save your arse just in case and cleaning it up is just a case of bzr clean-tree --detritus (which lists the files to be deleted and asks for a confirmation).
One of the other examples is from the blog post. git branch -d abranch will delete the branch called abranch. Now to me this seems incredibly dangerous as there isn't any confirmation given. Occasionally I've seen warnings to use the uppercase -D option if changes aren't merged into the parent, but sometimes even those may not appear. If you're doing something like deleting a branch then it should be made harder to do. Really it should be git branch --delete-branch abranch and then ask you to confirm the delete.
Destructive actions should really be moved out into other commands if possible. bzr has 2 such commands: uncommit and clean-tree. Uncommit and clean-tree both list the items that will be removed and ask you to confirm. This makes the user double check what they're doing to confirm what they are doing. Now these commands could be moved into other commands. Uncommit could be made into bzr commit -d, but by separating them out you are making the user think that this is a different thing and making it harder for them.
It does seem very hypocritical, when most of UI design is a push to make life easier for a user, to advocate making it harder. But as odd as it may seem, making something harder may make it more usable. Now by harder I don't mean make a series of convoluted steps that require an animal sacrifice. I mean add an extra step to any potentially dangerous action. Tell the user exactly what the result of the action will be and ask them to confirm it.
Obviously you should provide undo when possible, but sometimes it isn't. Think about where in your UI you place these actions and consider whether you need them there at all. Don't put a 'wipe library' button right next to one of the most commonly used buttons in your UI, and no matter where you put it, if you can't offer an undo then tell the user exactly what you will do and make them confirm. Force them to pay attention to what they are doing. They'll thank you for it, even if it is just by not complaining to you (or worse to the internet) about how your software lost their data without warning.