DaedTech

Stories about Software

By

Professional Code

About a year ago, I read this post in my feed reader and created a draft with a link to it and a little note to myself that said, “interesting subject.” Over the past weekend, I was going through old drafts that I’d never gotten around to finishing and looking to remedy the situation when I came across this one and decided to address it.

To be perfectly honest, I had no idea what I was going to write about a year ago. I can’t really even speculate. But I can talk a bit about what I think of now as professional code. Like Ayende and Trystan, I don’t think it’s a matter of following certain specific and abiding principles like SOLID as much as it is something else. They talk about professional code in terms of how quickly the code can be understood by maintainers since a professional should be able to understand what’s going on with the code and respond to the need to change. I like this assessment but generally categorize professionalism in code slightly differently. I think of it as the degree to which things that are rational for users to want or expect can be done easily.

To illustrate, I’ll start with a counter-example, lifted from my past and obfuscated a bit. A handful of people had written an application that centered around modifications to an XML file. The XML file and the business rules governing its contents were fairly complex, so it wasn’t a trivial application. The authors of this app had opted to prevent concurrent edits and race conditions by implementing an abstraction wherein the file was represented by a singleton class. Predictably, the design heavily depended on XmlFile.Instance.CallSomeMethod() style invocations.

One day, someone in the company expressed that it’d be a nice value-add to allow this application to show differences between incarnations of this XML file — a diff changes, if you will. When this idea was presented to the lead/architect of this code base, he scoffed and actually became sort of angry. Evidently, this was a crazy request. Why would ever want to do that? Inconceivable! And naturally, this was completely unfeasible without a rewrite of the application, and good luck getting that through.

If you’re looking for a nice ending to this story, you’re barking up the wrong tree. The person asking for this was humbled when it should have been the person with the inflexible design that was humbled. As a neutral observer, I was amazed at this exchange — but then again, I knew what the code looked like. The requester went away feeling dumb because the scoffer had a lot of organizational clout, so it was assumed that scoffing was appropriate. But I knew better.

What had really happened was that a questionable design decision (representing an XML file as a singleton instance) became calcified as a cornerstone assumption of the application. Then along came a user with a perfectly reasonable request, and the request was rebuffed because the system, as designed, simply couldn’t handle it. I think of this as equivalent to you calling up the contractor that built your house and asking him if he’d be able to paint your living room, and having him respond, “not the way I built your house.”

And that, to me, is unprofessional code. And, I don’t mean it in the sense that you often hear it when people are talking about childish or inappropriate behavior — I mean that it actually seems like amateur hour. The more frequently you tell your users that things that seem easy are actually really difficult, the less professional your code is going to seem. The reasoning is the same as with the example of a contractor that somehow built your house so that the walls couldn’t be painted. It represents a failure to understand and anticipate the way the systems you design tend to evolve and change in the wild, which is indicative of a lack of relevant professional experience. Would a seasoned, professional contractor fail to realize that most people want to paint the rooms in their houses sooner or later? Would a seasoned, professional software developer fail to realize that someone might want multiple instances of a file type?

Don’t get me wrong. I’m not saying that you’re a hack if there’s something that a user dreams up and thinks will be easy that you can’t do. There are certainly cases where something that seems easy won’t be easy, and it doesn’t mean that your design is bad or unprofessional. I’m talking about what I perceive to be a general, overarching trend. If changes to the software seem like they should be easy, then they probably should be easy. If you’ve added 20 different customer types to your system, it’d be weird if adding a 21st was extremely hard. If you currently support storing data in a database or to a file, it’d be weird if there was a particular record type that you couldn’t put in a file. If you have some concept of security and roles in your system, it’d be weird if adding a user required a re-deployment of your software.

According to the Clean Code videos by Bob Martin, a defining characteristic of good architecture is that it allows decisions to be deferred as long as possible. If the architecture is well designed, for instance, you should be able to write a lot of the code without knowing if it’s going to be a web app or desktop app or without knowing whether you’d use MySQL or PostgreSQL or MongoDB. I’d carry this a bit further and say that being able to anticipate what users might want and what they might change their minds about and then designing accordingly is the calling card of a writer of professional code.

