Monday, August 10, 2020

New Blog...

I'm switching this blog over to Devblog.  More interestingly, it's now located at https://blog.mkrebs.dev/.  I republished my seven blog posts there, although they didn't support backdating far enough.

Blogger and Devblog were two platforms I found that supported custom domains for free.  And Blogger was neglected for so long, I'm reluctant to use it.  Google does not have a good track record with keeping sites around, and even if Google keeps a product around, it oftentimes forces folks to upgrade or lose it (like with Google Sites, Hangouts, Allo, etc.).


Thursday, July 19, 2012

Code Reviews Waste Time and Energy

When I first heard of using code reviews, I remember thinking they seemed like a waste of time.  But, to be fair, I had heard of them in the context of Extreme Programming -- which I had already thought was a waste.

Now I work for a company that requires code reviews for every change you make, and I know they're a waste of time.  But what I hadn't realized, until after I was subjected to them, was that they are also a waste of energy.  I'll describe below a general scenario that has played out on more than one occasion where I've needed a code review.

----

First, you have a change you want to commit.  So you go through the motions of uploading the change to the code review server and add a reviewer.  Then you wait.

You get your review back, and the reviewer has marked up half your changes as being against the current coding style that you're supposed to be using.  But here's the thing: you were just copying the same style that already existed in that file.  Coding styles are an ever-changing thing at companies, so this isn't that unusual, and in my case I mostly work on open-source so the file could very well have been written at a different company.

But you make the changes, because you can't commit without the reviewer's approval.  In the meantime, another reviewer has been added, either because the first reviewer thought he/she might have something to say too, or because they have a watch on code reviews and wanted to add their two cents.  Now, the second reviewer sees your updated changes and flags the review saying you need to make your changes consistent with the style in the rest of the file if you want to commit it.

Okay, fine.  In order to make both reviewers happy, you now go and change the rest of the file, along with your change, to match the current style.  Mind you, don't forget to re-run all your tests on the updated changes!  Finally, you upload your latest round of changes.  If you're lucky you can just commit everything now.

You think you're done?  Maybe not.  Because in about a week, you have a third person trollin-- er, browsing around the source code and they come across your change.  They add a comment to the now-closed code review saying you need to redo your changes because they were too big.  You can choose to ignore this (which I've done sometimes), but you run the risk of making enemies -- which sucks if you end up needing that guy/gal to review your next change.

How I usually choose to resolve this is to just placate each person along the way.  Eventually, everyone will get bored and move on.  Once, I had two reviewers that were feeling particularly stubborn, and they made me change my code back and forth (the first reviewer insisted I use different logic than I did, and the second reviewer insisted I use the logic that I had used at first).  In that case, I tried pointing them to each other and told them to work it out; eventually, one of them gave up.  Of course, a third reviewer came in two weeks after the commit and told me to use a third kind of logic!

----

All in all, most of my code reviews are a waste of time and energy.  At best, I get someone who has better things to do and so just tells me to go ahead.  I wish I could say that was the norm.

I should mention that I rarely have bugs caught in my code reviews.  I don't know if I'm that good (I do test my changes a lot before committing), or if my code reviewers are that bad.

Maybe I should intentionally throw a bug into my uploaded changes.  That way the reviewers can still get that sense of accomplishment, while leaving the piddly stuff alone.


Monday, June 21, 2010

Interview Selection Principle

You get what you interview for. That is, the selection criteria used during a company's interview process dictates the type of candidate that company will likely hire. For lack of a better name, I've dubbed this the Interview Selection Principle.

I bring this up because it seems to me that a lot of high-tech, and well-respected, companies aren't getting their interview process right. I wrote about one example of this in my previous post, with respect to coding on whiteboards.

If you ask your candidate to write code on a whiteboard, he passes with flying colors, and then gets hired, all you've done is made sure you that your new employee can write good code on a whiteboard. But what skills does that process select on?

One skill shown by that would be the ability to hammer out a logically-correct design in one shot. That may be a nice skill for a programmer to have, but is it necessary? And, more important, does it necessarily make for a Great Programmer? It's a fair argument to make, to say that having this skill can be a predictor, but that's no guarantee.

