Tuesday, December 18, 2007
(Aha!) Part of the reason why great hackers are 10 times as productive
So when I read Paul Graham (and Joel's) claim that great hackers are at least ten times as productive as average programmers (too lazy to cite right now), I was kinda shocked. Surely, ten times is an order of magnitude! Something that takes an average programmer a 40 hour week to do the great hacker can do in a 4 hour afternoon?
I wondered about that, since there are times when I get stuck on something, then I just start stabbing around randomly out of frustration. I had assumed that great hackers were faster only because they had either the experience or insight to side-step whatever I was doing wrong.
But lately, I've been re-reading everyone's essays that write about programming productivity. And one thing that caught my eye the second time around was when Paul Graham was talking about bottom up programming and how he didn't really believe in objects, but rather, he bent the language to his will. He was building new blocks for himself so he could think about the problem at a higher level of abstraction.
This is basic stuff! I mean, that's the whole point of higher-level programming. When you refactor methods out, you're creating a vernacular so that you can express the problem in terms of the problem domain, not in terms of general computing. This is much like if you want to drive a car, you'd want to be able to step on the gas, rather than time the firings of the pistons. And if you want to control traffic in a city, you'd rather tell all cars to go to a destination, rather than stepping on the gas and turning the steering wheel for each one.
But taken into the light of bending a language to your will, it makes it more clear for me as to how great hackers are ten times as productive. Great hackers are productive not only because they know what problems to sidestep and can problem solve systematically and quickly, but they also build a set of tools for the problem domain as they go along. They are very good pattern recognizers and will be able to generalize a particular pattern of code, so that they can use it again. But not only that, great hackers will create an implicit understanding attached to the abstraction, ie. what we might call common sense.
A case in point. Before Ruby, I'd used for loops over and over again, never really thinking that I could abstract a for loop. It wasn't until they were taken away in Ruby did I realize that map, inject, and their cousins are all abstractions of the for loop. When I see "map" I know that it performs a transformation on every element. But I also know that the array I get back will be the same size, that each element operation doesn't affect other elements, among other things. These are implicitly stated, and they allow for shorter code.
When that happens, you can simply read "map", and get all the connotations it comes with, and hence it comes with meaning. It also becomes easier to remember, since it's a generalized concept that you can apply in different places in the code. The more times you use it, the easier it is to remember, instead of having specialized cases of the same kind of code where the behavior is different in different parts of the code.
A great hacker will take the initial time upfront to create this generalized code, and will save in the long run being able to use it. Done over and over again, it all adds up. So it's not that for any given problem, a great hacker will be done in 4 hours what it takes an average programmer 40 hours, but that over time, a great hacker will invest the time to create a tools and vocabulary that lets him express things easier. That leads to substantial savings in time over the long haul.
I hesitated writing about it, as it's nothing I (nor you) haven't heard before. But I noticed that until recently, I almost never lifted my level abstraction beyond what the library gave me. I would always be programming at the level of the framework, not at the level of the domain. It wasn't until I started writing plugins for rails extracted from my own work and reading the Paul Graham article that a light went off for me. It was easier to plug things like act_as_votable together, rather than to still mess around with associations (at the level of the framework). I still believe you should know how things work underneath the hood, but afterwards, but all means, go up to the level of abstraction appropriate for the problem domain.
DSLs (Domain specific languages) are really just tool-making and vernacular creation taken to the level of bending the language itself. It's especially powerful if you can add implicit meaning to the vernacular in your DSL. It's not only a way of giving your client power in their expression, but it's also a refactoring tool so that you can better express your problem in the language of the problem domain. Instead of only adding methods to your vernacular, you can change how the language works. It was with this in mind that I did a talk on DSLs this past weekend at the local Ruby meetup. First part is on Dwemthy's Array, and the second is using pattern matching to parse logo. Both seemed pretty neat when I first read about it. Enjoy!
DSL in Ruby through metaprogramming and pattern matching
Thursday, December 06, 2007
Communicating your intent in Ruby
To start, programming is recognized rightfully as a means to build something from pure thought. But it's also a form of communication, to other programmers that will touch your code later, and to yourself when you look at it months from now. We're at a point that other than embedded and spacecraft programming, we have the luxury of using programming languages that focus ease for the programmer, rather than for the ease of the machine. Fundamentally, that's the philosophy that Ruby takes.
And while Ruby's nice in a lot of ways, I'm not sure about how it communicates an object's interface. When you're allowed to modify objects and classes on the fly, how do you communicate interfaces between modules you mixin and methods/modules you add? By interface, I mean, how do you use this class so that it does what it's suppose to? Normally, it's pretty obvious--you look at the names of the methods declared in the code. A well-written class has public methods exposed, or you look at its ancestor's public methods. You might need some documentation to figure out how to call them in the right order, but generally, you have some idea just by looking at the method signatures.
However, when you throw mixins and metaprogramming in the mix, it becomes less easy to tell just from looking at the method signatures in the code--the structure of the code. You have to specifically read the code, or you have to rely on someone who knew intent to document it in detail.
An example communicating interfaces for mixins: the module Enumerable contains a lot of the Collections related methods. The cool thing is that if you wanted these functions in your own class, all you have to do is define each() in your class, mixin the Enumerable module, and you get all of these "for free". However, outside of documentation explicitly stating it, it's not as immediately obvious in method signatures that this is what you have to do in order to use it. It's only after scanning through the entire code that you notice each() being used for all the methods.
Of course, Ruby contains enough metaprogramming power to protect yourself against this. one can do something like this:
class MethodNeededError < RuntimeError
def initialize(method_symbol, klass)
super "Method #{method_symbol.to_s} needs to be in client class #{klass.inspect}"
end
end
module Enumerable
def self.included(mod)
raise MethodNeededError.new(:each, mod) unless mod.method_defined?(:each)
end
end
This only works if you put the include after you define each(). That's just asking for trouble when the order of your definitions in your class matter.
A fair number of people are writing mini-DSLs in ruby using metaprogramming tricks. One of the common ones is the use method_missing to define or execute methods on the fly. ActiveRecord's dynamic finds are implemented this way. The advantage of communication of interface here in the structure of the code is obvious. Unless it was documented well, you can't tell just by looking at the method signatures.
Why do I harp on interface signatures? I mean, in the instance of requiring each(), it works by just letting it fail in the enumerated methods, since it'll complain about each itself. In the instance of method_missing, just read the regex in the body. While these are true, none of these allow for rdoc to generate proper documentation. The whole point of documentation is to show you the interface--how to use that piece of code. I'm just afraid that given Ruby's philosophy of being able to write clear, powerful, and succinct code, it might fall short when people start using these metaprogramming tricks like alias_method_chain and method_missing more and more. Maybe rdoc needs to be more powerful and read code bodies for regex in method_missing?. It already documents yields in code bodies, but that seems awfully specific.
I'm not a exactly a fan of dictating interfaces like in Java. When you're first coding something up, you're sketching, so things are bound to change. Having plumbing like interface declaration gets in the way, imo. However, when something's a bit more nailed down, it'd be nice to be able to communicate to other programmers your intent without them having to read code bodies all the time.
In the end, I side on flexibility. However, I kinda wish Ruby had some type of pattern matching for methods so I didn't have to read method_missing all the time. But then again, that would be messy in all but the simplest schemes. Can you imagine a class that responded to email addresses as method calls? I guess I'd have to file this one under "bad ideas"
Saturday, September 01, 2007
Ajax.Ajax.PeriodicalUpdater has a decay option
There's plenty of treasure in API docs, I've usually found--like when you need two submit buttons for an AJAX form. While tutorials are helpful for just getting started, I'm a firm believer in just browsing through API docs and references once in a while, like a lazy grounds keeper checking for garden gnomes. I also like reading dictionaries. I don't do that too often, just when I'm looking up words. I never got any papers done until internet dictionaries came around.
The past two days, I've been playing more with Javascript, and that involved looking more closely at the Prototype library that comes with Rails. So far, my experience with prototype has been pretty good. It's less high level than, say mookit, but I think it was meant to fill holes in the current javascript language. Even little things like Try.these() are nice, due to javascript discrepancies between browsers.
As a result of browsing through the Prototype API, I found that the adaptive polling I had talked about before was actually already in the Prototype library. It was just never mentioned in any of the Rails docs or tutorials about periodically_call_remote().
Though I don't know if it was around when I blogged it last December, that should be lesson to me to stop talking, and just try writing a patch, as Prototype is open source. I probably would have learned a lot.
Thursday, August 16, 2007
The new YC.news
This ended up to be a long comment on YC.news, now turned Hacker news. I figured it was worth reposting here on my blog:
When I was working at an engineering job at a research lab, I was told what had to be accomplished. Of course, the degree of freedom, amount of creativity, and problem solving you can do varies from project to project, but in the end, I went to bed happy knowing in the back of my mind that someone, somewhere asked for whatever you're working on--that's why you're getting paid. When you're a startup founder, however, you aren't even sure of that, mostly because of the nature of startups and the markets they decide to persue.
A startup can be successful in an already crowded and proven market--especially if the market sucks (online dating comes to mind). But often times, where startups shine is where others fear to tread, and that's in potential markets, unproven markets, and useless markets (until you prove that it isn't).
But how do you figure that out? And given that you see a potential, how do you find a creative solution to build a business from it?
I don't think anyone can tell the future when it comes to these things. But you can certainly learn to get a good intuition for it. One of the ways to do that is to constantly read broadly about interesting things that are going on in the fringes of any number of industries. By interesting, I mean, things that you didn't know that stretchs your understanding of the world and perhaps your imagination a little bit more. When you start to get your finger on the pulse of possibility, you're able to see blooming solutions where others only see wilting dead-ends.
In addition, when you dig deep enough into any topic, it gets quite interesting. You'll start to find that all subjects are intertwined in one way or another. The way all subjects are compartmentalized in school is just so students don't get confused. But really, all subjects are inter-related. Sociology's studies on coordination and biology's study on social insects actually relates to optimization. Weather phenomenon actually relates to crytography. This inter-relatedness works to your advantage in finding creative solutions to make a business out of your new market, because creative things are usually a combination of old things put together in new ways.
Contrary to popular belief, creativity isn't often completely out of nowhere, just as masterpieces don't just materialize in front of masters. For every masterpiece you see hanging in the galleries, there are hundreds of sketches and throwaway paintings that you don't see the master artist practicing on. By the same token, a creative solution for a startup isn't just a stroke of inspiration from nowhere. It's a culmination of a slow absorbing of interesting tidbits that you've gathered and processed in the back of your mind until you've put the relevant pieces together.
So as far as I can tell, Paul Graham views hackers that are startup founders not as just really really good programmers. He believes what makes these people good startup founders is their innate curiosity in the world around them, and the willingness and drive to keep on learning about it to produce and create solutions--which lead to profit if attacked in a business way. That not only drives their strengths as programmers, but as thinkers and builders that change the world and will make money doing so. Not trying to put words in his mouth, but that's my best summary thus far.
Therefore, if you buy into that, then I think the direction into the new YC news as Hacker news is a good change. It will allow people to keep seeing and learning interesting things so they have a better gut for potential and emerging markets, as well as helping them along in their creativity for novel solutions. That is, at least my take on it.
Of course, we'll see how it actually all plays out, but I for one, am looking forward to the change.
Monday, May 14, 2007
Collateral damage caused by incidental limitations
"Python truly sold me on the benefits of dynamically-typed languages and rapid prototyping. I began to see that many of the sacred GoF design patterns were not, in actuality, grand universal truths of software engineering, but simply collateral damage caused by incidental limitations in the abstractive power and object model of certain manifestly-typed programming languages."This is pretty much the way I feel about it too. I had spent a good year of someone else's money learning UML and design patterns, and it ends up that the only pattern that is remotely useful with dynamic languages is the observer pattern. All others have fallen away because the problem they solved were no longer problems in dynamically typed languages.
That said, I think that the majority of us come from imperative backgrounds of C++ and Java, and it's probably no way to judge static-typeness. Modern static-typed languages such as Haskell and OCaml probably has more tricks up their sleeves.
Thursday, May 03, 2007
Innovation is force fed; someone get the lube!
When you're building a product you're essentially forcing your world view onto others. You're basically saying, "I find this to be a pain. And this is not the world as it should be. As a builder, I can correct it after mouthing off for a while." And this is usually why people don't warm up to innovative ideas readily--someone is shoving their world view in your face. And unless you're someone that has been looking for a solution to the same problem when it's introduced to you, you won't be receptive to it. Even innovative people suffer from this affliction of shortsightedness.
“Don’t worry about people stealing an idea. If it’s original, you will have to ram it down their throats.” – Howard Aiken
Because innovative products can be so jarring, they should soften the blow a bit--or as others like to call it lowering the barriers. This is where influences from design, gaming, and etiquette can help.
Beyond the current trend of sleek lines, horn-rimmed glasses and black turtle necks of designers, design isn't just about putting a gradient background on your web app, or painting things in pastel colors. Hackers making a product should understand that design is the study of how to best solve communication and usability problems with limiting constraints. What information would the user need to know right this second, and how should you convey it to make it as easy to understand as possible? And from the answers to those questions will emerge a form that is also pleasing to the eye.
Gaming is an avenue more familiar to hackers than design is. However, games are often seen as mere trifles of play reserved for kids--though this is changing. If you've played enough video games and thought about WHY they're fun, will help also, because to bring out the essence of fun in what's normally perceived as tedium will give your product an edge. In the lecture about the ESP game by Luis von Ahn, he laments the fact that there's millions of cycles of human computation wasted. There was 9 billion hours played of solitaire last year (est.). Considering that the Empire State Building took 7 million hours and Panama Canal took 10 million hours, that's a lot of wasted hours. We should be able to put those cycles to good use by making people play games to solve problems that computers can't yet solve. So a symbiosis of humans and computers can be considered a large distributed computer to solve hard problems, such as object recognition in images. You might have played it.
In other web apps, the idea of a collection is a powerful mechanism of play. Social networking sites play on the idea of collecting friends, much in the same way that in Pokemon, you "gotta catch them all!". In others, the idea of a scoreboard is a powerful motivator, as seen on Digg and Reddit.
And last of all, the idea of etiquette seems far removed from being applicable to innovative products. However, no matter how much technology people surround themselves with, we are still social beings and will have social tendencies. Because of that, we expect certain behaviors and interactions between ourselves and our machines. We get mad and frustrated at computers and devices because they're usually not very polite. They stop responding when they're busy doing something, but don't tell you what they're doing. They don't remember what you told them last time and asks us over and over again. And when they don't know how to ask for help when something goes wrong, since the error messages are unintelligible to most users. These are all hallmarks of an annoying person, and were it a real person, I'd have kick them to the curb.
The iPod, and in general, Apple products, are known for their politeness. When I first got an iPod, it was the 5th generation. I was surprised that it stopped the music, if the ear buds got unplugged, and that it turned itself off, after it's been paused for a while. Basically, it knew what was going on, and reacted to it in a fashion that makes sense to its owner. That sounds like the promise of Agent based software hyped so long ago. Maybe it should make a slow come-back.
The sad thing is, computer apps and devices have been annoying us for so long, that we have kinda gotten use to it. I think as research on classifiers become more readily available to programmers as being embedded in the language, and the rising influence of designers in applications, we should see a trend towards more polite products. If you can make a product that is polite, it'll go a long way in gathering fans.
In the end, you want people to use what you build if it has value. And users want to GET THINGS DONE, so they can move on with their lives. All products should solve problems, there's no doubt that it's essential. All other points are moot if your product is useless. But given that it does solve a problem, if it is also beautiful, fun, and polite, it will go a long way in lowering barriers so that we can all have pearls Before Breakfast.
Monday, April 30, 2007
Comments on the death of computing
There was excitement at making the computer do anything at all. Manipulating the code of information technology was the realm of experts: the complexities of hardware, the construction of compliers and the logic of programming were the basis of university degrees.Well, part of it is probably a lament by the author--presumably a scholar--on the loss of status and the general dilution in the quality of people in the field. And the other part is about how there's nowhere interesting left to explore in the field.
...
However, the basics of programming have not changed. The elements of computing are the same as fifty years ago, however we dress then up as object-oriented computing or service-oriented architecture. What has changed is the need to know low-level programming or any programming at all. Who needs C when there's Ruby on Rails?
To address the first part, it's well known that engineers, programmers (or any other profession) likes to work with great and smart people. Usually, when a leading field explodes you're going to attract these great and smart people to the field. However, the nature of the field of technology is to make doing something cheaper, faster, or easier. And as technology matures, the more the barriers to entry in the field lowers. And as a result, you'll get more people that couldn't make it before in the field and the average quality of people dilutes. People use to do all sorts of research on file access. But now, any joe programmer doesn't think about any of that and just uses the 'open' method to access files on disk. But that's the nature of technology, and it's as it should be.
The environment within which computing operates in the 21 century is dramatically different to that of the 60s, 70s, 80s and even early 90s. Computers are an accepted part of the furniture of life, ubiquitous and commoditised.And again, this is the expected effect of technology. Unlike other professions, in engineering one is able to make technology which gives people leverage over those that don't use it. This gives the advantage of acceleration and productivity that's scalable that you won't find in other professions. If you're a dentist, there is an upper limit to the number of patients you can see. In order to be even more productive, you'll need to create a clinic--a dentist farm--to parallelize patient treating and you need other dentists to do that. If you're an engineer, the technology that you build is a multiplier, and you don't even need other people to use the multiplier.
But at a certain point, the mass adoption of a technology makes it cheaper, and hence, your leverage over other people isn't that great, and you begin to look for other technologies to make your life easier or give you an edge over your competition. But these are all applications arguments to CS; while important in attracting new talent, it doesn't address where the field has yet left to go on the edge.
As for whether CS is really dead or not, I think there's still quite a bit of work to be done at the edges. Physics in the late 1800's claimed that there wasn't much interesting going on there until General Relativity blew up in their face. Biology has had its big paradigm shift with Darwin, but there's still a host of interesting unknown animals being discovered (like the giant squid) and I'm sure alien biology or revival of Darwin's sexual selection would help open up another shift. Engineering suffered the same thing in the early 1900's, when people with only a background in electromechanical and steam powered devices thought there wasn't much left to invent or explore, until the advent of computing spurred on by the Second World War.
In terms of near-term computing problems, there's still a lot of work to be done in AI, and all its offshoot children, such as data mining, information retrieval, and information extraction. We still can't build software systems reliably, so better programming constructs are being ever-explored. Also, since multi-core processors are starting to emerge, so better concurrent programming constructs are being developed (or rather, taken up again...Seymour Cray was doing vector processors a long while back)
But I'm guessing the author of the article is looking for something like a paradigm shift, something so grand that it'll be prestigious again, and attract some bright minds again.
In the end, he is somewhat hopeful:
The new computing discipline will really be an inter-discipline, connecting with other spheres, working with diverse scientific and artistic departments to create new ideas. Its strength and value will be in its relationships.This, I don't disagree with. I think far-term computing can draw from other disciplines as well as being applied to others. With physics, there's currently work on quantum computers. In biology, there's contribution to biology from bioinformatics and the sequencing of genes, as well as drawing from it like ant optimization algorithms and DNA computers. In social sciences, there's contribution to it using concurrent and decentralized simulation of social phenomenon, as well as drawing from it like particle swarm optimization.
There is a need for innovation, for creativity, for divergent thinking which pulls in ideas from many sources and connects them in different ways.
One day, maybe it will be feasible to hack your own bacteria, and program them just as you would a computer. And then, a professor might lament that any 14 year old kid can hack his own lifeform when it use to be in the realm of professors. But rest assured, there will always be other horizons in the field to pursue.
Saturday, March 31, 2007
Crazy small nuances
For example, there's a difference between system and exec. I wouldn't have known, as I was skimming the docs for something I needed. Were it not for this post by jayfields, I would have had no idea.
And there's something in Ruby 1.9 called "funcall", in which it's definitely not at all intuitive how that's different from "send". I hope these are just growing pains, because while Ruby is nice when you're taking it out for dinner on the first couple of dates, I hope it doesn't get abusive the more time that you spend with it.