Two-month plan postmortem

August 25, 2008 by bearpatch

So it’s been two months.  We didn’t complete all the tasks on this list, but we came pretty close.

We got very far with the speed improvements:

  • Server switch
  • Plone upgrade
  • Multiple Zope servers in production
  • Changing file attachments’ storage mechanism
Only the first of these is totally done, but the Plone upgrade is going to be deployed very soon, with the load-balancing servers following soon after that.  Ra’s gotten pretty far with the storage work, and it’ll be done well before we actually have a free moment to deploy it, so it’s effectively ahead of schedule.A pretty good showing on software dependency upgrades:

  • Upgrade WordPress on Streetsblog and StreetFilms
  • Upgrade Xinha on Streetsblog
  • Upgrade Xinha on OpenPlans.org and LivableStreets
The first two are done, though it took us quite a while to actually have an opportunity to do them.  The last one is scheduled to happen after the Plone upgrade, so it’s waiting on that.We hit most of the new feature targets:

  • Project wiki backup
  • Account deletion
  • Project-specific search
  • Tagging
The first two are totally done and the last is implemented and functional (which was the only target here; there were no plans for any deployment of a tagging feature).  The project-specific search is the only one we didn’t do, and it’s just a matter of getting around to it and doing a bit of work with a design-savvy individual.We didn’t actually launch either of the large-scale lingering projects:

  • Geotagging of people and projects
  • NYC Fix-It Map
The geotagging is almost done, but I’ve been saying that for the entire two months. :)   And the NYCFIM hasn’t seen any attention since I re-enabled its demo and discovered some bugs that prevent any use.  Both of these could probably have been launched in time if we’d just taken a bit more focused time and attention to finish them up.  (And to be clear, that’s entirely my fault, for not scheduling that focused time and attention.)

So, putting it all together, I think missing the target boils down to two things: the Plone 3 upgrade, and lack of commitment.  Four of the seven missed target projects are blocking on the completion of the Plone upgrade, and the other three we just didn’t really get around to.

I think deadlines are an easy and obvious solution to the second problem.  These objectives sort of qualify as deadlines, but they were a bit vague, not exactly a commitment, and I think most importantly grouped together — nothing has an individual deadline, so the set of projects are naturally prioritized and the ones that are large-ish (particularly those that “just” involve attention more than they do anything else) and/or not urgent priorities just slip to the back.  Those are the sorts of projects that I think would really benefit from deadlines … provided they can be identified.

As for the Plone upgrade, it’s hard to say yet what it really points to.  Maybe it means that our deployments take too much time and effort.  (Which I think they do, but Doug’s been furiously working to improve that as he does deployments to OpenPlans.org, so each one is easier than the last.)  Maybe it means that we don’t have enough sense of how, when and how much to test an upcoming deployment whose changes are very wide-reaching.  (Which I think we don’t, but I have no idea what we could do better.)  Or maybe it just means that upgrading OpenCore from Plone 2.5 to Plone 3 is a uniquely fuzzy and fairly risky thing and that I was just overly optimistic about the effort it would require, and it’s just a one-time mistake with no useful information to mine.  I think the Xinha upgrade and the load-balancing will be pretty decent ways to figure out if there’s a fixable underlying problem here, so I’ll be particularly curious to see how those go.

There’s one other problem I think I see here.  Though we did get around to most of them, the server switches, Streetsblog software upgrades, and Plone upgrade did all happen later than I was expecting, even leaving aside how long they took to finish after they had been started.  In a sense I think they all suffered from a sensible reluctance on the part of the stakeholders (variously, Nick, Aaron, Doug, Bryan and myself) to pull the switch on a major upgrade.  In the case of the server switches and Streetsblog upgrades — the ones we’ve actually managed to pull the switch on — it was even difficult to schedule a time to do it, between regular site traffic levels and planned events on the sites that required high reliability.  Broadly speaking, I think we can improve this with more and more explicit communication with stakeholders: agreeing upon a set of acceptance tests in each case; stakeholders perhaps listing, on a private calendar somewhere, their planned upcoming needs for reliability; the engineering team setting some span of time in which to perform an upgrade; stakeholders picking a date and time.  I’d be curious to experiment with some of these.

At this point I knew I had stayed up too late coding.