By

Notes on Job Hopping Part 4: Free Agency

I’ve been very busy of late, so I had let this series slip a bit by the wayside. But I was taking a break from recording my Pluralsight course to sort of mindlessly read tweets when I noticed this one:

 

Juxtapositions as Outrage Factories

There is a fine line in life when it comes to juxtapositions. On one side of the line is genuine profundity, and on the other side is schmaltzy non sequitur and/or demagoguery. And I’d argue that the line is not entirely subjective, as it might seem. There is a Tupac Shakur lyric that is sort of raw and powerful that says, “they’ve got money for wars but can’t feed the poor.” If you’re a bleeding heart type, you’ll probably agree wholeheartedly. If you’re more of a pragmatist, you might say, “well, there are degrees of poverty and need, and what good is feeding people if some foreign entity is lobbing cruise missiles at them?” But you have to admit that he’s comparing apples to apples, so to speak. There is some finite pool of money, and some of that money is being spent on blowing one another up instead of feeding people that are hungry.

On the other side of this line of juxtaposition lie tiresome canards like “they can send a man to the moon but they can’t make a computer that doesn’t crash?!?” Yeah, because those are the same engineering problem. Or how about “a country can’t run a fiscal deficit because I don’t run my own budget that way at home with the groceries and the car payments!” Right, because macroeconomics is like your budget spreadsheet. And you also have the ability to print money to pay off your debts.

Back to the tweet. I think it sits right on the juxtaposition line. On the one hand, it seems to be sort of garden-variety line-employee populism (“pointy-haired bosses bad, knowledge workers good”) that ignores an important difference between athlete-coach and employee-manager — namely the inverted money and fame related power dynamic of athletes and coaches as compared to line employees and managers. LeBron James, not Erik Spoelstra, puts butts in seats and gets paid a king’s ransom, even if Spoelstra does theoretically call the shots. But it does raise an interesting question that isn’t the one that’s literally being asked (the answer to the tweet’s question being easy: managers make more money, have offices and get to boss people around).

Overvaluing Management

The interesting question that is raised is “why are line managers and other overhead personnel overvalued?” Let me say here that I’m not going to spend this post talking in much detail about that. I poured a lot of time and thought into it for the concluding part of my Expert Beginner E-Book, so I’ll summarize here by saying that there is a bit of a societal pyramid scheme that occurs when it comes to work. We collectively agree on a system where 20-somethings that are new to the workforce do all the grunt work for little pay and that, over the course of our careers, we accumulate vacation time, bigger salaries, larger desks and offices, and the ‘right’ to tell others what to do rather than doing it ourselves. We pat ourselves on the back for ‘earning’ it, but often that assessment is pretty questionable. It’s more a matter of waiting our turn.

Managers are overvalued in organizations because of a collective endorsement of the same kind of reasoning that drives social security — disproportionate dues paying now, followed by disproportionate dues receiving later. The entry level folks tolerate overvalued mid-level management either because they have no choice or because they someday want to be that overvalued mid-level management which is, of course, a fairly sweet deal once you get into the club.

But the overvaluation of management goes deeper than that and finds its real roots in the undervaluation of non-management. In other words, if the Product X Team, consisting of five knowledge workers and a line manager, delivers a spectacular and wildly profitable success, is this owed to the team or to the manager? I’d say that, in a very real way, this is comparable to sports teams in that a good manager will account for some variance and some wins here and there by managing egos, strategizing and motivating, but at the end of the day no one is going to manage a hopelessly underqualified team into serious contention. But, unlike sports teams, the spotlight in the corporate world often falls onto the manager because the manager is in a position to seize it and because it’s simply easier to give credit to the “leader” than to parcel it out in equal portions to the team.

