Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by email or phone:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 6,515 | Comments: 47,933

filter by tags archive

Code review challengeThe concurrent dictionary refactoring–answer

time to read 4 min | 612 words

Here is the full method that we refactored:

 public void ReturnMemory(byte* pointer)
 {
     var memoryDataForPointer = GetMemoryDataForPointer(pointer);

     _freeSegments.AddOrUpdate(memoryDataForPointer.SizeInBytes, x =>
     {
         var newQueue = new ConcurrentStack<AllocatedMemoryData>();
         newQueue.Push(memoryDataForPointer);
         return newQueue;
     }, (x, queue) =>
     {
         queue.Push(memoryDataForPointer);
         return queue;
     });
 }

And here is the allocation map for this method:

public unsafe void ReturnMemory(byte* pointer)
{
    <>c__DisplayClass9_0 CS$<>8__locals0 = new <>c__DisplayClass9_0();
    CS$<>8__locals0.memoryDataForPointer = this.GetMemoryDataForPointer(pointer);
    this._freeSegments.AddOrUpdate(CS$<>8__locals0.memoryDataForPointer.SizeInBytes, 
new Func<int, ConcurrentStack<AllocatedMemoryData>>(CS$<>8__locals0.<ReturnMemory>b__0),
new Func<int, ConcurrentStack<AllocatedMemoryData>, ConcurrentStack<AllocatedMemoryData>>(CS$<>8__locals0.<ReturnMemory>b__1)); }

As you can see, we are actually allocating three objects here. One is the captured variables class generated by the compiler (<>c__DisplayClass9_0) and two delegate instances. We do this regardless of if we need to add or update.

The refactored code looks like this:

 public void ReturnMemory(byte* pointer)
 {
     var memoryDataForPointer = GetMemoryDataForPointer(pointer);

     var q = _freeSegments.GetOrAdd(memoryDataForPointer.SizeInBytes, size => new ConcurrentStack<AllocatedMemoryData>());
     q.Push(memoryDataForPointer);

 }

And what actually gets called is:

public unsafe void ReturnMemory(byte* pointer)
{
    Interlocked.Increment(ref this._returnMemoryCalls);
    AllocatedMemoryData memoryDataForPointer = this.GetMemoryDataForPointer(pointer);
    if(<>c.<>9__9_0 == null)
    {
        <>c.<>9__9_0 = new Func<int, ConcurrentStack<AllocatedMemoryData>>(this.<ReturnMemory>b__9_0);
    }
    this._freeSegments.GetOrAdd(memoryDataForPointer.SizeInBytes, <>c.<>9__9_0).Push(memoryDataForPointer);
}

The field (<>c.<>9__9_0) is actually a static field, so it is only allocated once. Now we have a zero allocation method.

Code review challengeThe concurrent dictionary refactoring

time to read 2 min | 216 words

In a recent code review, I had modified the following code:

_freeSegments.AddOrUpdate(memoryDataForPointer.SizeInBytes, x =>
{
   var newQueue = new ConcurrentQueue<AllocatedMemoryData>();
   newQueue.Enqueue(memoryDataForPointer);
   return newQueue;
}, (x, queue) =>
{
   queue.Enqueue(memoryDataForPointer);
   return queue;
});

Into this code:

var q = _freeSegments.GetOrAdd(memoryDataForPointer.SizeInBytes, 
                         size => new ConcurrentQueue<AllocatedMemoryData>());
q.Enqueue(memoryDataForPointer);

Can you tell me why?

Stories from the interview room: Should your code be doing THAT?

time to read 2 min | 246 words

We require all candidates to do a coding test before we invite them to an interview.

The purpose of the coding test is to get some idea about the way the person thinks, and to see what they can do. Often, we don’t really care about the actual solution that was sent, because the point isn’t to solve the problem in the “best” way. The “best” way is highly dependent on many factors (are we trying to optimize for readability, speed, memory consumption, for example)?

But what I find most interesting is when we confront a candidate with their own code. Typically we have certain remarks, because even if the code is great, we can change whatever it is that we are trying to get (this is highly readable code, but we care about perf here, what would you do if we wanted…).

A really fun exercise is to invalidate a certain assumption, and see how the candidate handle that. This is typically done on:

You called int Read(byte[] buffer, int start, int count) and you assumed that it will fill the entire buffer, but it will give you only as much as it has available right now. Your code needs to handle that. What needs to be changed?

