Ayende @ Rahien

It's a girl

After talking about the EntitySet so long...

I just run into a bug that happened because I used EntitySets.
I was relying that the order I'll get the items from the set will be identical to the order I inserted them.
It even pass a couple of tests when I wrote this, but it started to break today until I figured out what was wrong. A quick change to EntityList (which does have this guarantee) solved the problem. 

More Funny Code

How fast can you understand what is going on in here?

public int Calc()
{
  int @return = 0;
  return @return;
}

I'm consderring moving to this as a way to name my return variables.

DotNetRocks #169, Second Take: O/RM

I listened to the rest of the DotNetRocks episode 169 with Rocky Lhotka. This time, I wanted to comment about the part where Rocky talks about ORM. Before everything else, I would like to comment on something he said about Microsoft and O/RM.

He said that most O/RM are using Reflection, and that only Microsoft can solve this issue, because the can modify the CLR to allow direct access to private fields.

I wanted to note that there is already such a thing in .Net 2.0, and it is called LCG (Lightwieght Code Generation), and it basically means that you can inject a method into a class, which will have full access to all the class' members, regardless of visibility (just as any class on the object does). There is a patch for NHibernate that allows it to use this functionality in .Net 2.0, so you don't need to me Microsoft to use this.

I would also like to comment that NHibernte is already avoiding Reflection whenever possible, relying on runtime code generation to read and write to public properties / fields. 

I want to address another part of what he said, where he said that O/RM assumes that objects are structure the same way as the database is. Only the simplest O/RM assumes this. One of the important charactaristics of objects is not the data they contain, but what type of object you have, and what relations it has to other objects. A good O/RM will know to map the schema of a database to your object structure without impacting the design of the object.

In fact, I would go as far as to say that this is the criteria of good O/RM.

DotNetRocks #169 and TDD

I was listening yesterday to DotNetRocks episode 169 with Rocky Lhotka, and I was muttering "WTF??!!" throughout the first part of the show.

The issue that I had was Rocky talking about TDD and saying stuff that simply didn't match the reality, not by a long shot. Jeffery Palermo post about it as well, by the way.

Rocky's main objections seem to be:

When you are working Test First, you don't get intelli sense for classes and methods that don't exists, and that seem to hurt his development style.

First, what is the problem. You just created a class, why do you need intelli sense for something that you'll write in a few minutes? Yes, it is convient, but the rate of creating new methods / classes in my code is not high enough that I will forget that I created that class 3 minutes ago and need to think about the interfce I want to give it.

Second, good enough tools like the wonderful ReSharper or VS.Net 2005 (far less powerful) will gladly create classes and method for you on the fly when you refer to something that do not exist. This is not an issue.

Test First require that you will first write the test, and then write the code. Doesn't mesh well with programming by the wizards.

Considerring that most of the wizards have to do with UI in the first place, and considerring the big problems in testing UI, I would say that this is a non issue. If I think that I need something that doesn't work directly in the UI, I can't see how the wizards and the tools will help me any. I am aware that other people feels just the opposite.

That said, do you really think that you can trust the code that the wizard generates? Or are you going to run it through it paces a few times, just to make sure it works? If you intend to check it yourself, you need a test for this (or several). You will change this part of the code, and you need it covered. I would also argue that you get far better design and working experiance when working in TDD fashion that you do with all the wizards.

You write a bunch of tests, and then you've to write the code to make them work, which is hard.

You know what, he is right on this one, which is why you never write a bunch of tests and then try to implement them. You write one test, then you make it work, then you write another test, etc.

On a large system, it is hard to test one method at a time.

This is possible, and it indicate a design problem in the code, fix it. Check out "Working Effectively With Legacy Code" for the details. I can't imagine trying to change something in a large system without tests. How do I know that I didn't break anything?

If he is talking that it is hard to TDD a feature with small increments, than he is right, it takes some work. The end result is worth it since you got a decoupled design you know is working.

Ater writing a test, developers fear to refactor the system, since it will break the test.

I was literally ranting at this point, and this one is really over the top. If I have ever heard a falser statement... TDD is made up of three things: "Red, Green, Refactor". If you don't do all three, you are not doing TDD. What he calls refactoring is not that, it's random code movement through the code, with the prevent wishes of the developer that he isn't breaking anything. Thanks, but "Code and Pray" are not for me.