So why do young athletes aspire to be LeBron James and not Eric Spoelstra while young academics want to be the boss rather than the inventor? Because Steve Jobs. Because Warren Buffet. Because bosses, like athletes, represent the competitive pinnacle. It’s really the same thing in the end — a desire to dominate. Athletes, CEOs and, to a lesser extent, line managers, have gotten to where they are by defeating foes in direct competition, and that’s appealing to children in an environment where peer competition is natural and amplified (grade school).

Positive Sum Makers

The overvaluation of managers (and athletes, actually) is a zero-sum outlook on the world. You become a success by competing against others and causing them to fail. There are winners and losers and the glory lies in being a winner in this game. But there is another avenue, which is that taken by who I’d call the Inventor or the Maker — the positive sum player. Makers (and I use this umbrella to describe the overwhelming majority of line-level programmers as well as engineers and other people who produce work product) shine by making the world a better place for all. They transmute their creativity and ambition into products and services that improve the standard of living and better people’s lives. There doesn’t need to be a loser in this game for the Maker to be a winner.

Make no mistake — there is certainly competition among Makers. But it is a healthy, positive sum competition. They compete against one another and themselves to invent great things, to do it quickly, and to do it well. I may want to be the best programmer on earth and that desire may drive me to some late nights hitting the books and cranking out code, but I can produce helpful things without “defeating” some other programmer in some kind of game or competition for position.

The interplay between Makers and what I’ll call Competitors has historically been an uneasy balance. In the time before widespread knowledge workers in corporations, you had the mad-scientist/inventor archetype as your Makers: the Edisons and Teslas of the world. Then with the technological growth of the 20th century, the Makers were kind of funneled into working as Organization Man where they went from being valued professionals in the 50s to eventually being Dilbert in more recent times — toiling under the inept stewardship of a pointy haired boss that also happened to be a marginally victorious Competitor.

Makers were in a difficult position, as they really just wanted to make. Working your way up the corporate ladder as Competitor requires stopping Making and engaging in zero sum gamesmanship that doesn’t interest that archetype, but not doing so meant obeying the micromanaging and often incompetent Competitors and having the fun sucked out of the act of making. Finding organizations that got this right has become so rare that places like Valve and Github are the stuff of legends. Historically, Makers could try going off on their own, but that meant giving up a lot of the Making as well, since they’d then have to worry about their own sales, marketing, accounting, etc.

But the Makers are going to have the last laugh.

“Developernomics”

For Makers that happen to be software developers, times are pretty good, and they’ve been pretty good for years. Most developers complain about how annoying it is that recruiters won’t stop calling them to try to get them to go to interviews for jobs that will pay them more money. Let me repeat that. Developers complain that companies won’t leave them alone when it comes to offering them work. The reason that this is happening is that the demand for programming is absolutely exploding as we transition into a world where the juggernaut of endless automation has finally lurched up to ramming speed and is methodically wiping out other types of jobs at an unbelievable rate. Quite simply, they days of any company not being a “software company” are drawing to a close, as described in an article entitled “Developernomics.

Flush with opportunities, developer job hopping is accelerating rapidly. Companies are ceasing to bother with asking developers why their resumes feature so much job hopping — they’re so hard up for programmers that they don’t bother to ask. More and more, developers are seizing on any excuse or any annoyance to fly the coop and go work on something else. This might be organizational stupidities, but it also might simply be something like “I’m tired of C# and want to try out Ruby for a while.” The mobility within the job market for developers is pretty much unprecedented for a Maker position.

In fact, it’s starting to look a lot more like another type of profession that is also not zero sum: high skill jobs for which there is virtually inelastic demand. Two that come to mind are doctors and lawyers. As long as the world has sick people it needs doctors, and as long as there are disputes (and lawyers making laws requiring lawyers for things), it needs lawyers (at least until the automation juggernaut automates both of these professions — I put an upper bound of 50 years on the full automation of the medical profession making human doctors obsolete). Both doctors and lawyers have a different sort of work model than most Competitors and Makers. They get a lot of education and then they start their own practices, band together in small groups, or join a large existing practice. But whichever option they choose, their affiliations tend to be very fluid and their ability to work for themselves almost a given, if they so choose.