Seeing a candidate interacts with code is much more enlightening, especially  because this is code that the candidate wrote, so they are familiar with it.

What I wish they would teach in universities

time to read 3 min | 455 words

A few weeks ago I gave a talk about what makes a good developer. And more to the point, what doesn’t. We are in a hiring sprint now, so we spend a lot of time thinking about this. Primarily, I’m concerned with having passionate people who love what they are doing. But that isn’t the topic of today’s post.

We get a lot of CVs from people who went to good schools, had excellent grades, and can’t actually write real world code worth a damn. Actually, I look at the previous statement and I really don’t like it. “Writing real world code” implies that writing the code is the most important aspect of the work, and it isn’t.

Real world projects is about a lot more than just the code. What about using a source control system. And not just knowing that there is such a thing that is better than this:

image

I’m talking about actually using a source control system to manage code, to review past work, to see the flow of changes, etc.

What about knowing how to debug? I’m talking about a bit more than F5 and F10. I’m talking about practical things like being able to debug a big system and understand how to work the debugger to give you what you want. Knowing how to look at the stack trace, or understand the difference between an exception that is thrown (and handled) and an unhandled exception.

What about actually solving real world problems? Like a project that has a double assembly reference because of a bad merge, and you need to be able to track it down and fix it.

What about actually reading code? Given a non trivial amount of code, figuring out what is going on and making changes there.

Those are just some of the things that bug me because people come out of the university assuming that they can start pumping code, and they don’t know how to actually work on projects.

I wish a four year degree would also mean having a a four years project, that you started to work on day one, and to modify and work on throughout those years. That would give newly graduated students some concepts about how to manage a codebase over time. For that matter, I see questions like this being asked, and I don’t really know what to say.

There is a very strong need to have practical learning as well. Not just learning algorithms or how things work, but also how to actually work.

Emergent behavior

time to read 3 min | 403 words

About five or six years ago, there were two guys (me and another dev) working from our Israeli offices. We needed some way to setup remote access to the office, and there were just the two of us. We changed the port forwarding settings in the router and got a static IP, and assigned each of our computers a specific port, so we could RDP into our computers. That happened a long time ago, and I pretty much forgot about it. If I was on a new machine, I knew that I had to RDP into a specific URL and port, but that was about it.

Since then, we got a lot more people in the office, and they occasionally work remotely. Until at some point, we run out of room in the office, that was when we were just over 10 people. So we started to look for new (and much larger) offices. One of the things that we did alongside the move to the new offices was take the time to actually setup proper infrastructure. That means that we got a VPN, proper network structure, etc.

The newest guy in the company was having trouble logging into his computer remotely, and I looked into that. It took a bit of time to figure out what the problem was. He was able to VPN properly, but he couldn’t RDP to his machine. The problem was that he was trying to use the default port, but… his machine was configured to listen to a different port, because of the port forwarding setup.

Now, this was a surprise to me, because I never did that, or told anyone to do that. In fact, the one setting it up was the other dev who was there when we first set it up. What happened was that he made sure, as part of welcoming new employees to the company, to set them up with remote access to the office.

The funny thing was, I had no idea that this was happening. Now, to be clear, I have no issue with that, and having stuff taken care of without me having to hand hold everything is pretty much the definition of why Hibernating Rhinos isn’t a single person company, but it still surprised me to see that this was something that was happening for so long that I wasn’t aware of. It just worked.

FUTURE POSTS

  1. NHibernate Profiler 5.0 Alpha has been released - 14 hours from now
  2. The best features are the ones you never knew were there: You can’t do everything - 4 days from now
  3. You are doing it REALLY wrong, the shortest code review ever - 5 days from now
  4. Carefully performing invalid operations to get the wrong error and the right result - 6 days from now
  5. If you have a finalizer, watch your ctor - 7 days from now

And 6 more posts are pending...

There are posts all the way to Dec 08, 2017

RECENT SERIES

  1. PR Review (9):
    08 Nov 2017 - Encapsulation stops at the assembly boundary
  2. API Design (9):
    27 Jul 2016 - robust error handling and recovery
  3. Production postmortem (21):
    07 Aug 2017 - 30% boost with a single line change
  4. The best features are the ones you never knew were there (5):
    21 Nov 2017 - Unsecured SSL/TLS
  5. RavenDB Setup (2):
    23 Nov 2017 - How the automatic setup works
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats