Ayende @ Rahien

Refunds available at head office

Hibernating Rhinos: The Movie

Well, it is finally here, it has been ten years since I started blogging. My first blog was on April’s 1st 2004, and somehow, we are a decade later.

Usually it is time for introspective, and careful thought about what was and what will be, but I’m having no time for that. Instead, I wanted to let you know that we just finished signing with Lucas Film (well, it said Disney on the contract, but I’m a geek, so I’ll go with the more impressive title) for a movie about Hibernating Rhinos. The idea is basically similar to the Social Network, but much better.

I’m trying to see if I can get Jesse Eisenberg to play there.

And I got a budget for 999 ravens to be released in a flock at one of the scenes!

We’ll show a trailer for the movie (purely computer generated, so far) at our Conference in a week.

Tags:

Published at

Originally posted at

Comments (7)

Answering customer questions

This made me laugh:

image

And yes, I am aware that laughing at my own action is… strange.

Tags:

Published at

Originally posted at

Comments (7)

Multi Threading Insanity

Insanity: doing the same thing over and over again and expecting different results.
Albert Einstein

You obviously never done any multi threading work, dude!

Tags:

Published at

Originally posted at

Comments (10)

The seven deadly sins for the developer (* some restrictions apply)

Originally posted at 3/30/2011
I have seen all of those in production code…
  1. throw new NullReferenceException();
  2. public class AbstractController : Controller
    // or 
    // public class AbstractPag : Page
    {
        public static bool IsAdmin { get;set; }
    }
  3. public static class BlogMgr
    {
        public static void AddPostToBlog(Blog blog, Post post)
        {
                blog.Posts.Add(post);
                post.Blog = blog;
        }
    }

* I could only think of three, but I didn’t want to modify the title. Can you complete the list?

Tags:

Published at

Originally posted at

Comments (65)

Code review ranking methods

Originally posted at 3/8/2011

I use a sort of a ranking sheet when I am doing code reviews. I recently run into one that was really horrible…

image

Tags:

Published at

Originally posted at

Comments (6)

It really happened, legacy programmers tales

Fairy tales always start with “Once upon a time”, and programmers tales starts with “when I was at a client”…

Two days ago I was a client, and the discussion turned to bad code bases, as it often does. One story that I had hard time understanding was the Super If.

Basically, it looked like this:

image

I had a hard time accepting that someone could write an if condition that long. I kept assuming that they meant that the if statements were 50 lines long, but that wasn’t the case.

And then yesterday I had an even more horrifying story. A WCF service making a call to the database always timed out on the first request, but worked afterward. What would be your first suspicion? Mine was that it took time to establish the database connection, and that after the first call the connection resided in the connection pool.

They laughed at my naivety, for it wasn’t connecting to the database that caused the timeout, it was JITting the method that the WCF service ended up calling.

Yep, you got that right, JITting a single method (because the runtime only JIT a single method at a time). I had even harder time believing that, until they explained to me how that method was built:

image

Some interesting stats:

  • It had a Cyclomatic Complexity of either 4,000 or 8,000, the client couldn’t remember.
  • The entire Rhino Mocks codebase fits in 13,000 LOC, so this single method could contain it several times over.

But you know what the really scary part is?

I upgraded from Super If to Black Hole Methods, and I am afraid to see what happen today, because if I get something that top the Black Hole Method, I may have to hand back my keyboard and go raise olives.

NHibernate – Get Thou Out Of My Database – 2nd Edition

Following up on my previous post, the customer has complained about table names like [tbl_-1434067361], apparently they felt that this was misusing their naming policy. I told them that while I understood that, it did meet their naming policy. I got a new naming policy that stated that numbers are not allowed in column or table name, (and showing forethought) that table names must be composed of valid English words.

I, of course, decided that if this is what they wanted, they will get just that. And created this:

image

The words.txt file was taken from this URL: http://www.puzzlers.org/pub/wordlists/pocket.txt

The result is exactly per their specification:

create table [tbl_colonel] (
  [col_verbiage] INT IDENTITY NOT NULL,
   [col_unsparing] NVARCHAR(255) null,
   [col_indomitable] NVARCHAR(255) null,
   [col_bulldog] BIT null,
   [col_thank] DATETIME null,
   primary key ([col_verbiage])
)
create table [tbl_stump] (
  [col_upheaval] INT IDENTITY NOT NULL,
   [col_promissory] NVARCHAR(255) null,
   [col_predecessor] NVARCHAR(255) null,
   [col_chafer] NVARCHAR(255) null,
   [col_unyoke] INT null,
   [col_vise] NVARCHAR(255) null,
   PostId INT null,
   primary key ([col_upheaval])
)

create table [tbl_reprieve] (
  [col_wherewith] INT IDENTITY NOT NULL,
   [col_wolf] VARBINARY(8000) null,
   [col_legendary] NVARCHAR(255) null,
   [col_ago] NVARCHAR(255) null,
   [col_carabineer] DATETIME null,
   [col_referee] NVARCHAR(255) null,
   primary key ([col_wherewith])
)