I, for one, do not always hammer out a good design the first time I write code. But, I'm willing to bet that I can complete a project with fewer bugs, an easier path forward for new features, less required maintenance, and in less time than most programmers. You see, being able to "Get It Right" the first time was great when programmers had to put holes in punch cards, but that doesn't much matter now that you can cut & paste a section of code, search & replace the name of a variable, and delete large swaths of code -- all with a few keystrokes in Emacs or VI.

Another criteria many tech companies seem to focus on is knowing the Big-O notation for various algorithms. If someone can pass your test by knowing the correct answer is "O(n * log n)", all you've done is found someone that can rattle off something that most programmers would just look up in Wikipedia. Can knowing these arbitrary things be a predictor for Great Programmers? Possibly. I mean, if a candidate knows that stuff, it probably means they at least have a basic understanding of programming (whoop dee doo).

But, I admit, I don't know the exact expected times for most algorithms off the top of my head. And -- you know what -- that doesn't matter. Why, you ask? Are you thinking that I'm going to, someday, waste my time implementing some algorithm only to find that it's untenable because it's "O(n^2)"? Well, I have three responses to that...

First, the situations where a programmer has to design and write new code for some large dataset, where speed matters, are few and far between. It's not what most programmers do every day.

Second, and more important, if a programmer is a Great Programmer, he/she can rip out that slow algorithm and write a new one in less than a day. Remember, we're not working with punch cards here. They can delete the crappy nested loops with a few Control-K's in Emacs, and then call off to some nifty hash implementation. And, because a hash should be simple to a Great Programmer, they can then write the hash implementation in less than an hour. After that, they'll still have time to improve their hash function and have leftover time to grab a snack from the company kitchen.

Third, I believe one thing that makes for a Great Programmer is instincts. There's an instinct in Great Programmers that makes them check if a pointer is NULL before dereferencing it, if (and only if) there's a chance of it being NULL. There's also an instinct that makes sure to always free() allocated memory in the appropriate place. And, another instinct is to not unnecessarily loop through large sets of data.

So what should a company do instead in their interviews? Well, you'll already know one thing they should do if you've read my previous post: ditch the whiteboards already (for interviewing)! But, more to the point, have each candidate write code, on a computer, that does something. And, yes, that something can be to sort or search some data.

In other words, don't just pick out some data points (like knowing the Big-O for merge sort) and try to extrapolate whether or not someone's a Great Programmer. Instead, just directly put them to the test to see if they write code like a Great Programmer! Do they implement an exponential algorithm, and not even realize it? Do they use recursion for each element of a list that might hold billions of elements, not realizing they can blow their stack? Now that they have the power of cut & paste, are they repeating code that should really have been pulled out into a function?

To get back to the Interview Selection Principle, assuming you hire what you select upon during your interview process, why not select upon actual, real-world programming?


Interview Pet Peeve

This is a plea to any and all companies that are interviewing Software Engineers: require that your job candidates write code. This, in and of itself, isn't new. If you've read The Joel Test, for example, you'll find this as requirement #11. But I want to add to that: ABSOLUTELY NO WHITEBOARD CODING!

When was the last time, other than in an interview, that you pulled out a dry-erase marker and wrote fully-functionally, syntactically-correct code on a whiteboard? If you can name a time you've done that (and it was more than a few lines), then you're doing something wrong.

Computers are cheap now. Buy one for your conference room, or wherever else you carry out your interviews. If you don't want to install actual development tools on the computer for some reason, at least let your interviewee code in Microsoft Notepad. You can even let them use some netbook computer if you have to. Or, let them use a smartphone to type it in! Heck, you'd be better off offering him/her an old-style typewriter rather than a whiteboard -- they can't edit and insert with either input device, but at least with a typewriter they can have the benefit of entering code fast.

Wednesday, April 12, 2006

Little to no use of object-oriented interfaces

Recently, I've been developing code in an application that is heavily object-oriented. And, in doing so, I have reaffirmed my hatred of the stuff. There are several reasons for this, although I don't care to go into them all right now -- maybe when I have more time.

At least one problem I have with an object-oriented design relates to global variables. Let us examine those first. If you mention the use of "global variables", most software engineers will scold the idea and damn the writer of such code to hell. Why, you ask? Well, to be honest, I forget the official reason we were taught in school, but I can tell you that my reason for hating them is because they increase debugging entropy.

