Small Projects
March 31, 2008 at 06:19 PM
Tiny projects keep it new, for sure. It seems to tie in a little bit with proof-driven development and personal projects - in each case, you're escaping the mental cage of a monolithic, mature product to start something new. (Even if the "something new" is a component that's going to plug in to said mature product.)
Recently I've been dividing up the the Heroku architecture more finely. We've gone from about three repositories to over a dozen. Each time we carve off a new piece, it's a chance to freshen things up. A new revision control system, a new framework, or even just a new class hierarchy. Breaking free of the past is liberating.
Admin Debris
March 28, 2008 at 09:31 PM
Ryan Tomayko gives us all a good spanking on the subject of admin debris in your interface. He especially scorns the /admin style of management interfaces, in favor of edit functions sprinkled in with the standard app content. I like the usability of this approach, though the downside is views that are littered with <% if @user.admin? %> ... <% end %>.
rush 0.3
March 26, 2008 at 12:35 PM
You can read the full details, but here's a tantalizing sample:
box.bash 'mongrel_rails start', :user => 'www', :env => { :RAILS_ENV => 'production' } file.access = { :user_can => :read_and_write, :group_and_other_can => :read }
Backticks are just so 2007.
Y Combinator
March 26, 2008 at 01:09 AM
The winter 2008 session of Y Combinator is just about wrapped up. What a great experience. If you're thinking of applying to the upcoming session but aren't sure if it's worth it, let me assure you: it is.
I could gush for hours about what the experience was like, and what it means to continue to be a part of the YC network. But I'll let you read about that elsewhere.
Instead, I'll comment on something a little more subtle: the distinct culture which seems to be emerging from YC. I see this in the current session, but even more strongly in the network of YC alumni. The three month session itself is just the beginning - a boot camp to kick your ass into gear (and maybe weed out those that aren't cut out for the high-intensity life of a startup founder). As nearly as I can tell, the ties to fellow YCers only get stronger, and the YC culture more distinct, the further out from their initial session a given YCer is.
This got me thinking about the root of this culture, and in doing so, thinking about what Y Combinator is really about.
If you're a huge geek (and I certainly hope so), you recognize the little inside joke: the y combinator is a bit of lambda calculus, a function that recursively bootstraps other functions. At first, I thought: ok, so YC is a company that recursively bootstraps other companies. Ha ha. But after experiencing the session, I see another layer to this. Although YC itself is four people (three of whom I got to work with in the session, all of whom are very smart and talented), YC's heart is really Paul Graham. So YC may be a company that makes other companies, but culturally it Paul Graham, and what it does is recursively bootstrap other Paul Grahams.
The process is like this: PG writes essays that grab the attention of smart, technical, entrepreneurially-minded people. A subset of these people apply to YC. PG interviews them to select a further subset that have the most immediate potential. Then, YC puts them all through a three month bootcamp, at the end of which they pop out thinking, talking, and building companies in a way that is remarkably similar to the way that PG would.
If you think this sounds like a criticism, then you couldn't be more wrong. To my mind, the world could use a hundred more Paul Grahams, or a thousand. And as near as I can tell, we're well on our way.
I met some YCers from past sessions prior to attending the kickoff of my session. This gave me the chance to see the developed version of YC culture right from the get-go. I then got to watch as members of my session adapted and took on that culture for themselves. It's a culture seeded by PG, but it's also developing on its own, through the influence of the growing group of people coming into it.
What are the tenets of this culture? Entrepreneurial spirit, and a belief in one's own ability to change the world. Blunt honesty and healthy criticism, both in communication with others and in personal self-analysis. Its members have a deep and natural rapport with programming, math, critical thinking, economics, and community. Perhaps most of all, we have an uncompromising desire to passionately pursue the things we believe in, and in doing so, we hope to make the world a better place.
In short: these are hackers and self-made men. I've found my people.
Binge and Purge
March 23, 2008 at 02:01 PM
There's a cycle to building software. First, you furiously write a bunch of code to get something working. It's complicated, a bit messy, a bit unfocused - but you manage to get it to work, just barely, and then you can start using it. Being used by one or more real users (even if that's just you, or you and a few others in your workgroup) then provides focus as to which features and functions are the most central.
Now the second half of the cycle begins: you start to trim it down, simplifying the code and data, trying to get the same functionality for the users with less code, fewer modules, less data complexity. At the end of this you come to a Zen-like state with your code, a minimalistic approach where you can subtract no more. From here, you now have a solid base to go back into the first cycle again, and start growing out your feature set.
Watch any good open source project to see this binge-and-purge cycle in action. Rails experienced this furious expansion of features in its early days, culminating around 1.2. Rails 2 was all about trimming down - doing more with less, focusing on core features that provide the most bang for the buck, moving everything else into external add-ons. Another one: Mozilla. After the open sourcing of Netscape, the codebase became a chaotic mess of building sprawling infrastructure components (Gecko, XUL, SpiderMonkey...). Once these had been built out, Phoenix Firebird Firefox showed up to trim, trim, trim down to a feature set that represented the core of what people really wanted out of a browser.
There's an apparent paradox here. If you don't let yourself write bad, messy, overly complex code you'll never make anything really cool or revolutionary. But bad code is unmaintainable over the long term. So if you don't take the time to factor down your bad, messy, overly complex code you'll never have a solid base to build the next set of killer features upon.
Which stage is your project in right now? And if you're on a team, do all the team members agree which stage the project is in?
Speaking Gigs
March 21, 2008 at 01:54 PM
In descending order of size (and, coincidentally, reverse order of chronology):
- Railsconf 2008, at the end of May. My topic is "Custom Nginx Modules: Accelerate Rails, HTTP Tricks." Even if you're not specifically interested in Nginx modules, a lot of the talk will on my theory of how HTTP is the enabling protocol in the era of cloud computing. The significance of HTTP goes way beyond just serving web pages and web APIs.
- Silicon Valley Ruby Conference, on Friday, April 18th at 2:30pm. My topic here is "Cluster Management with rush, the Ruby Shell."
- Cloud Computing Demo Camp, on March 24 (next Tuesday). I'll be doing a quick Heroku demo and discussing a few implications of running on top of EC2, and how on-demand services in general are going to transform the landscape of IT infrastructure over the next few years.
Situated Software
March 20, 2008 at 12:29 PM
Custom software is often written in the moment and by someone close to the problem, and designed to serve the highly specialized need of a smallish group of people. Clay Shirky gives this a name: situated software.
I've seen situated software countless times in my career as a programmer. In a business - big or small - someone needs a quick app for tracking orders, or tasks, or trouble tickets. Or in personal life: someone wants to track attendees to their party, or their book collection, or their family's travel plans.
The problem with situated software is that software development is extremely expensive, and the value of a small piece of software to be used by a small number of people is nowhere near high enough to match its cost. That's why most software development tends to be focused on general-purpose apps that have a potential audience of millions.
But situated apps, in aggregate, probably have a much greater value than the aggregate of the general-purpose apps which software development focuses on today. This is the long tail of software, and it remains an almost entirely untapped market.
How do people get situated apps right now? If they are a business with a decent amount of cash to spare, they might hire a consultant. This probably works out badly more often than not. The cost of software is so high that the consultants are constantly being squeezed; the result of the squeeze is that quality is sacrificed, so the client may end up with a poor-quality product. The smaller the project, the worse this gets. I've rarely seen a small software consulting gig work out well for either side.
The other route is to reach for an end-user computing tool: Excel (or Google Spreadsheets), Filemaker Pro, Microsoft Access. These are better than nothing, but in the age of the web they are becoming increasingly irrelevant.
How can we unlock the massive potential of the long tail of situated software? The only path to this is to decrease the cost of software development substantially. This process is already underway, though it will probably be a while before true end-user computing bliss is upon us. Nevertheless, I'm excited to see what the next five to ten years will bring on this front.
A Taste of the Future
March 18, 2008 at 05:26 PM
Yesterday I had a chance to tinker around with a new project using Merb, DataMapper, RSpec, and Thin. Merb + Thin means your app serves up pages twice as fast, with half the memory. Merb + DataMapper means your app is threadsafe. RSpec + DataMapper means your tests are completely independent of the database - which means no db:test:prepare step, so the tests run lightning fast and without fragile database dependencies.
Above all, these components are all cleaner, smaller, and more specialized than their mainstream counterparts (Rails, ActiveRecord, Test::Unit, and Mongrel). It's too early for me to make any kind of real judgement about these tools (except for RSpec, which is very mature and entirely suitable for production use.) But using these four tools in a stack together leaves me with the gut sense that this is where the future lies.
to_xml
March 16, 2008 at 07:57 PM
When serving up an ActiveRecord as resource, you can use options like :only and :except to to_xml. But in most cases, you want the same fields served every time - on create, update, and get. So put the options into the class itself:
def to_xml(options={}) options[:only] ||= [ :name, :width, :height, :created_at ] super end
One Expectation Per Spec
March 15, 2008 at 02:17 PM
Jay Fields posts about one expectation per spec, something that I generally agree with but often find hard to practice. I typically find myself with one mock and one assert per test, such as this example from the rush specs:
it "transmits file_contents" do @con.should_receive(:transmit).with(:action => 'file_contents', :full_path => 'file').and_return('contents') @con.file_contents('file').should == 'contents' end
I want to test both the input and the output - that the file_contents method calls the right method with the right arguments, and that it returns the expected value. Breaking this into two specs would be:
it "transmits file_contents" do @con.should_receive(:transmit).with(:action => 'file_contents', :full_path => 'file') @con.file_contents('file') end it "gets the right return value from file_contents" do @con.stub!(:transmit).and_return('contents') @con.file_contents('').should == 'contents' end
This is a lot more verbose but I don't feel it adds a whole lot of clarity. Checking both the input and the output in one place seems reasonable to me. But I'll keep this in the back of my head and see how it influences my spec-writing.
Another item I spotted in Jay's example specs is stub_everything. I wasn't previously aware of this. (His examples use Mocha, but the RSpec mocks have the same exact method.) Like this:
class BankAccount def transfer(other_account, amount) balance -= amount other_account.balance += amount end end it "transfers money out of this account" @account.balance = 10 @account.transfer(stub_everything, 1) @account.balance.should == 9 end
stub_everything returns an object that responds to every possible method, but does nothing on the calls. This allows you to effectively ignore any operations on that object, rather than having to stub every call explcitly.
REST Enlightenment
March 14, 2008 at 11:37 PM
REST appealed to me right from the get-go. But it's taken me a surprisingly long time to wrap my head around all of its implications. Some of my recent projects - building the fully RESTful Heroku API, working with Mike Clark on the Nested Resources recipe for his upcoming book, and writing rest-client - have allowed me to finally get a handle on how all the pricinples of REST fit together into a unified whole.
If you're a longtime member of the Church of REST, what I'm posting here may seem obvious. But if you're like I was six months ago - that is, a little confused by how you could make a useful application with only four verbs - then read on.
Raw HTTP
REST is hard to get precisely because it is so simple. It just seems like there isn't much to it. But it turns out that there are some subtle implications hidden within its seemingly straightforward principles.
First, let's get the easy one out of the way. REST is about URLs and HTTP. This part makes sense to most people right away. Hitting a URL is something that can easily be done from almost any language or programming environment; it's extremely transparent (and thereby discoverable and easy to debug) due to the simple nature of URLs and the fact that you can use a web browser to do simple testing; and using HTTP as the transport gives benefits like virtual hosts, easy proxying, and doesn't require running a separate daemon besides your webserver. In short, REST is the web, and this makes it vastly easier to use than the various RPC protocols whose corpses now litter the highway of software history.
But don't get tripped up on this - there's much more to REST than just HTTP. This part of it doesn't really have a name, but it should. "Raw HTTP," maybe? Raw HTTP does beat the heck out of SOAP, so it's a step in the right direction. But true REST devotees make fun of APIs which use only one HTTP verb (GET) and have their own custom verb embedded in the URL. Amazon is (in)famous for this, yielding SimpleDB calls that look like this:
GET https://sdb.amazonaws.com/?Action=PutAttributes&DomainName=MyDomain&ItemName=Item123&Attribute.1.Name=Color&Attribute.1.Value=Blue
A true REST API would look more like this:
PUT https://sdb.amazonaws.com/MyDomain/Item123
...with an input body containing an XML (or even CGI) representation of the data being updated. (Subbu Allamaraju explores what's wrong with the SimpleDB API in detail.)
Headers, Verb, Resource, Payload
So true REST calls divide up the HTTP protocol space into four sections: the headers, the verb, the resource, and the body. (I like to call the input body the "payload," which makes its purpose much clearer to me.) When you're designing a REST API, you have to make sure that each piece of data goes into the correct section, or else things turn into a mess. Let's look closer at each.
The headers are meta information about the request. Most are used by the webserver and don't concern the web app or its API, but two (Content-type and Accept) are important, since they describe the nature of the input body and output body.
The verb is the HTTP method: GET, POST, PUT, or DELETE. These map exactly to the standard CRUD operations: GET = read, POST = create, PUT = update, DELETE = delete. These are the only verbs you can use, and that's all there is to it. This rigid uniformity is a plus, but it takes a while to learn to adapt to it. More on that later.
The resource is what is described by the URL. It's a noun, and by itself does not describe any action. You can do things to a resource, but a resource itself doesn't do anything. (Hence the clever term "RESTful resource" - the resource is at rest, not moving.) Amazon and others who write raw HTTP APIs get flack for calling their APIs REST when in fact everything goes into the URL, ignoring the other three sections.
The payload is the input body of a POST or a PUT. (The other two verbs don't have payloads.) This point turned out to be key for my understanding of how to use REST in the real world. The payload is data you are sending to the server, for use in creating or updating a resource. The simplest example is a form full of data, but its uses are actually much more diverse and flexible than just forms.
The flexibility of payloads comes from the Content-Type header. With a standard web form, your content type will usually be application/x-www-urlencoded. This basically makes the payload of the POST be a bunch of CGI parameters. For years I thought of POST and its ability to stuff the parameters into the payload as nothing more than a way to avoid cluttering the URL. But once you start using different content types with your payloads for POST (and PUT), a whole new world of possibilities opens up.
For example, to upload a photo into a photo collection, you might do:
POST http://myphotos.example.com/users/adam/photos
...with the content-type set to image/jpg and the payload containing the binary data of the image.
How about importing an archive of images? Use the exact same resource! Just set the content-type to application/x-gtar and pass a payload containing the binary data of a tarball.
Updating an existing image could be:
PUT http://myphotos.example.com/users/adam/photos/12345
...again with a content-type of image/jpg and the binary data of the image. But what about updating the metadata on the image, like a caption? Same URL, but switch the content-type, perhaps to application/xml (or perhaps trusty old application/x-www-urlencoded).
How about fetching different types of data for a resource? Just mirror the process: it's now a GET, and we'll use Accept to ask for a different type of content in the returned body. For example, you could download the image by setting the Accept header to image/jpg; or download a collection of images by setting Accept to application/x-gtar.
This distinction between the verb, the resource, and the input and output bodies (each with a content type) is the core of what makes REST both useful and usable.
Status Codes
There's one other piece of the HTTP puzzle here, which is the status code returned by a request. In practice I've found there are three codes you really care about in designing or accessing an API: 200, 401, and 422.
200 means success, everything went fine.
401 is unauthorized, meaning that you failed to supply the proper credentials. Typically this means you need to check your http basic auth username and password.
422 is unprocessable entity. In a Rails app, this usually means that the attempt to create or save the record failed, and the returned body contains XML with the error messages.
Status codes can be treated something like the return value on a shell command; if it's bad, you should treat the result differently than if it was normal. Check out the processresult method in restclient.rb for an example.
Putting It All Together
Now, the big question - how do you make do with only four verbs? The answer is: more resources. In particular, nested resources, but not necessarily full model resources. Rather, think about dividing the domain space of your individual objects into subresources - whether or not this is represented by a separate record in your database.
I'll give you a particularly gnarly example straight from my own real-world experience: Heroku apps. We have a model, App, which maps to the apps table in the main database. This is our central model: everything revolves around the app. As a result, our first pass at the internal API on our backend ended up with an AppsController that had 20+ actions.
These actions make perfect sense: they're the verbs that we need for the App object. Some examples: rename, import, export, purgedatabase, restartserver. How in the world can we represent these with just CRUD operations?
The answer lies in a proliferation of subresources. To quote Mike Clark, the question that REST is always asking is: What's the resource? And if you let yourself break from a one-to-one mapping between resources and models, things get a lot more flexible. So let's map those actions I mentioned to REST, keeping in mind that we also have payloads with different content types available.
| action | verb + resource | payload |
|---|---|---|
| rename | PUT /apps/myapp | content-type: application/xml |
| import | PUT /apps/myapp | content-type: application/x-gtar |
| export | GET /apps/myapp | accept: application/x-gtar |
| db_migrate | PUT /apps/myapp/rake | payload: db:migrate |
| purge_database | DELETE /apps/myapp/database | |
| restart_server | DELETE /apps/myapp/server |
Check out the subresources on the bottom three. These aren't necessarily ActiveRecord models, though they could be. But conceptually, they represent a particular area of action. There may or may not be a Database object belonging to the App, but it makes sense to subdivide the problem space by implying a has-a relationship between app and database.
What's more, you may find that a designing a clean URL scheme gives a great deal of insight into the design for your internal architecture. If you create a REST subresource that isn't a full object, perhaps you should stop and think about making it one.
rush 0.2
March 13, 2008 at 01:43 PM
New features include:
- an exceptions framework (communicated across the wire - an exception on the remote box raises the same exception locally)
- Box#bash to execute arbitrary bash command (returns stdout, raises an exception with stderr if shell command returned failure)
- FindBy extensions for processes.findby_pid(123) and processes.findallby_cmdline(/mongrelrails/)
- Process#parent and Process#children
- Process#kill doesn't return until the process is really dead (courtesy of the god code)
- Improved tab completion
Read the full announcement for details.
Startup School
March 12, 2008 at 10:50 PM
If you're a hacker that has thought about (but not yet attempted) creating your own startup, you might want to think about attending Startup School in April. It's in the Silicon Valley area, but even if you're not local, the list of speakers may be worth the trip. I've heard most of these guys speak at some time or another and each of them had extremely valuable wisdom to share.
Morning Clarity
March 11, 2008 at 05:34 PM
One of my favorite life hacking tips is how to use your morning time. (By morning I mean whenever you get up - for me, it's technically afternoon.)
Recently, I've taken to using this time to jot down a simple plan for the day. Before anything else I ask myself: What's one thing I could do today that would make me completely satisfied with my productivity for the day?
This is no doubt influenced by The 4-Hour Workweek's suggestion that you ask this question of yourself throughout the workday. At each moment you should be doing something that, were it the only thing you accomplished today, would leave you satisfied with the day. This is a great way to avoid excessive rabbit-trailing; but I think it works even better if you make the plan first.
This only works if you write down your plan before you let any distractions into your mind. That means: do not open your feed reader, do not check your email, and do not look at your phone to see text messages or calls that came in overnight. Do not open any program except a blank page in your text editor, where you'll write the plan for the day. And make sure you left no windows open on your screen the night before. When you sit down for this you should find yourself before a blank slate, with a zen-like mental state to match. Only then can you focus clearly on the big picture and decide your most valuable short-term goal.
By the way, when I say "plan," what I mean is a few words of shorthand notes for each item, and no more than three or four items. Something like:
- proof of concept for widget manager - fix the gadget tracker page not found bug - email joe to schedule that meeting
Short, sweet, to the point.
This moment of calm reflection brings incredible clarity. It's so tempting to think "I'll write this stuff down as soon as I check for that important email that should have come in this morning," but resist that temptation. If your inbox is anything like mine, as soon as you open it your focus is forcibly zoomed in on a flurry of user requests, questions from your coworkers, exception notifications, and so on. Within minutes of facing this hailstorm of information, the valuable clarity and perspective is whisked away, not likely to return again until the following morning.
Rest Client 0.2
March 11, 2008 at 12:16 AM
Based on Dan Kubb's suggestion, I've implemented an ActiveResource-style accessor for rest-client. This also supports basic auth, so now:
r = RestClient::Resource.new('http://example.com/photos/', user, pass) r.put File.read('pic.jpg'), :content_type => 'image/jpg'
The static methods for raw URL access are still available as well. See the updated RDocs for details.
Rest Client
March 09, 2008 at 08:03 PM
REST is part of the Ruby Way. Which is why I'm surprised that every time I go to access a RESTful resource, I find myself writing some sort of ad-hoc rest client. Net::HTTP is too low level - you've got to write at least three or four fairly dense lines of code even for a relatively simple GET or PUT.
I was banking on ActiveResource being the defacto solution starting with Rails 2, but I was a bit disappointed when it was finally released. Its purpose is fairly narrow - accessing resources that are database-recordish and which operate completely in a certain XML format. But further, it doesn't (as near as I can tell) support nested resources, which cuts out about 70% of what I might want to use it for.
The only other thing I can find is this, which monkey patches open-uri to handle other kinds of verbs. Fine, but still a bit too low level.
While I was toying with Sinatra the other day, I realized that what I wanted was just the client-side equivalent of its controller syntax. So I threw together rest-client.
require 'rest_client' RestClient.get 'http://gemtacular.com/gems' RestClient.post 'http://myphotosite.com/users/adam/photos', File.read('pic.jpg'), :content_type => 'image/jpg' RestClient.destroy 'http://heroku.com/apps/myapp'
The middle one - post (or put) with a payload an non-xml content-type - is the one that interests me the most, and that I find hardest to do with other libraries. Particularly for a one-off on the command line. I'll usually hobble together a curl command with a bunch of obscure switches that I can never remember. But now, I've just added require 'rest_client' to my .rush/env.rb, so at the rush command line I can instantly access any REST resource on the web with an easy-to-remember one-liner.
I also threw together a test server at rest-test.heroku.com, to try out all the different verbs. It just echoes back the verb, resource you requested (wildcard routing will match anything), and info about the payload. Here's a session from my rush shell:
rush> RestClient.get "http://rest-test.heroku.com/some/resource" GET http://rest-test.heroku.com/some/resource rush> RestClient.put "http://rest-test.heroku.com/some/resource", home['pic.jpg'].contents, :content_type => 'image/jpg' PUT http://rest-test.heroku.com/some/resource with a 70335 byte payload, content type image/jpg rush> RestClient.delete "http://rest-test.heroku.com/some/resource" DELETE http://rest-test.heroku.com/some/resource
gem install rest-client if you'd like to give it a try. RDocs here.
git-wiki
March 09, 2008 at 02:28 PM
git-wiki is a wiki written in less than 200 lines of code using Sinatra as the web framework and Git as the database. Quite clever. Check out how they store the CSS at the end of the file using END - a Ruby trick I was previously unawrae of.
Incremental - Always
March 07, 2008 at 01:12 AM
Programmers generally agree that working iteratively is a good idea. But sometimes, we'll say: you just can't. This particular problem has to be done in one big bite; there's no way to break it down into smaller pieces; we just have to take the plunge.
Poppycock, I say. (Or perhaps something stronger.)
I've begun the process of using rush in Heroku's infrastructure. But this is tough: it's an unproven and immature library, barely a month old. Worse, most of the things we want it for - system-level calls - are of critical importance. Misplaced files are not forgiveable the way that, say, a UI glitch might be.
I started by selecting the absolute least important bit of code it could be used for. This component is something that happens very infrequently: rsyncing config files when launching a particular kind of instance. Further, I launch these manually (unlike some other instance types which self-scale), so there will always be someone watching the logs when it boots up.
But I took it even a step further. I kept the old method around and, in the case of exception on the newly rushified method, call it as a fallback. Here's the code:
def sync_nginx_conf sync_nginx_conf_via_rush rescue Exception => e Log.error "Exception on sync_nginx_conf via rush, falling back to rsync: #{e.summary}", :addendum => e.full_display sync_nginx_conf_via_rsync end
This is not foolproof; something in the rush sync could write an incorrect file without throwing an exception, for example. I'll keeping a very close eye on this method when it runs in production. Once this has proven itself in action, I'll feel confident in taking a bigger step.
Unobtrusive Screencasting
March 04, 2008 at 12:47 PM
I wish screencasting were more ubiquitous. Not just developers showing off their products, but for everyone. When a customer sends a bug report to customer service, it should be completely standard for them to include a screencast of themselves experiencing the problem. Used properly, screencasts could become a sort of multimedia email for anyone who works on something that can be displayed on a computer screen.
I've had this sense ever since watching my first screencast (DHH's "make a blog in 15 minutes" - probably many people's first). A year or so later I went looking for screencasting software and discovered that despite the apparent popularity of screencasts, the authoring software available was fairly lackluster.
I ended up making do with hacked up copy of pyvnc2swf plus a command-line audio recording tool when I made these. Nowhere near turnkey, to say the least. Later I started using iShowU on the Mac, which is an ok piece of software, but not grand by any means. Plus, it's shareware, which pretty much means it can never achieve ubquity. (This is not because people are unwilling to pay, but that the process of payment creates friction that will always keep it out of the hands of some portion of the computer-using population.)
Recently I had occasion to try out Istanbul, an open source project for screencast recording on the Linux/GNOME desktop. I am very impressed. This is desktop software at its finest: simple, streamlined, does exactly one thing and does it well. Compare the bewildering battery of options on iShowU to the easy-to-understand context menu of Istanbul, for example.
But perhaps more significant is how it runs. It sits in your dock, showing a simple record icon (red circle) when inactive. Click it and you instantly begin recording - no questions, no dialogs, no delay of any kind. Click it again to stop your recording, review it, and either discard or save it.
It saves to Ogg Theroa, a format I'm excited about for reasons I'll mention in a future post, but thanks to ffmpeg you can convert it to pretty much any other format.
This quiet, always-accessible aspect of Istanbul represents what I hope is the future of screencasting. iShowU dominates your screen with a huge window whenever it's open; you'd never have it open perpetually. This is quite reasonable, if you assume that screencasting is an occasional thing, a big event. But technology is the most useful when it becomes an unobtrusive part of the background, a tool that is always within each reach. Istanbul shows us that future for screencasting.
Sysadmin vs. Programmer
March 02, 2008 at 04:16 PM
I've spent much of my career straddling two worlds: systems adminstration and programming.
Sysadmining is the world of unix, processes, filesystems, daemons, networking, and servers. Sysadmins are all about getting hands-on: solving a specific instance of a problem, rather than the entire class of problems. You could call this ad-hoc and shortsighted. You could also say that it's just being pragmatic and realistic: solving a real problem, today, right now.
Programming is a world of design, theory, and elegance. Programmers are notorious for prefering solutions which are elegant over those that actually work. It's not about solving a particular instance of a problem: a good programmer wants to solve all the problems of that sort, now and forever.
People's personalities tend to lead them into one area or another. For some reason I always saw the value in both. Or actually, I never even realized that there was a divide. I thought of them as being different aspects of a more general category: how to make computers do your bidding. Only when I got my first jobs and started working on development teams it become clear that there were two camps.
There's no moral to this tale, it's just an observation.