Freitag, 8. Februar 2013

Cannot drop a user that is currently connected

I hate this message. It constantly broke our CI builds. Here is why and how I fixed it.

The Basic Setup

We use Maven as our build system. In UI projects we start a Jetty server that hosts our application and run a bunch of frontend tests against it. Our application also needs an Oracle database so we setup and tear down this as well. The build phases go like this:

pre-integration-test: 
- create database user (== schema in Oracle)
- update database with the latest scripts
- jetty:start (daemon mode)

integration-test:
- failsafe plugin runs tests

post-integration-test:
- jetty:stop
- drop database user

The Problem

The problem comes with the post-integration-test phase. The jetty:stop command returns immediately while the server is busy shutting down. All the while our drop script tries to "Drop user @username cascade;" and fails with the error that gave this post its title. So our first reaction was to write our own little Jetty plugin that actually waits for a complete server shutdown. This worked, but it made builds unnecessarily slow.

The Solution

So I took another go at our drop script and changed it to this:


With this script in place we could now shut down Jetty and drop the Oracle user in parallel, making our builds that much faster. 

As a bonus I stumbled across another Oracle oddity: Our users have dedicated tablespaces (named "<username>_<tablespacename>"), so we drop them too. Since we already did a cascading drop of the user, we can be sure that those tablespaces are empty. You would think that Oracle recognizes this, but at least on 11gR2 you would be wrong. Calling "drop tablespace @tablespacename including contents" is much slower than "drop tablespace @tablespacename" even if the tablespace is empty. This spares us some more valuable seconds in each build.

Samstag, 2. Februar 2013

Languages matter (not!)

Comment from the future (2014/10/19):

It's fun coming back to this old post and seeing how I totally missed the point how a good language can help with exactly the things I was pointing out. I guess this post was due to me being in a desperate project where no amount of language improvements helped, since we just didn't have access to the domain experts. I hope this is not the case for most of you, so please disagree with this post just like I do today =)


Yesterday one of our student trainees held a passionate talk about how most design patterns disappear into the background in functional languages. He showed some pretty convincing code examples of Java vs. Haskell. The Java solutions were a verbose mess while Haskell was usually a readable one-liner. He concluded that functional idioms are the future, because they make software design easier and code shorter, more readable, testable or even provable.

I have great sympathy for functional languages myself. Taking a break from Java and doing some Clojure really changed the way I look at algorithmic and design problems. But algorithms and low-level system design are not the main challenges in software development. Introducing a bug into an algorithm is usually no big deal. Either a unit test catches it for you or you fix it with a quick maintenance release. Sure, avoiding bugs and writing less code leads to more productivity and reduced maintenance costs. But such bugs usually don't break your neck. That is unless you're building a space ship or working on Google's search algorithm.

The real crux in software engineering is domain modeling. Getting from a (usually very vague) business plan to a software model that is both understandable and implementable is a demanding task. If not done properly, projects will fail miserably. Misunderstood requirements can be prohibitively expensive to fix. Over- and underestimated technological capabilities are also a problem. They can make a model either too implementation-centric or physically unimplementable.

So what really matters? People and communication of course! Developers need direct access to domain experts so they can talk about new questions that emerge during design and implementation. They all need to speak the same ubiquitous language. Domain experts need information about technical possibilities so they don't just describe a modern copy of a legacy system. Users need quick prototypes, because requirements often emerge only after working with a real piece of software. Problems in production system must also be analyzed beyond the technical level. Maybe they are due to wrong specification and not a software bug per se.

Optimizing things like programming languages, frameworks, IDEs etc. will only give you a real boost after you have above feedback loop in place. Without it, you will just be more efficient at implementing the wrong stuff.

This leads me to an interesting question: Why do so many people make such a rave about new languages? Either they have already mastered communication with their domain experts and programming really is the last thing they can optimize or they are already overwhelmed with the relatively simple task of programming and don't even see the greater problems. I fear the latter is true in too many cases.