It's easy to write your own test harness in a couple of lines.

Yes, it is easy, but you are only running one test that you keep changing, you are not check other parts of the code, can't add it to the build process, etc. In essense, this "test harness" is merely a way to execute the code as it would be on the production system, so you could debug the problems. I would rather not debug at all, and get a nice warm blanket of tests telling me where I am doing wrong.

Appropriate Comments

Both Analtoly and Oren Ellenbogen  had commented on my commenting post (pun intended). The example we are using right now is this piece of code:

outputs = new EntitySet<IConnection>(
      delegate(IConnection connection) { Raise(OutputAdded, connection); },
      delegate(IConnection connection) { Raise(OutputRemoved, connection); }
      );

I argue that this piece of code should stand on its own, without any comments to explain what is going here. I think at least part of the issue here is that I am focusing entirely on the comments on the code and not XML Comments. Here is the code for the EntitySet, the class start with a big XML comment that start with general explanation on the class and then goes on to some detail with regard to some detailed implementation that has to do with NHibernate.

To quote the first part of the comments:

/// This class handle strong typing collections that you get from
/// NHibernate.
/// It also handles adding/removing items to the other end (by allowing
/// you to specify delegates to do it).

And the constructor that I'm calling about is defined as:

public EntitySet(Action<T> add, Action<T> remove)

Putting this two together, I'm comportable with not commenting what is going on in the output declaration. It should be obvious by reading the xml comment on EntitySet<T> and seeing the constructor overload I'm using.

With regard to commenting on a library code, Anatoly said:

When you call the library function, the comment what the function does should be in the header of the function. When you change implementation you change the comment. When you call the library function (even in several places) need to say what the line of code does (calling x expecting y) here it may be very light. But still need to comment.

If I need to comment on the callsite for a method, that is a sign for bad design on my code. The possible exceptions is I'm doing something non standard there (like expecting spesific result because the conditions are just right) and if I'm doing it more than once, I need to refactor to remove the comments.

The case above is a classic one, I think. If you don't understand what is going on there, you really don't understand what is going here. It's not a question of not understanding some side affects. In this case it's whatever you know what the library does or not.

Ayende: You seem to say that the code should be optimized for someone completely ignorant about the project, just seating down and understanding what is going on.

Anayoly: Something like this. My point is that clear and self-descriptive code is a must but it does not mean that you don't need comments.

This is the part I disagree with most strongly, I think. Clear code doesn't need call site comments. They are a chore to write when you write the code, they are noise when you read the code. On heavily commented code, my eyes gets into 'ads-skipping' mode, and I literally don't see them more than green blurs on the screen.

I tend to think that a big enough project require some rumping up time before you understand what is going on. Anatoly says that it is possible to have a new guy on a project and starting to contribute useful features in a very short times (minutes to hours).

I've seen accessible projects. You feel the difference right away.

Could you explain what made it accessible? Was it that you were familiar with the technology and the development methods that were used? Was it good documentation? How much time did you spend reading the comments in the code in order to learn what is going on there. I said in the comment that I believe that it is possible only on "common ground" projects, where the architecture is mostly the same.

Moving to Oren's comment about this now. The first suggestion that you had (refactor creating the outputs into a method that would have a comment there) is something that I would generally prefer to do if the code needed explaining. In this case, do you think that the comments on the class and the naming of the parameters are enough?

