Lately I have been giving some thought to just what exactly the guiding principles are behind the way I both approach and execute my professional software development career. After considering this for some time, I have come up with the following fifteen or so principles that I think sum up pretty nicely my approach to things.
Things to note about these:
- These principles aren’t listed in any order; except in so far as the order they came to mind (so perhaps subconsciously they are ordered! )
- Some of these are related to designing and developing software; others are related to managing people because both are significant components of my varied responsibilities
Complexity is the Root of all Evil in Software Engineering.
This principle springs from the observations over my career of myself and others that as the complexity of software increases, nearly all other positive aspects of the project decrease. All of the ‘-ilities’ that are espoused as being the goals of ‘well-engineered software’ (whatever that means!) decrease as complexity increases.
Flexibility, extensibility, adaptability, manageability, etc. all suffer terribly under the weight of an oppressively complex software project as the complexity conspires at every turn to make achieving these other aspects of sound design nigh-impossible. As a result, if you can successfully reign-in complexity in your work, then all other goals are at least within range of being achievable.
A lot of what we do requires creativity; a lot of what we do does not. KNOW THE DIFFERENCE.
If I had a dollar for every time I saw a developer solve a problem in a needlessly creative fashion, I could retire and live out the rest of my life in luxury. Certainly, good software developers understand that they need to be creative problem-solvers, great software developers actually are, but exceptional software developers recognize when creativity is called for and when their tendency for creativity is inappropriate.
Often manifesting itself in concepts like NIH (Not-Invented-Here), ignoring this principle leads to wastefully redesigning the wheel for every project rather than smartly leveraging what others have done who have come before us. The shoulders of giants are there for a reason; use them.
Write code for other developers, not the computer.
When it comes time for a developer to actually write code, always consider that there is absolutely no difference to the computer between using variables with illustrative and informative names like OrderNumber, CustomerName, etc. and needlessly-terse names like a, b, c, etc. But to the developer who has to maintain your code (and this could even be yourself, stupid!), there is tremendous value in the former approach vs. the latter. This principle applies well beyond things like variable, method, and class names and continues into function bodies, logic of algorithms, and the very structure of your software design and implementation.
Always be cognizant of the fact that your code will be read once by the computer (during compilation) but hundreds — if not thousands! — of times by yourself and other developers during the current project and any future maintenance. Optimize your work so that other humans can effectively read your code; the compiler optimizations are improving just fine with each new version but developers aren’t getting any better at reading complicated or counterintuitive source code.
This principle is related closely to the preceding thought about appropriate and inappropriate creativity; don’t get needlessly creative with your code such that it makes it difficult for another developer to interpret what you meant. This isn’t clever, its wasteful.
Context, Context, Context.
Very simply, this principle is about paying attention to your situation and recognizing what aspects are similar to other situations and what aspects may be different. The reason there are 100 (at least!) different ways to solve a problem with software isn’t so that you can randomly pick one and go with it . Its because in each context, a different approach may be called for. All aspects of your software solution from the overall architecture to the underlying language and run-time platform should all be the result of understanding what is and isn’t appropriate for the problem at hand. Dogmatic application of any specific approach, technology, etc. needs to be tempered by constantly asking yourself "is this appropriate for the current situation?"
If I didn’t learn anything new at work today, I should have stayed home.
Every day I have to learn something, even if its just increasing my recognition of how much more I have to learn. One of the reasons I am drawn to this profession is that I can never be an expert at my craft, only (hopefully!) better at it than yesterday. As soon as I ‘master’ something (even assuming that’s possible today), something new comes along that I have to ‘master’ next. If I didn’t learn a single thing at work today, then the day was a waste of my time.
That something new doesn’t need to be as big as a different programming language (of course). It can easily be as small as a new technique, a new API call in a library I thought I knew pretty thoroughly, or even just my increased awareness of something new out there that I now need to find time to look into.
But if I’m not constantly learning, then I may as well be dead.
Anything can be measured in a manner more accurate than not measuring it at all.
I tend to think of myself as an empiricist. "Show me the data", is my refrain. One reason I take this approach is that all too often in my career I have posited solutions to problems based on faulty assumptions (and not surprisingly this doesn’t result in positive outcomes).
Probably the biggest challenge with a "show me the data" approach is that often data upon which to base a decision is simply unavailable. In these cases, one has to rely on the idea of "Context, Context, Context" as discussed above plus good judgement. But in the absence of any data at all the phrase ‘good judgement’ sadly reduces down to a ‘guess in the dark’ since without any data there is nothing to ‘judge’ when applying your ‘judgement’. This leads me to the principle that a faulty (or less-than-100%-accurate) measurement is always preferable to no measurement at all. Which is to say that partial data is always better than no data.
"There is no objective measure of programmer productivity that is 100% accurate.", is a familiar refrain (and one I happen to agree with). But does that truly mean that all programmers are equally productive? Of course not, but with zero data to review that is the only conclusion one can actually draw that isn’t a complete guess-in-the-dark. Raw LOC count, bug-introduction rates per LOC, time between bug-fix-start and bug-fix-complete are all highly inaccurate measures of programmer productivity, but IN CONTEXT each of them tell us something about the developer’s productivity that together start to let us draw conclusions about relative productivity of our staff.
In every case, in every context, some data is always better than no data so long as the interpreter of that data understands the context within which it was captured.
If you cannot look at code you wrote last month and say ‘yuck!’, take early retirement now because your best days are behind you.
If at any time as a software developer you look back at your past work and aren’t horrified by the work you did in the past, then you should hang it up now and just go home. Tied closely to the notion of "I need to learn something new every day", this principle is about the idea that if you are constantly improving your skills then you will always look upon your past works with some level of disdain as you see it through the lens of your newfound skills.
If not, your best days are behind you, you have stopped improving, and the downward slide into uselessness has begun. Get out of the way and free up the desk for someone else.
An Open-Mind Policy is infinitely more important than an Open-Door Policy.
I have spent most of my career working for companies that were very proud of their open-door-policy. Seriously, has anyone ever worked for a place that didn’t say "We have an open-door policy here."? Its like "We value our employees, they are our most important resource." and is equally as meaningless as just so much boilerplate HR-speak that every HR director who apparently comes from the same HR Executive factory has been taught they must communicate to employees.
But an Open-Door policy just tells you where its ok for you to go and communicate your input and says nothing at all about the chances that anything will come of it. The barriers to communication in most companies have nothing to do with open or closed doors, they have everything to do with open or closed minds about what gets said when one passes through one of those ‘open doors’ that employers are so proud of talking about.
We all need to always keep an open mind about everything because the hubris that comes from "I know now and forever the best way to do XYZ" is getting in the way of the ‘learning organization’ that we all really want to work for.
There is no problem so simple that a bad developer cannot make it complicated.
This principle maps closely to the common quote "Never underestimate the ability of the Universe to produce a better Idiot." but it speaks also to the same "Complexity is the root of all Evil" notion discussed previously. This principle boils down to the idea that the best way to mitigate complexity is to become a better developer and that unskilled developers are more likely to overcomplicate solutions than experienced ones.
If I was given four hours to fell a tree, I would spend three of them sharpening my saw.
The principle embodied by the above quote from (of all people) Abraham Lincoln, 16th President of the United States is basically a way of illustrating the concept of "Work smarter, not harder."
As software developers much of what we do is creative, unique, one-off work but so much of what we do is also rote, repeat, boilerplate content. All too often, software developers fall into the ‘solution by brute-force of effort’ approach to getting work completed on schedule. Instead, we need to constantly be on the lookout for tools, techniques, processes, and general approaches to our work that allow us to always be improving our efficiency and effectiveness at problem-solving.
I’m not against hard work, but I would rather put my energy into avoiding it by working smart where possible
The key to effective delegation is learning to ignore HOW something gets done and just caring that it gets done.
One of the biggest challenges to the effective management of people is learning effective delegation. And one of the biggest barriers to effective delegation is resisting the urge to micro-manage what you delegate.
It is a logical truism that in anything as complex and variable as software engineering, no two people will perform a task (whatever it might be) in exactly the same way. This truth applies to tasks that run the gamut from "write an e-mail to that client asking for more info" to "develop the guts of the data-access-layer".
While its important to care generally about how each task is performed (e.g., is it up to our standards?, is it on time?, etc.) to effectively delegate means defining clear goals for the task and then only caring about the outcomes. To care too much about the how of what gets done is to risk micro-managing the task such that you convey that the only valid approach is the one that you would have taken. If you find yourself dissatisfied with the outcome of what you delegate, then it means you failed to adequately convey the goals of the task when you delegated it.
Managing people is simple: hire the best, define clear goals, assign proper authority to execute, and get out of the way. If they don’t perform, fire them and go get someone else.
This principle embodies what I consider to be perhaps the single most important set of concepts for effective management of people because it to me it reflects a set of commitments to the process from both sides of the equation. In essence, its an acknowledgement that creating the conditions where success is possible is a two-way street to which both parties have to contribute.
If management (department heads, project managers, whatever) fails to live up to their end of the bargain (hiring the best, defining and communicating clear goals, granting authority to produce, and getting out of the way) then the results (staff performing to expectations) is never going to come to fruition and to blame the employee for that failure is to avoid the painful introspection that will be needed to avoid repeating the failure in the future.
But if all those inputs are correctly provided for and you still don’t get the performance you want (or need) out of an employee, then the single best course of action is to let that person go and hire another. Life is too short and the pool of potential hires too large to waste time on reshaping an employee that is a square peg to fit into a round hole.
Leadership means being a short-term pragmatist and a long-term idealist.
This principle is about the idea that to effectively provide leadership one needs to keep one eye on near-term tactical goals and another eye on long-term strategic goals. When the effective balance between these two gets badly out of whack, terrible things start to happen to a team of people.
On the one hand, when there is no long-term strategy this can lead to nothing but reactionary short-term ‘firefighting’-style emergencies that preclude planning and executing any tactics in support of a longer-term strategy. Since there is no articulated long-term strategy, troops on the ground lack sufficient context to make the correct tactical choices day-to-day that would be needed to reinforce the attainment of the strategy. They try to make the correct decisions, but lack enough context to do so.
On the other hand, when there is nothing but a long-term strategy without any tactical idea communicated about how to best achieve the long-term strategic goal, this tends to lead to ‘death by a thousand initiatives’ where everyone on the ground tries in vain to follow their own ideas about how to best attain the long-term strategic goals. Eventually, you end up with everyone in the team headed in a different short-term direction, but if you ask each of them why they are acting as they are, each will (capably) explain why what they are doing is in direct support of the long-term goal. But with everyone headed in a different direction, the long-term goal can never be achieved.
Effective balance between these two is critical to the effective leadership of people.
Vision without execution is daydreaming.
This principle is related closely to the prior principle and essentially says that big ideas without any concepts about how to get there from here aren’t a vision, they are just fantasies.
This is true whether your vision is a corporate strategy or a software design approach; talking is great, but every now and then its important to spend time finding ways to make your vision a reality or else your vision is just a daydream without substance.
Software Architects care WHAT software does, Software Engineers care about HOW. BOTH ARE EQUALLY IMPORTANT.
This principle is an attempt to draw a correlation between the roles of architects and engineers in the software development world very much akin to the the role of architects and engineers in the building construction field from which my career began a number of years ago. This principle tries to acknowledge that just as in the building construction world, there is a need for both roles in the world of software development.
There is tremendous invective and derision in the software development world between ‘Software Architects’ and ‘Software Engineers’ where neither considers what the other does to be of tremendous value. To be sure, I have met in my travels any number of terrible ‘Software Architects’ and any number of terrible ‘Software Engineers’. I have also met any number of terrible building Architects and any number of terrible building Engineers. But none of these experiences has convinced me that the body of knowledge that defines these peoples’ areas of study is somehow of no value even if some of these people I have met certainly added little value to the project (a building or a software system).
Nobody (who knows what they are doing!) would suggest that constructing a building without engaging the professional expertise of both Architects and Engineers would be a good idea. This principle says the same is true of developing software. Somebody has to be concerned both for the WHAT and the HOW of the final software solution.
To be clear, a lot of people with ‘Software Engineer’ as their title are secretly also practicing ‘Software Architecture’ because someone has to do this task and their team lacks someone in that official role with that official title. This is perfectly acceptable as this principle isn’t about defining titles for business cards. Instead it’s about defining roles for a software development project independent of any title anyone may have or want and acknowledging that in the software development process, both roles are equally needed for the project to be a success.
I don’t believe anything; it gets in the way of learning.
Despite the title of this post, this last one is perhaps the most important becuase it reiterates that what I know today is the sum total of all my experiences and knowledge acquired to-date and recognizes that there is a world of knowledge and wealth of experience that I just don’t have (yet!). I have to remain open to the idea that once I have more experience and knowledge some (or perhaps even all!) of what I current think to be true may in fact turn out to be wrong. Belief in anything gets in the way of anyone’s ability to learn anything new that might contradict their present beliefs.