So this is something I’ve seen two large camps pitted against each other for. Programmers should always be responsible for the code they write and should always be actively trying to write responsible code in itself. I think everyone can get behind that without much quarrel. But! One camp tends to argue that the programmer should ensure there is ~absolutely~ no way for things to blow up while the other camp argues that the programmer should place ‘checks’ in the code in the possibility that it does.
Hopefully the issue is clear.
Should a programmer place checks in their code to not only protect users in the future, but also themselves? “Why wouldn’t you?” your reaction may be. Well, you might have a complex piece of code that would take a lot of resources to constantly check will work properly. The goal is to make sure your code is exception-safe as much as possible, but there is always someone out there who will holler out “at what cost?!” If something is expected to work one way, that should be the ~only~ way it will ever work they argue!
It boils down to a kind of elite purist paradigm vs a human-error safe paradigm. Both have merit!
I made a pretty timely and amateur mistake today because I was running the purist paradigm. I’ll talk about how I should have placed checks to save myself and evidently my boss about 2 hours of time. But at the same time the issue could’ve been easily avoided and no check at all would’ve been needed if I didn’t rely on my faulty memory.
So because of the confidential nature of work and me being super cautious about what I can talk about and what I can’t, I will be as vague as possible in explaining my issue.
I have a box. It can fit something that is 2ft tall inside of it (ignore width). I put something that is exactly 2ft tall inside of the box, and its just perfect. But, maybe my box is no good for some reason so I have to move the contents to another box. This other box can fit something that is 5ft tall. Well, that’s 3ft of wasted space – but it will work anyway right?
What if it was the opposite. What if the box I had originally was 3ft tall and had 3ft worth of content. I need to move to another box, but the new box is only 2ft tall. You can’t fit 3ft in 2ft! Small to big is fine. Big to small is not!
Pretty basic in programming: If you have a 16 bit integer you can put it in a 64 bit container fine. But if you’re expecting 64 bits to be in a 16 bit container, you’re going to have a bad time. Naturally, a compiler will blow up in your face and tell you “hey man, what are you doing with your life that you’d expect this to work?”
Mine didn’t… and I spent 2 hours in confusion. Basically what was happening was I was serializing a 16 bit integer into a 64 bit container, and when the receiving end got the 64 bit container over the network – it spent infinity wondering “where’s the extra 48 bits?” after reading in the 16 bit stream. It threw my socket into a mess and it refused to receive any more serializations because… it was always waiting on the other 48 bits that was never coming.
How did this happen? Well, I originally was using 64 bit integers. I changed the server side to take 16 bit integers, but never changed the ‘client’ side to send 16 bits as well. So – again – it was taking a 16 bit integer, putting it in 64 bits, throwing it at a hole that was “only big enough” or really only expected 16 bits. Because I SWORE I changed all the 64 bit entries to 16 bits. But of course, human error! How could I be such an amateur!?
Live and learn right?
So what could have prevented this or at the ~very least~ told me this could happen? I relied so much on a compiler telling me “hey man, this won’t work” that when it didn’t (it really can’t), I was lost. The only ‘solution’ is to make sure there are checks in place where that “hole” takes in 16 bits and if it ever gets more than 16 bits: have it make noise – flag some support down – shoot a flare – something – anything! It would’ve cost nothing more than a simple sizeof comparison to flag down.
Now, the other camp would’ve said “hey noob, don’t forget next time” but this could happen to ~anyone~. Its a multithreaded system talking over the network across not 1 language. Not 2 languages. But 3 different ones all with different compilers. I kid you not. It’s just not one of those things you can count on every human interacting with the system to remember even if you document the hell out of it.
So long story short – when you’re putting things in boxes, don’t just assume you put the right thing in the right box based on how it looks or feels or how you may have remembered the box. Try to have the mailman yell at you when you hand him a damn 5ft box when you’re claiming its only 2ft. Never rely on one or the other though! Both camps have merit! This isn’t an invitation for sloppy code that always calls comparison on itself to make sure the slapdash glue is holding…. Just make sure you don’t ignore both the mailman and the box.
If that made any sense at all. Dear lord help me otherwise.
Some may read this and say “that’s incredibly obvious. You should always do it X way.” But you’d be surprised at how many people will say Y instead of X depending on who you ask. Some even say Z, which in this case could be “both, work in both paradigms” which I’m currently sitting in I guess. Everyone comes from different programming backgrounds where things can be incredibly different.
A friend of mine put it this way “every program has bugs… there’s one you’re not thinking of 100% of the time.” It’s totally true. Paradigms from The Pragmatic Programmer will totally point this out and harp on it a ton. Also another point is that I mentioned code being used one way and only one way. A lot of people will say “no it shouldn’t be like that, code should always try to be modular and multipurpose.” That would be great but sadly making things generic and multipurpose is much more time consuming and harder to than most people make it out to be. Especially when you’re dealing with incredibly case specific work like games or lower-level C++.
OOP design should be strived for and you should always be trying make things multipurpose in my opinion, or at least “open and documented” enough to be used or modified by anyone down the line. That includes “checks” for things I mentioned in the beginning.
However, depending on your situation, that might not be worth the time or effort or, sometimes, money. You’ll find, again, in just this subject alone that many people will jump immediately on X or Y. But no matter the majority, there will be another camp of people who will tell you that “OOP stinks” or might be for an entirely different paradigm all together. It’s incredible food for thought and this subject alone could be done as a whole study.