The fun part about this approach is that you still get great level of security, while maintaining the naming convention. Even more than that, you get queries like:

SELECT col_verbiage, col_indomitable, col_bulldog, col_wolf, col_legendary, col_referee
FROM tbl_colonel JOIN tbl_repreieve ON tbl_repreieve.tbl_referee = tbl_colonel.col.unsparing
WHERE col_ago = 'Fun@house.at'

It is obvious that we are getting users & blogs with specific email, right?

This is actually much harder than just numeric values, because this is going to really mess with your mind.

Nitpicker corner: Yes, this is a humorous post, don’t take it seriously, and please don’t really do it to unsuspecting customers / DBAs. Unleash it on silly integration teams only.

Random Developer Quotes

Those are just things that I happened to hear or say in the last week:

Q: Did you read the book Beautiful Architecture?

A: No, I don’t read fantasy books.

And:

Q: Why are you doing the dishes?

A: I was a C++ programmer for a long time, I am used to cleaning up after myself.

Post #4000

Dear ALT.NET Community,

You are likely familiar with that classic Warren Zevon song, Werewolves of London. I was reminded of this the last night being in London under a full moon and in the same hotel as one of the more famous Lycanthropic developers in the .NET community, Ayende Rahien, with whom you are also likely familiar as, well, you are reading his feed. Duh.

Shocked? Read on...

To call Ayende a werewolf is inacurate, of course. A lycanthrope, yes: Half-man, half-animal (i.e. manimal). But his primal half does not take the form of the lupine. Rather, Ayende is a were-Rhino. This should be obvious given the various logos and trade names he chooses. There you have it! His shape-shifting nature explains his Rhino fetish along with the genesis of the names of such projects RhinoMocks, RhinoCommons, Hibernating Rhinos, etc.

Yes we're all familiar with the conventional wisdom detailed in the classic essay of the same name by Fred Brooks, "No Silver Bullets." In this corner case of our industry there is a silver bullet, a couple (luckily, friends)!

There are a few things you can do to protect yourself from this marauding monster, Mr. Rahien. When in his manimilian state, if you ask him a question about NHibernate, you will stop the abomination in his tracks. If, being a proper member of the ALT.NET tribe, you cannot think of an NHibernate question (as you are undoubtedly an expert at this point) engage the brute in a discussion regarding the popular science fiction book series, "The Wheel of Time." That should do.

IMPORTANT: a curious, oft-overlooked but quite dangerous feature of the wererhino is that the beastly transformation can be triggered when the subject views a piece of code built on the Entity Framework. Be very, very careful when working with EF code around Ayende.

You have been warned.

Yours truly,

Dave Laribee

1st April Post – The multi purpose method

Since it appears to be customary, I decided that I need to make a few posts for April 1st. Here is the second of them.

public void RemoveReversalsMoveCompletedMessagesAndFinishSubQueueMove(Guid transactionId)
{
    Api.JetSetCurrentIndex(session, txs, "by_tx_id");
    Api.MakeKey(session, txs, transactionId.ToByteArray(), MakeKeyGrbit.NewKey);

    if (Api.TrySeek(session, txs, SeekGrbit.SeekEQ) == false)
        return;
    Api.MakeKey(session, txs, transactionId.ToByteArray(), MakeKeyGrbit.NewKey);
    Api.JetSetIndexRange(session, txs, SetIndexRangeGrbit.RangeInclusive | SetIndexRangeGrbit.RangeUpperLimit);
    
    do
    {
        var queue = Api.RetrieveColumnAsString(session, txs, txsColumns["queue"], Encoding.Unicode);
        var bookmarkData = Api.RetrieveColumn(session, txs, txsColumns["bookmark_data"]);
        var bookmarkSize = Api.RetrieveColumnAsInt32(session, txs, txsColumns["bookmark_size"]).Value;

        var actions = GetQueue(queue);

        var bookmark = new MessageBookmark
        {
            Bookmark = bookmarkData,
            QueueName = queue,
            Size = bookmarkSize
        };

        if (actions.GetMessageStatus(bookmark) == MessageStatus.Processing)
            actions.MoveToHistory(bookmark);
        else
            actions.SetMessageStatus(bookmark, MessageStatus.ReadyToDeliver);

        Api.JetDelete(session, txs);
    } while (Api.TryMoveNext(session, txs));
}

And yes, it is from real code, and it is going to production soon.

1st April Post – Sending Data

Since it appears to be customary, I decided that I need to make a few posts for April 1st. Here is the first of them.