Let’s stop for a second now. These high skill knowledge workers are highly in demand, have a great deal of fluidity in their working relationships and association, and often work for themselves. Doesn’t that sound familiar? Doesn’t it sound like software these days where some people freelance, some people bounce around among startups, and others just job hop between larger corporations to get themselves promoted and paid quickly? And doesn’t it seem like more and more developers are working at shops that are just software development consultancies? Isn’t it starting to seem like the question shouldn’t be “is job hopping okay,” but rather be “for how much longer are we going to bother with typical corporate jobs from which to hop?”

I think the handwriting is on the wall for the future of software development. I think that we’re careening toward a future where developers working for corporations for any length of time is such an anachronism that it isn’t considered a serious possibility. Developers aren’t going to job hop at all because they won’t have traditional corporate jobs. Due to increased globalization, networking, and interconnectivity, developers have sort of a de facto guild — their association with the global network of developers. Promotion, marketing, sales, and even some other aspects of managing one’s own consultancies are collectivized to a degree as developers have a network of friends to help them with such things. They often become moot points because who needs to bother with sales and marketing when business is banging down your door already?

So to return to the sports world and metaphor that started all of this, I’d say the future of developers doesn’t involve an ebb in “job hopping” but rather the opposite: a codified establishment of extreme job hopping as the status quo. Developers are going to become free agents like athletes who drift from team to team as their title aspirations and salary negotiations dictate. Like mercenary athletes, developers are not especially interested in things like culture, domain knowledge, corporate slogans and mission statements and all of that company man, corporate identity stuff. They’re interested in challenging projects, learning, making a few bucks and heading out to the next gig. In a previous post in this series, I had said the answer to the question “should I job hop” is “probably.” In the future, I think the answer to this question for developers will be another question: “uh, as opposed to what?”

By

Good Magic and Bad Magic

Not too long ago, I was working with a web development framework that I had inherited on a project, and I was struggling mightily with it to get it to work. The functionality was not discoverable at all, and it was provided almost exclusively via inheritance rather than composition. Runtime debugging was similarly fruitless, as a great deal of functionality was obfuscated via heavy use of reflection and a lot “squishing” of the application to fit into a forms over data paradigm (binding the GUI right to data sources, for instance). Generally, you would find some kind of prototype class/form to look at, try to adapt it to what you were doing and struggle for a few hours before reverse engineering the fact that you weren’t setting some random property defined in an ancestor class properly. Until you set this string property to “asdffdsa,” absolutely nothing would work. When you finally figured out the answer, the reaction wasn’t one of triumph but indignation. “Really?!? That’s what just ate the last two hours of my life?!?”

I remember a different sort of experience when I started working Web API. With that technology, I frequently found myself thinking things like “this seems like it should work,” and then, lo and behold, it did. In other words, I’d write a bit of code or give something a name that I figured would make sense in context, and things just kind of magically worked. It was a pretty heady feeling, and comparing these two experiences is a study in contrast.

One might say that this a matter of convention and configuration. After all, having to set some weird, non-discoverable string property is really configuration, and a lot of the newer web frameworks, Web API included, rely heavily on convention. But I think it goes beyond that and into the concepts that I’ll call “good and bad magic.” And the reason I say it’s not the same is that one could pretty easily establish non-intuitive conventions and have extremely clear, logical configurations.

When I talk about “magic,” I’m talking about things in a code base or application behind the scenes. This is “magic” in the sense that you can’t spell “automagically” without “magic.” In a MVC or Web API application, the routing conventions and ways that views and controllers are selected are magic. You create FooController and FooView in the right places, and suddenly, when you navigate to app/Foo, things just work. If you want to customize and change things, you can, but it’s not a battle. By default, it does what it seems like it ought to do. The dark side of is the application I described in the first paragraph — the one in which all of the other classes were working because of some obscure setting of a cryptically named property defined in a base class. When you define your own class, everything blows up because you’re not setting this property. It seems like a class should just work, but due to some hidden hocus-pocus, it actually doesn’t.