July 28, 2008 by bearpatch
>>> viewlet_app
<function viewlet_app at 0xdc6c80>
>>> viewlet_app(app)
<function filter at 0xedb488>
>>> viewlet_app(app)(app)
<class 'footsie.viewlet.ViewletManager'>
>>> viewlet_app(app)(app)(app)
<footsie.viewlet.ViewletManager object at 0xf3c9d0>
>>> viewlet_app(app)(app)(app)(app)
*** TypeError: __call__() takes exactly 3 arguments (2 given)
>>> viewlet_app(app)(app)(app)(app, app)
*** AssertionError: URL fragments must start with / or http:// (you gave 'viewlets')
>>> try:
...   reduce(viewlet_app, [app] * 3)(app, app)?
... except AttributeError:
...   raise AttributeError("Something has no attribute 'app'")
... finally:
...   print app, app(app), (app(app, app), app)

Programming by Interface

July 20, 2008 by bearpatch

The other day I started writing a Python library to provide support for programming against interfaces with swappable implementations. In general I like the ideas of the Zope Component Architecture but in my experience it can be a bit of a pain to work with, and I’d like something more lightweight which can ideally be useful on its own or in conjunction with ZCA (either side-by-side or wrapping it) and other systems. I should mention that I haven’t had any firsthand experience with Trac’s interface/component system, but from what I’ve seen of it, it suffers from more or less the same problems as ZCA.

The guiding principles are something like:

  • No surprises; explicit, auditable code both in the library itself and in consumer code. In my opinion ZCA tends to fail here; even just stepping through the code for “getComponent(IDesiredInterface)“ in a pdb breakpoint is too confusing and convoluted. Straightforward Python code without interfaces tends to do this very well, of course
  • Loose coupling. There are four classes of people each writing distinct types of code: the designer of an interface, the consumer of an interface, the implementor of an interface, and the integrator. The integrator should be the only person who needs to select implementations for interfaces in use, and it should be as easy as possible for him to make informed decisions. Interface implementors should not need to know about anything beyond the interface, and ideally even need not know about the interface, so that an interface can be retroactively applied to an unwitting implementation. The ZCA accomplishes this quite well — through arbitrarily distributed ZCML directives, an implementor doesn’t even need to know that it’s implementing a particular interface. It could do a better job of making the integrator’s life easy, though.
  • This is really a sub-point of “loose coupling” but it’s rather crucial so I’ll mention it separately regardless: consumers of an interface should not need to know anything about what’s behind the interface. If I’m writing code to interact with an object of type IDesiredInterface, I should never need to inspect the implementation at all. Period. Good examples: “str(obj)“ (which implicitly assumes that “obj“ implemented IString) and “getComponent(IDesiredInterface).doSomething()“. Bad examples: “envion['beaker.session']“ (which, in its semantics, relies upon a particular implementation of a session object) and “getComponent(IDesiredInterface, name=’this_one’)“ (if you’re invoking an interface with a disambiguating name, you’re not programming against the interface).
  • Lightweight as a framework. I don’t want to force anything on any consumers, only to provide tools that could be used by anyone who feels like using them. Ideally code using this library should look more or less just like any other Python code (which ZCA-consuming code certainly does not). So, for example, I provide tools for validating that all required interfaces are implemented and that all purported implementations actually conform to the interfaces, but don’t actually enforce either of these restrictions. Client code can choose to invoke the validation tools and enforce the restrictions, or it can choose not to. Similarly I provide some scary magical tools (in the helpfully named scarymagic module) but do no more than providing them for someone else to invoke.
  • Minimize abstraction. This might seem like a strange goal for an interface library, but I think it’s an important goal if code is to be clean and meaningful. So in this library there isn’t actually any well-defined notion of what interfaces and components are, even though I use that language, because those terms strike me as being so general as to be conceptually empty. Instead an interface is any object that is said to be an interface, and a component is any object that is said to implement an interface. Along the same lines, I’ve avoided formal schemas, which always seem very un-Pythonic and unhelpful.

I’ll expand on that last point a bit. Code is communication and code expresses intention and reflections of reality. Well,

class IDesiredInterface:
name = Schema.TextLine()

does not express any meaningful assertion with all that formal code, nor does it naturally convey any information to real humans. But

class IDesiredInterface:
name=None # the name by which the object is known, used in string representations and the object's whoami() method

does naturally convey information to humans, through a combination of sensibly named variables and informative comments, and is not inherently less informative to machines. This does cause some difficulties for reliably meaningful automated validation of implementations against their interfaces, which I’ll admit is one of the reasons I’ve left that part rather underdeveloped, but for the same reason it’s not obvious to me that reliably meaningful automated validation of implementations is actually a worthwhile goal.