private IEnumerator<int> SendInternal(AsyncEnumerator ae)
{
    try
    {
        using (var client = new TcpClient())
        {
            try
            {
                client.BeginConnect(Destination.Host, Destination.Port,
                                    ae.End(),
                                    null);
            }
            catch (Exception exception)
            {
                logger.WarnFormat("Failed to connect to {0} because {1}", Destination, exception);
                Failure(exception);
                yield break;
            }

            yield return 1;

            try
            {
                client.EndConnect(ae.DequeueAsyncResult());
            }
            catch (Exception exception)
            {
                logger.WarnFormat("Failed to connect to {0} because {1}", Destination, exception);
                Failure(exception);
                yield break;
            }

            logger.DebugFormat("Successfully connected to {0}", Destination);

            using (var stream = client.GetStream())
            {
                var buffer = Messages.Serialize();

                var bufferLenInBytes = BitConverter.GetBytes(buffer.Length);

                logger.DebugFormat("Writing length of {0} bytes to {1}", buffer.Length, Destination);

                try
                {
                    stream.BeginWrite(bufferLenInBytes, 0, bufferLenInBytes.Length, ae.End(), null);
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }
            
                yield return 1;

                try
                {
                    stream.EndWrite(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                logger.DebugFormat("Writing {0} bytes to {1}", buffer.Length, Destination);

                try
                {
                    stream.BeginWrite(buffer, 0, buffer.Length, ae.End(), null);
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                    exception);
                    Failure(exception);
                    yield break;
                }
            
                yield return 1;

                try
                {
                    stream.EndWrite(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                logger.DebugFormat("Successfully wrote to {0}", Destination);

                var recieveBuffer = new byte[ProtocolConstants.RecievedBuffer.Length];
                var readConfirmationEnumerator = new AsyncEnumerator();

                try
                {
                    readConfirmationEnumerator.BeginExecute(
                        StreamUtil.ReadBytes(recieveBuffer, stream, readConfirmationEnumerator, "recieve confirmation"), ae.End());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not read confirmation from {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                yield return 1;

                try
                {
                    readConfirmationEnumerator.EndExecute(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not read confirmation from {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                var recieveRespone = Encoding.Unicode.GetString(recieveBuffer);
                if (recieveRespone == ProtocolConstants.QueueDoesNotExists)
                {
                    logger.WarnFormat(
                        "Response from reciever {0} is that queue does not exists",
                        Destination);
                    Failure(new QueueDoesNotExistsException());
                    yield break;
                }
                else if(recieveRespone!=ProtocolConstants.Recieved)
                {
                    logger.WarnFormat(
                        "Response from reciever {0} is not the expected one, unexpected response was: {1}",
                        Destination, recieveRespone);
                    Failure(null);
                    yield break;
                }

                try
                {
                    stream.BeginWrite(ProtocolConstants.AcknowledgedBuffer, 0,
                                      ProtocolConstants.AcknowledgedBuffer.Length, ae.End(), null);
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Failed to write acknowledgement to reciever {0} because {1}",
                                      Destination, exception);
                    Failure(exception);
                    yield break;
                }

                yield return 1;

                try
                {
                    stream.EndWrite(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Failed to write acknowledgement to reciever {0} because {1}",
                                      Destination, exception);
                    Failure(exception);
                    yield break;
                }
                Success();

                buffer = new byte[ProtocolConstants.RevertBuffer.Length];
                var readRevertMessage = new AsyncEnumerator(ae.ToString());
                readRevertMessage.BeginExecute(
                    StreamUtil.ReadBytes(buffer, stream, readRevertMessage, "revert"), ae.End());
                yield return 1;
                try
                {
                    readRevertMessage.EndExecute(ae.DequeueAsyncResult());
                    var revert = Encoding.Unicode.GetString(buffer);
                    if (revert == ProtocolConstants.Revert)
                    {
                        Failure(null);
                    }
                }
                catch (Exception)
                {
                    // expected, there is nothing to do here, the
                    // reciever didn't report anything for us
                }

            }
        }
    }
    finally
    {
        var completed = SendCompleted;
        if (completed != null)
            completed();
    }
}

And yes, it is from real code, and it is going to production soon.

Raising the level of abstraction

Right now I am working with a co-worker, and I realized that I am:

  • Using Mac OS
  • Running Windows in VMWare Fusion
  • To connect via SharedView to a remote machine
  • To connect via remote desktop to another machine
  • Which is also a virtual instance

And I wonder about the latency…

Laughing in code

I am not sure that this will make any sort of sense world wide, but Israeli coders should have a chuckle or two over this:

image

There is no database

I just noticed that for the last few months I have been consistently denying the existence of a database. I use the term persistent storage when asked, and when asked I usually say: “There is no database”.

It has gotten to the point that this is how I draw the DB on most whiteboard sessions:

image

Who wrote this code?!

  1. A drunken monkey, using his left feet
  2. Honest, it was the cat
  3. Offshore team of developer using the latest chisel technology
  4. It was lovingly crafted by a monk in a mountain on the Himalaya and submitted on six hundred A4 pages, the calligraphy was impressive
  5. Me

Joking in Code

People has started to use the comments of the previous post for putting programming jokes. Let us make this formal. I want to see code that is funny, or jokes in code.

The condition is that it has to be production worthy code. No perl poetry or things that you can do with the language just because you can.