The reason I mention all this is to offer some advice based on my own experience. When you’re writing code for other developers (and you almost always are because, sooner or later, someone besides you will be maintaining your code or invoking it), think about whether your code hides some magic from others. This will most likely be the case if you’re writing framework or utility code, but it can always apply. If your code is, in fact, doing things that will seem magical to others, ask yourself if it’s good magic or bad magic. A good way to answer this question for yourself is to ask yourself how likely you think it will be that you’ll need to explain what’s going on to people that use your code. If you find yourself thinking, “oh, yeah, they’ll need some help — maybe even an instruction manual,” you’re forcing bad magic on them. If you find yourself thinking, “if they do industry standard things, they’ll figure it out,” you might be in good shape.

I say you might be in good shape because it’s possible you think others will understand it, but they won’t. This comes with practice, and good magic is hard. Bad magic is depressingly easy. So if you’re going to do some magic for your collaborators, make sure it’s good magic because no magic at all is better than bad magic.

By

Beware of Mindless Automation

Something I’ve seen a lot over the years is a tendency to locally maximize when it comes to automating processes. We’re software developers, and thus automation is what we do. But not all automation is created equally, and some of it can be fairly obtuse and misguided if we aren’t careful. And the worst part is that it’s pretty easy to fall into this trap.

For example, let’s say that you observe some people in your organization following a process. They have some Microsoft Word template that they’ve stored somewhere and they regularly open it up and fill it out with data that they pull from an internal system. They populate things like today’s date and various data points and then they do some light formatting based upon various criteria, such as putting items in red if they fall below a certain threshold. When finished, they print out the result, drop it in an envelope, and mail it to another office location of the company. At that location, they process the data and put it into the system — you don’t know too much about that system because it’s not your office location, but that’s the general gist of it.

So, what do you do if you have some spare time and empathy for manual process on your hands and are looking to make a name for yourself? Do you automate this process for them, to their many thanks and heaped praise? And, assuming you do, how do you do it? Do you write some code that pulls the necessary data from your internal system, fires up MS Word interop, and starts automatically generating the documents they’re using? Then, flush with success from that project, do you also automate the printing of the envelopes and metering of the postage?

If you do, how does that go as a function of time? I bet the users are very grateful at first, but then they come to rely on it. And, what’s more, they like the system less and less over the course of time. Every time the USPS changes the price of postage you have to go into this system and made changes, and, what’s worse is that the part that generates the documents seems to break every time there’s a new version or even an update to Word. And when the format of the documents that the other office is requesting changes, suddenly you’ve got a real project on your hands, since automating intricate, form Word documents is about as much fun as spending the afternoon trying to cram a decade of your life onto a one-page resume. Wasn’t this supposed to be helpful? Weren’t you the hero? Does no good deed go unpunished?

Let’s go back to the point where you decided to help. Was the automation as you conceived it worth doing or was it sort of marginal? I mean, you’re probably saving a few minutes for people and some fat-fingering opportunities, but what you still have is sort of an involved, manual process. What if you had stopped to think about the process and the larger goal: getting data from one system into another? Might you not have been talking about things like “web service” or at least “file transfer” instead of things like “Word interop” and “postage?”

Here’s the rub. When your users are solving your problems, they think like users and not like software developers. As such, they come up with non-programming, user solutions. Normal computer users understand MS Word and sending things via mail (or at least email), so they come up with processes that feature those tools. You’re a programmer. By all means, automate, but don’t mindlessly automate whatever they happen to be doing. That’s an optimization tweak. Real software engineering is about using software to create simple solutions to problems. I’ve seen many people fall into this trap and have fallen into it myself. When you’re writing software, asking “why” is invariably more important than asking “how.”

By

Defining Done for Your Deployment Process

A Tale of Debugging

The other day, someone came to me and told me that a component of one of the web applications that my team maintains seemed to have a problem. I sat with her, and she showed me what was going on. Sure enough, I saw the issue too. It was the kind of integration thing for which we were able to muster up some historical record and see approximately when the problem had started. Apparently, the problem first occurred around the last time we pushed a version of the website into production. Ruh roh.