This concept is one I just now invented, so bear with me. By "debugging entropy" I basically mean that the chance for bugs goes up, and the difficulty of debugging bugs increases. One reason this is true (and maybe it's THE reason) is because you're adding more inputs and outputs to your code. For every global variable, you might as well be passing it as an argument to your function, nay, every function. That leads to a heck of a lot of potential code paths that have to be accounted for, because anybody could have set your global variable to just about anything (i.e. not just your caller). More code paths lead to more potential bugs, and also makes debugging harder because more things may have to be inspected while stepping through the code.

But what's worse is that programmers tend to use global variables out of laziness or bad code design. They use them because they don't want to pass some value to every single function. So instead of consolidating data structures, or just sucking it up and adding the parameter, they hack in a global variable.

Now, let us go back to how global variables relate to object-oriented design. If you are using classes/objects as an interface, you inevitably end up keeping around state for such objects. That state is kept in class member variables. In my opinion, these members are no different than global variables. They are accessible by all member functions of the class and will likely just increase in number as the lazy programmer needs to access more data.

For example, in a GUI program you might have a "Window" class that represents all there is to do with putting windows on a screen. And in that class you'd probably store things like a list of active windows. But I'm willing to bet that at some point that Window class will want to know what the current screen is. Since the Window object does not have access to that, it will likely be added to the class as a new member variable "current_screen". This is just a global variable -- it's a hack! To add insult to injury, I bet the programmer will use set_current_screen() and get_current_screen() accessor functions for it and claim that it is now good programming (see my previous entry about my hatred of those)!

Wednesday, April 20, 2005

No brain-dead accessor functions

I know this is a controversial one that many people disagree with me about, but I don't believe in using accessor functions that simply return a field/variable, or set a field/variable. I see it as a pointless excercise in object-oriented programming that serves to complicate things and barely makes anything easier.

My primary reason for hating these is that it makes for harder debugging of code that contains them. With MULTI, you can click on a field that's used within the code and it will print out the value. You cannot, however, click on a accessor function and have it print out the value of the field it accesses.

Another reason for not liking these is that I'd like to think of functions/methods as simplifying a block of code either for ease of reading, or so it can be used by more than one caller. So when I see a function/method call, it implies that something useful is going to go on when it is called. Therefore, if I'm debugging code I don't know like the back of my hand, I may look at the function or at least guess its purpose by its name. An accessor function, then, is simply a distraction as I have to think about it long enough to determine that it's not really doing anything.

ASSERT!!, ASSERT!!, ASSERT!!

To me, putting assertions in my code is one of the most useful things I can do when writing code. I have tried to get in the habit of noticing any assumption I'm making, and then putting that in my code as some form of an assert().

For example, if I were to cast a pointer to a long, I would make sure that it would fit (since C does not guarantee that). And, for something like this, you can make it a compile-time assertion that doesn't cost any run-time. Within GHS's source code, this can be done with gen_const_assert(sizeof(long) >= sizeof(ptr)). As another example, if your code does a "while (--num > 0)", it wouldn't be a bad idea to use an "assert(num != 0)" if "num" is unsigned.

I also rely on assertions as a way to efficiently write new code. If I'm doing socket programing, for example, I may just write assert(socket(...) >= 0). This way, I can quickly write my code without worrying yet about providing good feedback to users (i.e. error messages), yet also avoid the confusing bug that may occur when a file descriptor with the value -1 is written to. Plus, I can easily search for "assert(" later if I feel like giving useful error messages to users.

Assertions also provide me a benefit when I'm programming. When I see an assertion, I can *know* that the given condition is true. This allows me to reduce the problem space because I may know, for example, that I given pointer is never NULL.

Prologue

After writing code for many years, computer programmers develop a certain style, or method, of writing their code. Some of this is for aesthetics, like how much one indents a line of code. Some of it is for user interaction, like using verbose error messages. Some of it is for allowing easy code maintenance, like using comments. And some of it is for limiting the affects of bugs, like using assertions.

In this document I will try to describe my style. Some of it will be just my preference but some of it, I feel, helps me be a more productive computer scientist. I'm hoping this will either help others improve their coding style, or will inspire others to help me with mine.