Speed is not a guiding principle, and I think it shows. I don’t think it would be particularly difficult to make the implementation efficient; I just don’t yet have any reason to do so.

There’s no built in support for any of the other features of interfaces in ZCA like adaptation or marker interfaces. I think these would be fairly easy to build on top of my code, but I’m not sure there’s a good reason to.

Anyway, you can check it out at http://svn.sccs.swarthmore.edu/egj/ifoo. I can’t really tell whether it’s actually useful at all — in fact I’d say it’s code-to-make-a-point rather than code-to-use-in-production — so I’d love any feedback.

Do Deadlines Work?

June 20, 2008 by bearpatch

A few months into managing a fairly large team of programmers, I started saying to myself: “The next step is to start setting deadlines!”  But I never actually seem to get around to it.

That kind of bothers me, because I’m not sure how I can benchmark success without deadlines.  After all, wthout a deadline, how do you measure a project’s efficiency?

But when I do try giving deadlines, nothing whatsoever changes.  Either the deadline is met, or it isn’t, and if it isn’t … I stress a bit and pace around the room, and in the meantime the work gets done anyway!  Even in my mind, I feel no more or less confident about progress against goals when deadlines are in place.  The nature of programming means that a project can be 98% complete in under half its scheduled time, and that last show-stopping bug is only found three weeks later and takes another nine to isolate and fix, so, really, what information does anyone gain by pretending we can say “it’s X percent done” and checking it against a calendar?  Deadline or not, the best and only useful measures of progress are the subjective outlooks of the implementors and manager, and finally the knowledge that the project is over (if you’re lucky).

(Sidenote: I should probably be talking about the role of the customer and iterative real-world feedback in this, but I haven’t yet managed any projects that have a particular external customer, let alone in XP fashion — which in turn means I haven’t yet managed any projects that have any meaningful deadlines imposed by external constraints.  I have no idea whether my present feelings on deadlines will apply to, or be completely changed by, an experience of that sort.  My theoretical understanding is that customers and rapid iterations provide a finer granularity of feedback but retain the same overall structure — meaning, I think, that iterations should be scope-driven and not time-driven.)

And, really, I have my own feelings about whether projects are going well and people are working well.  Those are pretty independent of deadlines; they’re just intuitive feelings that “this is starting to take too long” or “that’s going in the wrong direction.”  But of course … without deadlines, how can I ever know if I’m right?

It’s a bit of a circular problem, but all in all my hunch is that the confidence that a framework of deadlines provide is a false confidence; it might make you better able to verify the accuracy of your predictions against a model, but the model is fatally flawed, so the confidence is worse than useless.  That requires a certain amount of cliff-jumping, of course; it means embracing unknowns and throwing yourself headfirst into a completely unstructured space, armed only with confidence and subjective tools for “empirical” correction.  That’s a problem, but I think by rejecting the framework of deadlines-as-evidence you can find better metrics somewhere.

So it leaves me wondering whether deadlines are just a sort of calcified process, where we go through the motions to support a system that doesn’t actually support us in return, so we’re just generating emotional stress and wasting time, paper and mental space with a hollow ritual.

Open Source, For Real

May 25, 2008 by bearpatch
I originally wrote the following in late January 2008 for The Open Planning Project’s internal development blog, after returning to New York from the Zope 3 Snow Sprint in Austria.

A lot of times at the Snow Sprint I was struck by a feeling that I was in the middle of a group of people who were really doing open source right. So on the plane home I started thinking about what that meant and why I haven’t felt that way at TOPP.

Well, a lot of us have said at various times that our attempts at doing open source development have often been frustrating and rarely seem to be worth the effort. Coming out of the sprint, I think that’s because we are missing a very big piece of the “True Spirit of Open Source”. Doing open source properly is not just a matter of putting the GPL on our code—it is not about making a legal contract but about making a social one. It is about committing to reuse and collaboration both internally and externally and it is well worth the effort.

Writing, finding, and using software all take time and care and with someone paying for our time and care we ought to think of these acts as investments. We should make the most of those investments by seeking code reuse and encouraging collaboration. The more we encourage heavy use of software and heavy reuse of code, the better our ability to improve and solidify it. Whether or not we’ve read Dreaming in Code (though everyone here should—as soon as possible—seriously) we all know that software is hard to do well. It’s full of unexpected behavior, prone to breaking when you touch it, and rarely optimized. We can improve it only by testing and exercising it: give it to people to use, poke it in new ways, put it under stress, see what breaks, fix it and don’t let it break in the same way again.