scooby

Given that this was a pretty critical issue, I got right down to debugging. Pretty quickly, I found the place in the code where the integration callout was happening, and I stepped through it in the debugger. (As an aside, I realize I’ve often made the case against much debugger use. But when legacy code has no unit, component or integration tests, you really don’t have a lot of options.) No exceptions were thrown, and no obvious problems were occurring. It just hit a third party API, went through it uneventfully, but quietly failed.

At this point, it was time for some tinkering and reverse engineering. When I looked at the method call that seemed to be the meat of the issue, I noticed that it returned an integer that the code I was debugging just ignored. Hovering over it, XML doc comment engine told me that it was returning an error code. I would have preferred an exception, but whatever — this was progress. Unfortunately, that was all the help I got, and there was no indication what any returned error code meant. I ran the code and saw that I was getting a “2,” so presumably there was an error occurring.

Maddeningly, there was no online documentation of this API. The only way I was able to proceed was to install a trial version of this utility locally, on my desktop, and read the CHM file. They offered one through their website, but it was broken. After digging, I found that this error code meant “call failure or license file missing.” Hmm… license file, eh? I started to get that tiny adrenaline rush that you get when a solution seems like it might be just around the corner. I had just replaced the previous deployment process of “copy over the files that are different to the server” with a slightly less icky “wipe the server’s directory and put our stuff there.” It had taken some time to iron out failures and bring all of the dependencies under source control, but I viewed this as antiseptic on a festering sore. And, apparently, I had missed one. Upon diving further into the documentation, I saw that it required some weirdly-named license file with some kind of key in it to be in the web application root’s “bin” folder on the server, or it would just quietly fail. Awesome.

This was confirmed by going back to a historical archive of the site, finding that weird file, putting it into production and observing that the problem was resolved. So time to call it a day, right?

Fixing the Deeper Issue

Well, if you call it a day now, there’s a good chance this will happen again later. After all, the only thing that will prevent this after the next deployment is someone remembering, “oh, yeah, we have to copy over that weird license file thing into that directory from the previous deploy.” I don’t know about you, but I don’t really want important system functionality hinging on “oh, yeah, that thing!”

What about a big, fat comment in the code? Something like “this method call will fail if license file xyz isn’t in abc directory?” Well, in a year when everyone has forgotten this and there’s a new architect in town, that’ll at least save a headache next time this issue occurs. But this is reactionary. It has the advantage of not being purely tribal knowledge, but it doesn’t preemptively solve the problem. Another idea might be to trap error codes and throw an exception with a descriptive message, but this is just another step in making the gap between failure and resolution a shorter one. I think we should try avoid failing at all, though having comments and better error trapping is certainly a good idea in addition to whatever better solution comes next.

What about checking the license file into source control and designing the build to copy it to that directory? Win, right? Well, right — it solves the problem. With the next deploy, the license file will be on the server, and that means this particular issue won’t occur in the future. So now it must be time to call it day, right?

Still no, I’d argue. There’s work to be done, and it’s not easy or quick work. Because what needs to happen now is a move from a “delete the contents of the server directory and unzip the new deliverable” deployment to an automated build and deployment. What also needs to happen is a series of automated acceptance tests in a staging environment and possibly regression tests in a production environment. In this situation, not only are developers reading the code aware of the dependency on that license file, not only do failures happen quickly and obviously, and not only is the license file deployed to where it needs to go, but if anything ever goes wrong, automated notifications will occur immediately and allow the situation to be corrected.

It may seem pretty intense to set all that up, but it’s the responsible thing to do. Along the spectrum of some “deployment maturity model,” tweaking things on the server and forgetting about it is whatever score is “least mature.” What I’m talking about is “most mature.” Will it take some doing to get there and probably some time? Absolutely. Does that mean that anything less can be good enough? Nope. Not in my opinion, anyway.