Sunday, April 17, 2011
Python tip: 3.2 adds a memoization decorator
http://docs.python.org/py3k/library/functools.html#functools.lru_cache
There's some other neat stuff in the functools package too: currying and reducing. Pretty slick!
Tuesday, February 26, 2008
Today's viewing: Linus on git.
"There's a few of them in the room, I suspect -- you're stupid!"
-- Linus calls out the svn developers on hand
The Linux kernel team had previously been using the proprietary BitKeeper, which a number of kernel developers (including Alan Cox, with his Mighty Unix Beard) chose not to use. Before that, source control for the kernel was handled by sending patches around -- preferable to using centralized source control, according to Linus.
So let it be known that I haven't actually /used/ git yet, or in fact any distributed source control system -- but I like the idea so far. In this post, I'll outline the reasons Linus lays out for why we should be using git.
First off, the distributed nature of git also has performance and convenience benefits, from the simple fact that it doesn't need to make network roundtrips. Having your own repository on the local machine means that you're always set to go, even if the network is slow or unavailable.
Secondly, traditional source control makes branching and merging branches hard (Linus points out that many real-live software developers have never done it), so you don't want to commit your work until it's ready to be seen by others -- this means that you can't do much version control during the actual code-writing process. Contrastingly, in distributed source control, every checkout acts as its own branch, so each developer has at least one. This has the benefit that you can commit to your own repository whenever you want -- and then back up to previous versions whenever you like.
Centralized approaches to source control are particular drag when people are depending on your committed code as correct, or at least non-breaking -- you're not allowed to commit until your changes are ready for the rest of the team. As a project gets bigger, the associated test suite (hopefully) does as well, eventually leading to a pretty involved testing procedure that developers are supposed to complete before committing. And as Linus puts it, "... people make one-liner changes and ignore the test suite, because they know that those one-liners can't /possibly/, /possibly/ break." And then these breaking changes get pushed out to the rest of the team. The alternative approach, with git, is that you commit to your own version of the repository whenever you want, and when you're ready, your teammates can pull from you -- but in the mean time, you get all the benefits of having your own branch(es).
Thirdly -- social benefits! In his development process, Linus only pulls code from ten or fifteen other developers, whom he trusts to have filtered "up" appropriate changes from the people that they interact with. As he puts it, "if you have determined that somebody else is smarter than you -- go for it!" So the Linux kernel source control process mirrors the social networks of trust that make the whole thing happen. In the end, a lot of people end up only looking at the Linus branch, the defacto "official" one.
This dodges the social issue of giving out commit access to the central repository. Traditionally when managing a project, you create this class of people who are "ostensibly not morons", and typically, you make that group of people too small. Distributed model makes this go away, because everybody has his own branch. And if you happen to do good work in your own branch, then people start pulling from you! "That alone means that every single open-source project should use nothing but a distributed model."
So. That's what Linus said. Will everyone switch to git or some other distributed source control? We'll find out. Adoption would certainly be helped out if major project-hosting sites like Sourceforge or Google Code added git support. But sort of the point of the distributed model is that there's no one central hosting point...
Maybe I'll try it out. I'll let you know.
Saturday, January 05, 2008
Design Patterns Ahoy: Violator Pattern
And while, so far, it seems like just good, solid advice about software design -- and at the risk of sounding uncritical, is it really so bad to have common names for commonly-occurring software structures? -- ... no "Violator" pattern is to be found in Gang of Four. Or on the C2 design patterns wiki.
And I wanted to work out for myself what this mysterious Violator Pattern could be. And I figured it out today. In GWT, you can use the JavaScript Native Interface to make calls from code written in JavaScript into methods written in Java. And when you do this, the compiler totally ignores the access modifiers on the methods you're calling. That's the Violator pattern.
A paragon of OO design, verily :)
Wednesday, August 22, 2007
typing about typing about types
As we make the push to handle Java 1.5 features in GWT (it's about time!) I'm having flashbacks to undergraduate Compilers. Perhaps this is unsurprising, considering what I'm working on. Part of the difficulty in the problem is that whether you're talking about types in the code that constitutes the compiler itself, types in the code that the user is going to put in, or types in the output code... we use the same word. Oh my. (much worse, I suppose, is the code you get with the Appel book, where half of the words on the screen are helpfully "ty" or "typ". Jebus.)But! All of this means that by the next GWT release, you'll likely have some code that I touched in your hands. Woo.
Sunday, August 05, 2007
"If I knew the answer ahead of time, I wouldn't be writing this program!"
On the plane back from San Francisco to Atlanta, I read Thomas and Hunt's Pragmatic Unit Testing. It's a very quick read, about 120 pages plus appendices. And while it's very light, it has what seems like a lot of helpful advice for good design and development practice. To be honest, I've never done much unit testing in the past, thinking "oh, that's what those corporate software engineer guys do -- pssh." But! It turns out that these days, I am a corporate software engineer, and anyway one should always be looking out for new ways to hack more effectively.
There's a bunch of important principles to take away from Pragmatic Unit Testing. The one that stuck with me the most, though, is that when designing and writing code, you've got to think: "how am I going to test this?". The significance of this is not just "oh man, I'm going to have to write a unit test for my method"; it gets back to that generally-understood but oft-ignored idea that every logical unit of your code really wants to be its own method, a modular thing that you can use separately -- because you're going to have to use that same calculation again somewhere else. And Don't Repeat Yourself.
For example: if you have a method that calculates how to do something and then does it (say with a call to another library), maybe you want to make that two methods: the calculation and then a call to that calculation coupled with the library call. This will be easier to test -- you're not really interested in testing a third-party library, just your own calculations -- and as a happy side-effect, your code is now cleaner and more reusable!
Similarly, separating out the backend code from the GUI (two of the things that get my hackles up the most in this life are terms "business logic" and "MVC") lets you properly test the Stuff That Does Stuff on its own. One example in the book hit particularly close to home -- a small GUI application where all the caculations and I/O happened mixed in with the Swing code.
That example, and in fact the whole book, brought on flashbacks to a project I'd worked on recently. One of my friends and I (and he's one of the sharpest guys I know) inherited a fairly involved program and ended up sinking months trying to fix it up. This system suffered from pretty much every pitfall in the book: random silently-caught exceptions, real work happening mixed in with the GUI code, needlessly long, opaque, nigh-untestable (let alone "tested") methods, repetition all over the place. Worse! It was built by a guy who'd supposedly specialized in software engineering -- and he did pretty much everything that Thomaas and Hunt warn against! Not a pleasant situation. I'm sure you can relate.
Of course, I knew at the time that this was atrocious code. But now maybe I'll be a bit more principled in my development, working with a lean towards easy testability. Unit testing will probably be a good discipline to get into.
On the other hand, I've been reading about (and writing a bit of) Haskell. All this murky business of setting up and tearing down state, "proving" to yourself that each function does what you think it does "for the boundary cases" -- it all relies on the idea that you're going to be able to predict where you're going to make the bugs (by heuristic, habits, and mnemonics). And if you're smart enough to predict where the bugs are going to pop up, it seems like there's something better you could do to keep them from being introduced at all. In ML for the Working Programmer, L.C. Paulson suggests that a mark of the professional in the future will be writing functionally (in ML). The modularity practices seem like the Right Thing, useful for the functional programmer as well as the OO, but if your code could be formally verified, how much more confident would you be that it was correct for the general case? Simple testing is nothing like a proper proof.
But who ever writes proof-carrying code?