It seems to me (I'm guilty at this as well) that you fall in love with complex code but you forgot that someone else would have to maintain your code somewhere in the future.

Yes, and no. I sometimes does complex code for the fun of it, but I don't intend to take this code to production. There is some elegance for complex code that works. But if I look at it afterward and need more than a minute to understand what i did there, it's useless, in my eyes. This is part of the reason I like peer programming. You can't do stuff too complicated without sounding it out first, and then the other guy will likely offer a better / simpler way to do this.

I just had a case where i wrote a method that passed a test, but when I went back to the method and looked at it, I had no idea what was going there. I ended up breaking the method to several smaller methods, so I got something like:

AssertNoCycles();
List<Node> visited = new List<Node>();
foreach(Node node in graph.Nodes)
{
    DoWork(node, visited);
}
AssertAllNodeWereVisited(visited)

Imagine that each of those methods in inlined, and you'll start to see the problem, I guess. My first instinct is to break the code to manageble pieces rather than explain what I did there.

I liked Oren's second suggestion, which is to have a certral repository of "Required Reading" before you can work on the project. I'm not talking about 1,600 design guides. I'm talking about much simpler stuff like:

This project uses the following libraries, and here are the documentation. You probably need to check the following three links to get up to speed with what they do, and we are using them to do this and that (links to everything).

This allows you to assume a common base for the people that would work on the project.

Tags:

Published at

Election Day

I thought that I would do the world a service and inform them who I'm going to be voting for:

 

 

Overall, I find that they gave this company has the highest standards and the most consistent plans for the future. I also liked the fact that they bribed me to vote for them and that their campaign remained aloof from childish attacks on the competitors.

Published at

More on comments and code

Anatoly Lubarsky has commented on my previous post about commenting:

Sorry for this but you are totally wrong.
I don't want to search or read documentation or debug to understand your code.
It is totally useless work until you write for yourself only.

I also don't like this code and don't think it is descriptive.

I started to reply, but it turned to be pretty long and pretty important, so I'm posting it here.

Codebases do not exist in isolation. Explaining what is happening in the code because it's not doing the common thing get repetitive and annoying very quickly. To take few examples:

EntitySet<T> and its associated actions are not simple to grasp, but the moment you grasp them, there isn't any point to comments, it is just as useless as the "disable the button" one. Take a look at the code here. This is not commented, and is not likely to be. The moment you understand that EntitySet will call the delegate methods on add and removal, it should be clear what is going here. In this case, the collection will raise events in the parent class with very little coding on our part. Could this use a comment for somebody other than me?

Well, this did deserve its own post when I did it, so I guess that this means that I admit that it is not something trivial (not that I don't post about trivialities), but the other approach means that the code will look like:

// This will raise the OutputAdded event when a connection is added to the outputs
// and OutputRemoved event when a connection is removed from the outputs.
outputs = new EntitySet<IConnection>(
      delegate(IConnection connection) { Raise(OutputAdded, connection); },
      delegate(IConnection connection) { Raise(OutputRemoved, connection); }
      );


// This will raise the InputAdded event when a connection is added to the outputs
// and InputRemoved event when a connection is removed from the inputs.
inputs = new EntitySet<IConnection>(
      delegate(IConnection connection) { Raise(InputAdded, connection); },
      delegate(IConnection connection) { Raise(InputRemoved, connection); }
      );

Take a look at this code, it explains what is going on here, but is it useful to you? The first time, maybe. But the second time? And the third? And the 100th? This code has a comment bug in it, by the way. Can you find it?

Here is another example, this time it is from NHibernate Query Analyzer and it has to do with executing a database query in a background thread. This is complex stuff, I am sure that you would agree:

ICommand execQuery = new ExecuteQueryCommand(view, mainPresenter.CurrentProject, view.HqlQueryText, typedParameters);
mainPresenter.EnqueueCommand(execQuery);

Here is the commented version of this code:

// This command will be executed in a background thread. ExecuteQuery will take care of syncronizing the updates to UI and notifing it 
// it when it was done or it failed.
ICommand execQuery = new ExecuteQueryCommand(view,  mainPresenter.CurrentProject, view.HqlQueryText, typedParameters)

// Enqueues the command on the main presenter work items queue, which will be picked by the background thread 
// as soon as it is done with other stuff. This allows to keep a responsive UI in the face of long-running queries.
mainPresenter.EnqueueCommand(execQuery);                  

Now it also explain what is happening, and you know that the ExecuteQuery class will take care of handling returning the query to the UI. But I'm using code similar to this one for all my multi-threaded communication, do I really need to give basicaly the same comment over and over again? Do I need to do it just once? What if the other guy that is maintaning the code is looking at another location where I did this, but not where I left the comment?

Here is another example. Here Blog is an Active Record class with a lazy loading for Posts:

Blog blog;
using(new SessionScope())
{
   blog = Blog.Find(id);
}
foreach(Post p in blog.Posts)
{
   // do something
}

This is wrong. It will throw an exception when you try to access the Posts collection, but unless you are familiar with the way Active Record works (or you already go this exception), it will make not sense. Do I need to put the foreach inside the using and explain why? What about all the dozens of other places where I access lazy loaded collections (something that is certainly not obvious)?

Like I said, I don't believe that comments should be used to communicate the common stuff (even if it is not obvious). If you try to work with any code base of meaningful size, you either has to avoid doing anything of any complexity (which mean a lot of repetitiveness) or you are going to develop common idions (for this spesific codebase) for dealing with it. Not reading the documentation {best scenario} (or talking to other team members, or reading the tests and sweaping the code) when you are new to a project makes absolutely no sense unless you are confident that you can manage as you go along.

A project has common idioms for dealing with problems. In the context of the project, explaining what they do amounts to commenting "adding 1 to x" when you use: x++. When I work, I assume that the other people working on the project are familiar with the same idioms. Yes, it make it harder to understand the code in the start, but show me one significant project when someone can just come in, have a few minutes to look at the code and can start real work on it.

Tags:

Published at

Ideal XP environment

Continuing on the TDD list, this message from Robert Hanson has the best description of the goals of XP that I've ever read.

In an excellent programming environment there is no fear.

  • The customer has told us exactly what he values most. I have no fear that I might be working on something he does not want.
  • The code I'm working on is test driven. I have no fear (or at least, very little fear) that the code might do something I don't want it to do.
  • All other code has unit tests; and I have continuous integration in place. I have no fear that my code will break something without me knowing it; and I have every confidence that if it does break, I can quickly find the problem and fix it, and verify that the fix works and does not break anything else.
  • I have source code control in place; if a change is really catastrophic, I just go back to yesterday's version and start over.
  • I have short iterations, so that I have no fear that if priorities or business needs change, I can adapt to the new requirements without fear.
  • I have a pair, which I change every few hours or at the start of each day. I don't worry that some key piece of knowledge is known by just one person.

And boy, do I wish I actually worked at a place like this.

I wish I worked there too. Check out the replies, they contain some great discussion.

On Comments And Code

There is an interesting discussion about commenting code in the TDD mailing list. I think that we can agree that this comment is uselss:

//Disable the button
btnAdd.Enabled = false;

I don't like commenting in general, and I've been told that it makes my code harder to read and understand. In general I really hate to explain what is happening, even if the code itself is fairly complicated. To take an example, Rhino Mocks has some fairly complex code in it to handle nested method orderring. This is a piece that was very hard to get right (both from design perspective and from coding perspective). It has a single comment explaining the implication of the else case of an if statement.

In all of Rhino Mocks, there are 8 files (out of 56) that contains non (XML / documentation) comments. The comments I have are stuff like:

//I don't bother to check for RepeatableOption.Never because
//this is handled the method recorder
if (repeatableOption == RepeatableOption.Any)

(Where RepeatableOption is an enum with several states, out of which I'm checking only one.)

This one was tricky, though:

//because the expectation doesn't exist, an exception will be thrown
return repository.Replayer.GetRecordedExpectation(proxy, method, args);

Took me a moment to understand what was going there (I'm passing it to the replayer so it would format the appropriate exception message, instead of handling this myself) and it would need debugging to understand why this is needed.

One last one (this is in the part of the code that adds special handling for methods):

//Just to get an error if I make a mistake and try to add a normal
//method to the speical repeat method
Debug.Assert(expectation.RepeatableOption != RepeatableOption.Normal);

The rest of the comments are more in the same style, they are intent revealing and they are far and few between. I was actually surprised to find that I needed the comment to understand what was going on.

Those comments (and the overall thinking behind them) are not meant to explain what the code does, or even how / why it does it. They were written with the explicit assumstion that if you read them you know what you are doing in the codebase. They are there to explain implementation decisions, not how things work. If you need to know, it's not hard to figure out in most cases, since I try to use decriptive class and method names.

I would say that I take the same approach elsewhere in my code. Take the example I posted earlier today:

outputs = new EntitySet<IConnection>(
      delegate(IConnection connection) { Raise(OutputAdded, connection); },
      delegate(IConnection connection) { Raise(OutputRemoved, connection); }
      );

This code is using EntitySet<T> from NHibernate.Generics and anonymous delegates to raise event notifications in the class that create the outputs field. You can't understand what this code does unless you are aware of the things that EntitySet will do for you, or if you don't understand what anonymous delegates are.

But this code doesn't warrant a comment explaining its use, in my opinion. If you need to understand what anonymous delegates are, get a C# 2.0 book. If you need to know what is so special in EntitySet you can check the documentation (assuming you know to search for those :-)).

  The difference in my opinion is that the purpose of comments is to explain the uniqueness of a situation, nor how the code works, even if the code is complex / unusal.

Tags:

Published at

XForms

Kurt explains XForms. Check out the examples he gives. This is the first time that I had a look at this, but this is just flat out facinating. Talk about a way to do clean MVC on the web.

I really wish that I could use this to write web applications today (not feasable unless you would like to build site like this cool one).

On Starting a Project and Design Bugs

The part that I hate the most about a project of a type that I never done before is the start. The issue is that I produce a design that mostly works, but when new stuff need to be implemented, I often need to explore several approaches before I know what will work for this project, my last post in an example of the approaches I thought about for persisting object graphs.

The thing that really bothers me is that changing those approaches can lead to major changes in the code. This means that there are extended periods of time that I can't even build the code successfully (30 minutes to an hour, at times). This makes me very nervous, but I don't see how I can avoid doing this as I study the various ways to implement this functionality. In this case, the changes involved changing an interface that was common to many classes in the project, so that caused quite a bit of pain until I settle on the correct approach.

I was at the Israel User Group meeting today and talked with Justin who termed this as a "Design Bug". I like this term. The only encouraging part is that after the initial pain I get a stable base to work from. The bad part is that the changes are big enough that I can't really test drive them beyond very big tests (save the object graph and then load it, for example). Those type of tests are more integration oriented than developer oriented. They help me define the big goal, but not how I get there.

I guess that this is why XP has Spiking for unknown functionality. I'm pretty sure that I'm commiting horrendous crime for doing this with code that will go to production, but in this case, I don't have much implemented yet (only some interesting graph output functionality), so I feel that it is safe to do this.

One thing that I noticed happening is that I lose abstraction along the way. For instnace, when I tried XML Serialization, it couldn't handle interfaces, so I changed several interfaces to abstract classes. When I realized that XML Serialization would probably not work, I revert the changes. For now, I'm seeing this as removing premature abstraction on my part, and if I need this functionality later, it wouldn't be a problem.

Tags:

Published at

Saving object graphs to file: CodeGen and Executable Graphs

I need to save and load an object graph to a file.  A pretty routine task, but this time I thought I would dedicate a little thought to this. I need to support a flexible structure that allows saving objects that I don’t know about right now. I’m mostly free to develop the persistence layer any way I want it. My first thought was to try to use Active Record to persist it all to a SQLite database. But I need to support objects with inheritance that I don’t know about in advance. I suppose that I can solve this issue with Table Per Class approach, but I want to reserve this approach for later, mainly because this would mean generating the schema dynamically. I thought that XML Serialization would be easiest, but I run into problems with generics and serializations of interfaces, which I tend to use heavily.

Another issue that I run into is object identity. Here is the simplest example:

Before Serialization:

After Serialization (bad – disconnect in the graph):

  

U0 and U2 points to the same instance of U1

U0 and U2 points to different instances of U1

I couldn’t find a way to persist the first graph and get it back without doing some work that I would rather avoid. I have done some XML Serialization in the past, but I never done anything that cared about object identity. Using Active Record would solve this problem, but this brings me to the dynamic schema problem that I want to avoid if I can.

 

Right now I’m thinking about saving it in an executable format. The idea is to generate (using Code DOM) the actions that are needed to create the graph on save, and on load to compile and run the code to get the live object graph. For instance, take this graph:

 

 

This can be saved as this code:

 

Node u0 = new Node(),  u1 = new Node(), 2 = new Node();
u0.To(u1);
u0.To(u2);
u2.To(u1);
u1.To(u0);

 

There is code generation in this project anyway, so I’m not introducing something completely foreign. This is an intriguing concept for me, since it means that saving the file is quite complex, but the richness of the file format is unparallel.

Published at

With Notification: Collection

I needed to create a class with a collectiont that would raise events when items where added or removed to it. It was the work of a few minutes to add the events and then write this code:

outputs = new EntitySet<IConnection>(

      delegate(IConnection connection) { Raise(OutputAdded, connection); },

      delegate(IConnection connection) { Raise(OutputRemoved, connection); }

      );

Where Raise() looks like this:

private void Raise(EventHandler<ConnectionEventArgs> eventToRaise, IConnection connection)

{

      ConnectionEventArgs args = new ConnectionEventArgs(connection);

      if (eventToRaise != null)

            eventToRaise(this, args);

}

It starting too look like O/RM and frieds are the first tools that I pool out of the toolbox.

 

Published at

Working with VS.Net 2003

I had to do a two minutes task in Visual Studio 2003 today, and it took me exactly three seconds to run into something that doesn't exist in 2003 that I've grown to like in 2005. I thought that I didn't like VS.Net 2005, but it's a great deal (better | slower) than VS.Net 2003. I also got ReSharper to work semi reliably on VS 2005, so that makes all the difference in the world in the amount of satisfaction that I get from work.

I had ReSharper generate a full blown class from an interface in a couple of seconds, including properties and simple constructor that would take many minutes to do without it. I showed it to a friend, and then did a couple more times, for the sheer pleasure of it. That is how it should be.

Hilarious VS.Net Ads

I just found this site, and it's simply killing me.

I watched all the videos, and they are great. Check out #346 (flash, so no link). I nearly ruin the keyboard and a whole lot more because of this.

Tags:

Published at

Boo Reference

It seems like this is a wiki-is-a-page about Boo. It looks promising, so check it out if you want to learn Boo.

I made a quick scan through it, and it looks like very good info.

Tags:

Published at

Another Point Against GUI

I posted about why doing GUI is hard. Now I can add another thing, there are way too many details that you have to get just right for it to work.

It looks like I spent all day today just trying to draw several points on the screen, and handling all the 103 ways that the user can interact with it. Add to that a custom (not inheriting from Control) control that contains real controls and it’s a mess of calls that has to come in the exact order for it to work. It was fun finding out the order, too.

A tedious day and all I got is a couple of points of the screen. Sigh. Now I need to make it talk to the back end…

Published at

Thread Safe Stop Watch

Joe Duffy posted about using the stop watch class from the 2.0 framework.

I liked his implementation of weak hash table, that I going to come handy later.

Tags:

Published at

1.5 BILLION Page Views A Day

ScottGu got some interesting statistics about ASP.Net 2.0:

  • MySpace.com is now processing 1.5 Billion page views per day
  • MySpace.com handles 2.3 million concurrent users during the day
  • MySpace.com’s average server CPU utilization went from 85% to 27% after moving (from another technology) to ASP.NET 2.0

Those are some awesome numbers. Suddenly I feel much better about my technology choice :-)

Oh, and to finish it:

4 of the top 6 sites [most visited sites] (MySpace, MSN, Ebay and Hotmail) run on IIS and Windows. J

It is all text, and it's meaningless

I'm pretty interested in compilers and text analysis, so I spent several hours today trying to grok ANTLR. I can work my way through some of the samples, and even figure out what the stuff is doing, but I can't seem to make stuff work when I try to go forward on my own.

I want to be able to get an AST from ANTLR for the following text:

from Foo select Foo.Bar

And I want the AST to look like this:

  • from:
    • Name: 'Foo'
  • select:
    • Reference:
      • Left: 'Foo'
      • Right: 'Bar'

I can get a lexer to work, and I think I got the parser as well. My problem is that I can't seem to step forward from there to get it working with trees and more reasonable information. There is a wealth of information, but I think that I'm missing the background to understand it :-(

Tags:

Published at

NHibernate Query Analyzer 1.1.3 Release

Don't ask about the version number, it just is. I haven't done an all-nighter in quite a while, and while it was fun to do, I'm not thinking very clearly right now. Here is the details about this release:

I finally got around to take a good hard look into NHibernate Query Analyzer (AKA: NQA). I haven't update it in a while, and that is a shame. There was an issue with query translations when using parameters that kept me from going forward for a long time. Today I bit the bullet and trace it through all the twists and turns along the way and found the problem.

Along the way I also solved the Nullables issue that I've not been able to fix since forever. I run into some very strange differences between 1.1 and 2.0 along the way. Up until now, I mostly developed NQA on 1.1, but now I did all the work in 2.0 and the issues highly annoying (see randon GC failure).

The new stuff is:

  • Working against NHibernate 1.0.2 (the latest and greatest).
  • Supports 2.0 and 1.1
  • Supports Nullables

The fun part is that I did all of that without opening the UI once. I'm pretty confident in my tests to be able to do this without stuff breaking. I'm too tired now to think, but in the background there is a gong that warns against temping Merphie, but what the hell.

You can get it here