Laziness is a virtue

Because software is expensive to write, it is most responsible of us to write as little as we can. And because software is hard to write, it’s rarely done once it’s written; most software has tremendous room, and often necessity, for improvement. So our goal should be to maximize the impact of every improvement we make. This primarily means seeking to increase the breadth of our code’s effect: convincing other people to use our software, sharing code across multiple products, and reusing products in as many ways as we can across everything we develop.

To give a specific, if vacuous, example, we have five or more different pieces of code deployed on OpenPlans that generate and send email to users: Listen sends mail, Twirlip sends mail, WordPress sends mail, and Opencore sends mail in at least two different ways. Suppose, instead, that we had a single shared way to send mail to users. Aside from the immediate benefit of less overall knowledge to store, the different mail-sending needs of all these applications would force us to develop a stable and reliable method for sending mail, and when heavy usage of one of those dependent applications inevitably reveals an inefficiency or bug in the mail-sending code, multiple otherwise unconnected parts of our site would instantly benefit from our resulting improvements. Put that same mail-sending code on two or more websites and encourage other developers to deploy it in their applications, and we can tremendously increase both the number and variety of stress points and the magnitude of impact of each strengthening, both the opportunity and the payoff for improvements.

So maximizing adoption of every piece of software by both users and developers is a forward-thinking and cost-effective stance. It gives programmers the most opportunities to strengthen their (buggy, brittle) code and ensures that every (hard, pricey) act of improvement has a large and wide-reaching effect.

We’re not alone

It is not only creating software that needs be treated as an investment. In a true open source environment using others’ software, too, is an investment that we should make the most of. When we choose to depend upon existing free technology—in any way: WordPress, Xinha, Zope, Pylons, Trac—we will benefit ourselves and others by doing all that we can to improve it, participate in its communities of users and developers, and encourage the growth of those communities. The core reasons are the same as with our own code: the more eyes and hands that are on a piece of software, the better it can become.

There is, of course, an additional benefit to encouraging outside developers, namely lessening our internal development and maintenance burden by gaining volunteer contributors. When we create our own software we thus have the additional responsibility of building these communities from nothing. But when we are dealing with existing open source software this goal is all the easier to achieve. A community of developers already exists; our only responsibility is to gain admittance. We should treat our lack of commit rights not as an obstacle, but as a challenge.

Alongside the fuzzy feelings that come with earning the respect of an established group, there is, in keeping with the best of the open source mentality, great potential for everybody to win when we are welcomed into an existing community. We stand to reap the benefits of the efforts of the intelligent, experienced and caring people who develop the software that we have decided is worthy of our use, and we gain the potential to influence the path and priorities of their development with our input and interest. They, meanwhile, gain the feedback and work of a new set of smart (and funded) contributors with a real interest in the success of their project.

Finding those unicorns

I’ve framed this primarily as an economic argument to be concrete, but of course there’s more to it than that. The same stance is also about committing to respectful and positive relationships with outside agents; putting our faith in open and collaborative development environments and in the potential for groups of smart, committed people to produce great things even with differing agendas; taking the time and care to make our work as good as it can be and letting the rest of the world be the judge of it. It’s about being responsible consumers who contribute back to the products we consume, and being responsible producers who proudly stand by what we produce. And then there’s our aspirations at TOPP to do good and produce real positive change: all the time and money we can save by reusing and building on existing solutions can be diverted toward new projects to do even more good in the world, with cascading effects.

So let’s build and get involved with communities, submit and fix bugs in others’ code, give thanks and contribute ideas to the people whose software we use.

Let’s release Flunc, Externalator and Deliverance to the world for real, with welcoming websites and helpful documentation, and encourage people to use them and talk to us about them on mailing lists and IRC channels. Along with everything else it’s a good way to put our software to the test: to put a different spin on the dogfood concept, if no one else wants to use our software, why should we? Let’s keep up with Xinha development and submit behavioral patches to its authors instead of keeping our work isolated on our “vendor branch.” Let’s tell people about the recommendations of our smart interaction designers and submit our implementations of that advice; how many open source software communities have an excess of input from web software designers? Let’s release WordPress and Trac plugins to their wider communities and let’s solicit contributions and feedback to Listen and Opencore.

In short, let’s try to practice better open source. After all, we can only bring the open source ethos and philosophy to the broader world after we get it right in our software.