|
If you're reading this, you probably know exactly what I am talking about. There's that moment where an engineer opens his or her mouth and spews a bunch of words that sound intelligent, cohesive, and, if you're another engineer, like total bull. They rattle on about how a problem is extremely complex and requires care, how they have delicately crafted some exotic beast capable of doing epic battle against the Demonic Foe and winning in the most gallant, obfuscated way possible.
If you're an engineer, you pull the repository, check the product, and, much to your horror, realize they have attempted to build a space shuttle. From scratch. Or hobbled together with a bunch of Russian parts never meant to be used in the same sentence.
As an adjunct professor of Computer Science at Stevens Institute and a senior engineer that has mentored many software developers, interviewed hundreds of engineering candidates, and peer reviewed countless lines of code, I am here to tell you that the best engineers do not speak in tongues and, more importantly, certainly do not code in esoteric gibberish that only they understand.
So, what's the problem? Why, too often, do we end up with complex tangles of code that appear built to survive a nuclear holocaust and, yet, usually end up crashing servers, deleting user accounts, and being rewritten by another engineer after the original creator leaves?
Why Simplicity? Simplicity translates to flexibility, extensibility, and reliability. When a system is easy to understand, intuitive, and minimalist, action and reaction are easy to observe and modify. As additional systems are added, the separation of action and reaction increases and becomes remote. That is, when something happens, the impetus and final result have a vast distance of code to be traced through and understood.
A calling B is a direct reaction with very easy to understand result. I like to say, "The distance to understanding is small."
A dispatching something of type C read by a system called D and then translated from D specific understanding to B specific understanding before being related to B by an intermediary E is... garbage.
A Land of Complexity Every decision made during engineering has the ability to increase or decrease complexity. It is the engineer's ultimate responsibility to balance these decisions. Simplicity is harder than complexity in that it requires strong executive functioning skills (our ability to organize and use information), an understanding of how individuals use software, time to think through potential solutions to problems, and collaboration (without collaboration, you can never truly know whether the code you have written is simple for others to understand or convoluted).
Magic The first issue is simple enough: communication. To those that do not understand engineering, the craft of code is magical. Like a sufficiently advanced alien race, we engineers can be perceived as sorcerers. More so, many of us revel in the heady intoxication of "I know something you do not" and milk those moments for all they are worth -- they allow us to exert ourselves over those around us.
Often, when teams are being formed, there are non-engineers making decisions about who will lead the engineering department or team. When inexperienced engineers or non-engineers are involved, the magical words of technology can be more than enough to allow less-than-capable individuals through the doors. Damage is most impactful toward the beginning of a product's development, when the foundations are being first hammered out; so, any damage done by the complexity monsters at this point can have catastrophic effects.
Poor Mentorship That first arguement feels iffy. It's me saying, "Oh, you're not an engineer, you don't know what these guys do!" which is all part of the problem, right? Let me give a more concrete reasoning for these complex behemoths: mentorship.
If you could take every engineer that has mentored an individual and line them up, you would garner a deep understanding of the capabilities and methodologies of that person. Sadly, this is not possible. The interview process is meant to hammer and chip away at walls until the root individual stands, naked, before you -- or that's the idea, anyway, engineers tend to get wrapped up in asking tongue twisters about sandwich making and math.
What am I saying? Well, the behaviors engrained in an engineer early in his or her career define how he or she deals with complexity. Now, that sounds fatalistic, many of you will say. Deal with it. It's the truth. Until an engineer has been mentored to understand 1) what it means to work on a TEAM 2) how to collaborate, not compete and 3) pride in craftsmanship, he or she will, genuinely, not be aware that he or she actually needs to be mindful of these elements!
The Lone Wolf The most complex code I have witnessed has come from individuals with histories of "lone wolf" coding. They have never had formal mentors. They have assumptions about how other people use code based on how they use code -- not on experience actually collaboratively building products -- and they have been perceived their entire lives to be "aces" (as they have never had anyone actually look at the raw instructions they have been leveling at problems).
Good mentorship implies review. The point isn't to harm ego, put someone in his or her place, or embarrass them; rather, the idea is that engineers as a collective, working together, are stronger than when they are solving problems on their own.
The roman soldier could fight individually, this is true; yet, we remember them most for their exemplary collaboration on the battlefield. A horrible engineer is made better by collaboration. A great engineer is made worse by solitude.
Generalize It, Baby! Me: "Why is this so complex?" Them: "Well, we will want to use this across all of our products." Me: "How many is that?" Them: "Well, at the moment... 1"
There are a few simple concepts that have poisoned many a project. Just because we can create generalized, reusable code does not mean every piece of code we build HAS TO BE generalized and reusable.
The worst engineering I have witnessed has revolved around an engineer attempting to "think ahead" and build something to solve future problems that never materialize. In doing so, the code becomes complex. Why? Well, when you try to solve every problem in the universe, you have to cover a lot of cases! You have to build a lot of systems, of course.
"Architects" (the bad ones, that's why I used quotes, there are great architects, as well) love to do this. In an interview, I had a candidate say, "I like to build libraries for my team to use." My simple response, "Do you use them, too?" confused him. Why would he have to try his own product?
Now, the converse, not thinking ahead, is just as dangerous. I am not advocating building only purpose-built systems that can never be expanded; rather, I am saying that simplicity and clarity of purpose make systems that are better able to be extended AS NEEDED based on real, actual needs instead of prediction.
I think that's enough to think about for now. I apologize for the complexity :) I didn't have time to sit and simply compose a blog. Please leave questions, comments, etc.!
Andrew A. Grapsas is a senior software engineer specializing in gameplay and engine technology in the NYC area. You can read more at http://aagrapsas.com and follow Andrew on twitter at http://twitter.com/aagrapsas
|
P.S. : This article makes me appreciate the amazing mentors I had as well I couldn't imagine how i would code without them.
Good post. I know very well the truth to much of it because I am one of those engineers that want to over-engineer.
My first inclination to a solution tends to be vast, complicated systems, with many moving parts. And then I have to spend several hours breaking it down and simplifying. I can usually avoid my lust for complexity and succeed with straightforward solutions.
Why is my first pass usually bloated and complex? I think the best answer is because it is fun. In the same way I enjoy games, I like to see things work, and the more moving parts the more intriguing it can seem. And we all want to enjoy our work.
But to the point of your post, what is clever and complex does not tend to make a good solution.
People who write messy and complicated code make everyone's lives more difficult. If someone does it on accident, they can learn better.
But someone who intentionally causes trouble for others to make themselves feel more important is trouble.
I bookmarked it to use in discussion and arguments in the future, haha :P
Again, thank you!
No but really, I'm a very modest indie dev for our small Studio: RapusGames, and I mostly do coding. To be perfectly honest, I personally don't think I'm a genius programmer, but I know that at least my code is readable and clearly labled as to make it possible for anyone working with me to come in and change the "ChangeCameraTarget" function.
On the other hand I have worked with honestly brilliant people that write THOUSANDS of lines of terribly muddy code for a simple program simply following some unexplainable logic (Yeah! lets use bitwise operations for everything, Right?). And it is a PAIN, simply because replacing anything in their code or modifying any part of the process becomes an almost impossible task.
Lately I've actually been starting to feel better about my code simply because I can explain artists about what I'm doing and it is not at all shrowded in mysticism at all, so they actually understand the system. And I feel this is a pretty big accomplishment.
As you say I suppose a lot of it comes from a musconception that coding is almost like magic, or like an abstract talent (I don't even think that art responds to an abstract talent).
I've even met some programmers that actively advise that you should make REALLY COMPLEX CODE to ensure that you are not expendable for the project, I'm not even making this up.
I suppose the more we manage to de-mistify the discipline, the better for everyone.
Thanks for the read!
@Harold Myles, totally agree with the complexity is fun bit. Should probably reconsider my coding philosophy.