Stories about Software


What Is a Best Practice in Software Development?

(Editorial Note: Hello, Code Project, folks and thanks for stopping by! I’m really excited about the buzz around this post, but an unintended consequence of the sudden popularity is that so many people have signed up that I’ve run out of Pluralsight trial cards. Please still feel free to sign up for the mailing list, but understand that it may be a week or so before I can get you a signup code for the 30 day trial. I will definitely send it out to you, though, when I get more. If you’d like to sign up for a 10 day trial, here is a link to the signup that’s also under my courses on the right.)

A while ago, I released a course on Pluralsight entitled, “Making the Business Case for Best Practices.”  (If you want to check it out, but don’t have a Pluralsight account, sign up for my mailing list in the side bar to the right and I’ll send you a free 30 day subscription).  There was an element of tongue-in-cheek to the title, which might not necessarily have been the best idea in a medium where my profitability is tied to maximizing the attractiveness of the title.  But, life is more fun if you’re smiling.

Anyway, the reason it was a bit tongue in cheek is that I find the term “best practice” to be spurious in many contexts.  At best, it’s vague, subjective, and highly context dependent.  The aim of the course was, essentially, to say, “hey, if you think that your team should be adopting practice X, you’d better figure out how to make a dollars and cents case for it to management — ‘best’ practices are the ones that are profitable.”  So, I thought I’d offer up a transcript from the introductory module of the course, in which I go into more detail about this term.  The first module, in fact, is called “What is a ‘Best Practice’ Anyway?”

Best Practice: The Ideal, Real and Cynical

The first definition that I’ll offer for “best practice” is what one might describe as the “official” version, but I’ll refer to it as the “ideal version.”  Wikipedia defines it as, “method or technique that has consistently shown results superior to those achieved with other means, and that is used as a benchmark.”  In other words, a “best practice” is a practice that has been somehow empirically proven to be the best.  As an example, if there were three possible ways to prepare chicken: serve it raw, serve it rare, and serve it fully cooked, fully cooked would emerge as a best practice as measured by the number of incidents of death and illness.  The reason that I call this definition “ideal” is that it implies that there is clearly a single best way to do something, and real life is rarely that neat.  Take the chicken example.  Cooked is better than undercooked, but there is no shortage of ways to fully cook a chicken – you can grill it, broil it, bake it, fry it, etc.  Is one of these somehow empirically “best” or does it become a matter of preference and opinion?


Read More


Avoiding the Perfect Design

One of the peculiar ironies that I’ve discovered by watching the way a lot of different software shops work is that the most intense moments of exuberance about software seem to occur in places where software development happens at glacial speeds. If you walk into an agile shop or a startup or some kind of dink-and-dunk place that bangs out little CRUD apps, you’ll hear things like, “hey, a user said she thought it’d be cool if she could search her order history by purchase type, so let’s throw that in and see how it goes.” If it goes insanely well, there may be celebrations and congratulations and even bonuses changing hands which, to be sure, makes people happy. But their happiness is Mercury next to the blazing Sun of an ivory tower architect describing what a system SHALL do.

“There will be an enterprise service bus. That almost goes without saying. The presentation tier and the business tier will be entirely independent of one another, and literally any sort of pluggable module that you dream up as a client can communicate with any sort of rules engine embedded within the business tier. Neither one will EVER know about the other’s existence. The presentation layer collaborators are like Schrodinger and the decision engines are like the cat!

And the clients. Oh yes, there will be clients. The main presentation tier client is a mobile staging environment that will be consumed by Android, iOS, Windows Phone, Blackberry, and even some modified Motorolla walkie-talkies. On top of the mobile staging environment will be a service adapter that makes it so that clients don’t need to worry about whether they’re using SOAP or REST or whatever comes next. All of those implementations will hide behind the interface. And that’s just the mobile space. There are more layers and subtleties in the browser and desktop spaces, since both of those types of clients may be SPAs, other thick clients, thin clients, or just leaf nodes.

Wait, wait, wait, I’m not finished. I haven’t even told you about the persistence factories yet and my method for getting around the CAP theorem. The performance will be sublime. We’re talking picoseconds. We’re going to be using dynamically generated linear programming algorithms to load balance the vertical requests among the tiers, and we’re going to take a page out of the quantum computing book to introduce a new kind of three state boolean… oh, sorry, you had a question?”

“Uh, yeah. Why? I mean, who is going to use this thing and what do they want with it?”

“Everyone. For everything. Forever.”

You back out slowly as the gleam in his eye turns slightly worrisome and he starts talking about the five year plan that involves this thing, let’s call it HAL, achieving sentience, bringing humankind to the cusp of the singularity, and uploading the consciousnesses of all network and enterprise architects.


Like I said, the Sun to your Mercury. Has your puny startup ever passed the Turing Test? Well, his system has… as spec’ed out in a document management system with 8,430 pages of design documents and a Visio diagram that’s rumored to have similar effects to the Ark of the Covenant. And that, my friends, is why I think that a failing ATDD scenario should be the absolute first thing anyone who says, “I want to get into programming” learns to do.

Now to justify that whiplash-inducing segue. I wrote a book about unit testing in which I counseled complete initiates to automated testing to forgo TDD and settle for understanding the mechanics of automated tests and test runners first before making the leap. I stand by that advice, but I do so because I think that there is a subtle flaw to the way that most people currently get started down the programming path.

I was watching a Pluralsight course about NUnit to brush up on their latest and greatest assertion semantics, and the examples were really well done. In particular, there was a series of assertions oriented around a rudimentary concept of a role playing game with enumerations of weapons, randomization of events, and hit points. This theme exercised concepts like ranges, variance, collection cardinality, etc and it did so in a way that lent itself to an easy mental model. The approach was very much what mine would have been as well (I wouldn’t have come at this with TDD because there’d have been a lot of ‘downtime’ writing the production code as opposed to just showing the assert methods).

Nevertheless, it’s been a while since I’ve watched someone write tests against a pre-baked system when they weren’t characterization tests in a legacy rescue, and the experience was sort of jarring. I couldn’t help but think, “I wouldn’t want to write these tests if I were in his position — why bother when the code is already done?” Weird as it sounds from a big advocate of testing, writing tests after you’ve completed your implementation feels like a serious case of “going through the motions” in the same way that developers fill out random “SDLC” artifacts for no other purpose than to get PMPs to leave them alone.

And that’s where the connection to the singularity architect comes in. One of the really nice, but subtle perks of the TDD (especially ATDD) approach is that it forces you to define exit criteria before you start doing things. For instance, “I know I’ll be done with this development effort when my user can search her order history by purchase type.” Awesome — you’re well on your way because you’ve (presumably) agreed with stakeholders ahead of time when you can stop coding and declare victory. The next thing is to prove it, and you can approach this in the same way that you might approach fixing a leaking pipe under your sink. Turn the water on, observe the leak, turn the water off, fix the leak, turn the water back on, observe that there is no leak. Done.

In the case of the search, you write a client call to your web service that supplies a “purchase type” parameter and you say that you’re done when you get a known result set back, instead of the current error message: “I do not understand this ‘purchase type’ nonsense you’ve sent — 400 for you!” Then you scurry off to code, and you just keep going until that test that you’ve written turns green and all of the other ones stay green. There. Done, and you can prove it. Ship it.

Our poor architect never knows when he’s done (and we know he’ll never be done). The origin of this Sisyphean struggle started with hobby programming or a CS degree or something. It started with unbounded goals and the kinds of open-ended tasks that allow hobbyists to grow and students to excel. Alright, you’ve got the A, but try to play with it. See if you can make it faster. Try adding features to it. Extra credit! Sky’s the limit! At some point, a cultural norm emerges that says it’s more about the journey than the destination. And then you don’t rise through the ranks by automating for the sake of solving people’s problems but rather by building ever-more impressive juggernauts, leveraging the latest frameworks, instrumented with the most analytics, and optimized to run in O(Planck Time).

I really would like to see initiates to the industry learn to set achievable (but slightly uncomfortable) goals with a notion of value and then reach them. Set a beneficial goal, reach it, rinse, repeat. The goal could be “I want to learn Ruby and I’ll consider a utility that sorts picture files to be a good first step.” You’re adding to your skill set as a developer and you have an exit criteria It could be something for a personal project, a pro-bono client, or for pay. But tie it back to an outcome and assess whether that outcome is worthwhile. This approach will prevent you from shaving microseconds off of an app that runs overnight on a headless server and it will prevent you from introducing random complexity and dependency to an app because you wanted to learn SnazzyButPointless.js. True, the approach will stop you from ever delighting in design documents that promise the birth of true artificial intelligence, but it will also prevent you from experiencing the dejection when you realize it ain’t ever gonna happen.


You Want an Estimate? Give Me Odds.

I was asked recently in a comment what I thought about the “No Estimates Movement.” In the interests of full disclosure, what I thought was, “I kinda remember that hashtag.” Well, almost. Coincidentally, when the comment was written to my blog, I had just recently seen a friend reading this post and had read part of it myself. That was actually the point at which I thought, “I remember that hashtag.”

That sounds kind of flippant, but that’s really all that I remember about it. I think it was something like early 2014 or late 2013 when I saw that term bandied about in my feed, and I went and read a bit about it, but it didn’t really stick with me. I’ve now gone back and read a bit about it, and I think that’s because it’s not really a marketing teaser of a term, but quite literally what it advertises. “Hey, let’s not make estimates.” My thought at the time was probably just, “yeah, that sounds good, and I already try to minimize the amount of BS I spew forth, so this isn’t really a big deal for me.” Reading back some time later, I’m looking for deeper meaning and not really finding it.

Oh, there are certainly some different and interesting opinions floating around, but it really seems to be more bike-sheddy squabbling than anything else. It’s arguments like, “I’m not saying you shouldn’t size cards in your backlog — just that you shouldn’t estimate your sprint velocity” or “You don’t need to estimate if all of your story cards are broken into small enough chunks to be ones.” Those seem sufficiently tactical that their wisdom probably doesn’t extend too far beyond a single team before flirting with unknowable speculation that’d be better verified with experiments than taken as wisdom.

The broader question, “should I provide speculative estimates about software completion timelines,” seems like one that should be answered most honestly with “not unless you’re giving me pretty good odds.” That probably seems like an odd answer, so let me elaborate. I’m a pretty knowledgeable football fan and each year I watch preseason games and form opinions about what will unfold in the regular season. I play fantasy football, and tend to do pretty well at that, actually placing in the money more often than not. That, sort of by definition, makes me better than average (at least for the leagues that I’m in). And yet, I make really terrible predictions about what’s going to happen during the season.


At the beginning of this season, for instance, I predicted that the Bears were going to win their division (may have been something of a homer pick, but there it is). The Bears. The 5-11 Bears, who were outscored by the Packers something like 84-3 in the first half of a game and who have proceeded to fire everyone in their organization. I’m a knowledgeable football fan, and I predicted that the Bears would be playing in January. I predicted this, but I didn’t bet on it. And, I wouldn’t have bet even money on it. If you’d have said to me, “predict this year’s NFC North Division winner,” I would have asked what odds you were giving on the Bears, and might have thrown down a $25 bet if you were giving 4:1 odds. I would have said, when asked to place that bet, “not unless you’re giving me pretty good odds.”

Like football, software is a field in which I also consider myself pretty knowledgeable. And, like football, if you ask me to bet on some specific outcome six months from now, you’d better offer me pretty good odds to get me to play a sucker’s game like that. It’d be fun to say that to some PMP asking you to estimate how long it would take you to make “our next gen mobile app.” “So, ballpark, what are we talking? Three months? Five?” Just look at him deadpan and say, “I’ll bite on 5 months if you give me 7:2 odds.” When he asks you what on earth you mean, just patiently explain that your estimate is 5 months, but if you actually manage to hit that number, he has to pay you 3.5 times the price you originally agreed on (or 3.5 times your salary if you’re at a product/service company, or maybe bump your equity by 3.5 times if it’s a startup).

See, here’s the thing. That’s how Vegas handles SWAGs, and Vegas does a pretty good job of profiting from the predictions racket. They don’t say, “hey, why don’t you tell us who’s going to win the Super Bowl, Erik, and we’ll just adjust our entire plan accordingly.”

So, “no estimates?” Yeah, ideally. But the thing is, people are going to ask for them anyway, and it’s not always practical to engage in a stoic refusal. You could politely refuse and describe the Cone of Uncertainty. Or you could point out that measuring sprint velocity with Scrum and extrapolating sized stories in the backlog is more of an empirically based approach. But those things and others like them tend not to hit home when you’re confronted with wheedling stakeholders looking to justify budgets or plans for trade shows. So, maybe when they ask you for this kind of estimate, tell them that you’ll give them their estimate when they tell you who is going to win next year’s super bowl so that you can bet your life savings on their guarantee estimate. When they blink at you dubiously, smile, and say, “exactly.”


Is This Problem Worth Solving?

I’ve done a little bit of work lately on a utility that reads from log files that are generated over the course of a month. Probably about 98% of the time, users would only be interested in this month’s file and last month’s file. How should I handle this?

At different points in my career, I’d have answered this question differently. Early on, my answer would have been to ignore the sentence about “98% of the time” and just implement a solution wherein the user had to pick which file or files he wanted. For a lot of my career, I would have written the utility to read this month and last month’s files by default and to take an optional command line parameter to specify a different file to read (“sensible defaults”). These days, my inclination is more toward just writing it to read this month’s and last month’s file, shipping it, and seeing if anyone complains — seeing if that 2% is really 2% or if, maybe, it’s actually 0%.

Part of this evolution in me was the evolution of the software industry itself. When I started out doing a lot of C and C++ in the Linux/Unix worlds, gigantic documents and users’ manuals were the norm. If you were a programmer, it was your responsibility to write massive, sprawling APIs and if you used someone’s code, it was your responsibility to use those massive APIs and read those gigantic manuals. So, who cares what percentage of time a user might do what? You just write everything that could ever possibly happen into your code and then tell everyone to go read the manual.

Then things started to get a little more “agile” and YAGNI started to prevail. On top of that, the user became more of a first class citizen, so “let’s default to the most common path” became the attractive thing to do and “RTFM” went the way of the dodo. The iconic example would be a mid 2000’s Windows or web application that would give you a sensible experience and then offer a dizzying array of features in some “Advanced Settings” window.

The next step was born with the release of the iPhone when it started to become acceptable and then normal to write dead simple things that didn’t purport to do everything. Apple’s lead here was, “this is the app, this is what it does, take it or leave it.” The “advanced settings” window was replaced by “we’ll tell you what settings you want,” which requires no window.

This shifting environment over the last 15 years informed my perspective but wasn’t entirely responsible for it. I’d say what was responsible for the shift were two realizations. First, I realized, “a ‘business spec’ isn’t nearly as important as understanding your users, their goals, and how they will use what you give them.” It became important to understand that one particular use case was so dominant that making it a pleasant experience at the cost of making another experience less pleasant was clearly worthwhile. The second realization came years later, when I learned that your users do, frequently, want you to tell them how to use your stuff.

Some of this opinion arose from spending good bits of time in a consulting capacity, where pointing out problems and offering a handful of solutions typically results in, “well, you’re the expert — which one should I do?” You hear that enough and you start saying instead, “here’s a problem I’ve noticed and here’s how I’ve had success in the past fixing this problem.” It makes sense when you think about it. Imagine having someone out to fix your HVAC system and he offers you 4 possible solutions. You might ask a bit about cost/benefit and pros/cons, but what you’ll probably wind up saying is, “so…. what would you do and/or what should I do?”


There’s an elegance to coding up what a user will do 98% of the time and just shipping that, crude as it sounds. As I mentioned, it will confirm whether your “98%” estimate was actually accurate. But, more importantly, you’ll get a solution for 98% of the problem to market pretty quickly, letting the customer realize the overwhelming majority of ROI right away. On top of that, you’ll also not spend a bunch of money chasing the 2% case up front before knowing for sure what the impact of not having it will be. And finally, you add the possibility for a money-saving work-around. If the utility always reads this month’s and last month’s files, and we need to read one from a year ago… rather than writing a bunch of code for that… why not just rename the file from a year ago and run it? That’ll cost your client 10 seconds per occurrence (and these occurrences are rare, remember) rather than hundreds or thousands of dollars in billable work as you handle all sorts of edge cases around date/time validation, command line args, etc.

I always wince a little when I offer anecdotes of the form, “when I was younger, I had position X but I’ve come to have position Y” because it introduces a subtle fallacy of “when you get wiser like me, you’ll see that you’re wrong and I’m right.” But in this case, the point wasn’t to discredit my old ways of thinking, per se, but rather to explain how past experiences have guided the change in my approach. I’ve actually stumbled a fair bit into this, rather than arrived here with a lot of careful deliberation. You see, there were a lot of times that I completely whiffed on considering the 2% case at all and just shipped, realizing to my horror only after the fact that I’d forgotten something. Bracing for getting reamed as soon as someone figured out that I’d overlooked the 2% case, I battened down the hatches and prepared to face the fire only to face… absolutely nothing. No one noticed or cared, and the time spent on the 2% would have been a total waste.

So next time you find yourself thinking about how to handle some bizarre edge case or unlikely scenario, pull back and ask yourself whether handling that is worth delaying the normal cases or not. Ask yourself if your user can live with a gap in the edge case or work-around it. And really, ask yourself what the ROI for implementation looks like. This last exercise, more so than learning any particular framework, language or library, is what distinguishes a problem solver from a code slinger.


Flexibility vs Simplicity? Why Not Both?

Don’t hard code file paths in your application. If you have some log file that it’s writing to or some XML file that it’s reading, there’s a well established pattern for how to keep track of the paths of those files: an external configuration scheme. This might be a .config file or a settings.xml file or even a yourapp.ini file if you’re gray enough in the beard. Or, perhaps it’s something more exotic like a database table or web service that stores key value configuration pairs. Maybe it’s something as simple as command line parameters that specify the path. Whatever the case may be, everyone knows that you don’t hard code — you don’t store the file path right in the source code. That’s amateur hour.

You can imagine how this began. Maybe a long time ago someone said, “hey, let’s log critical application events to a file so that we can review and troubleshoot if things go wrong.” They shipped this for some machine running Windows 3.1 or something, and were logging to C:\temp, which was fine unless users didn’t have a C:\temp directory. In that case, it blew up spectacularly and they were flooded with support calls at which point, they could tell their users to create the directory or they could ship a new set of floppy disks with the new source code, amended to log to a directory guaranteed to exist. Or something like that, anyway.

The lesson couldn’t be more obvious. If they had just thought ahead, they would have realized their choice for the path of the log file, which isn’t even critical anyway, was a poor one. It would have been good if they had chosen better, but it would have been almost as good if they’d just made this configurable somehow so that it needn’t be a disaster. They could have made the path configurable or they could have just made it a configurable option to create C:\temp if it didn’t exist. Next time, they’d do better by building flexibility into the application. They’d create a scheme where the application was flexible and thus the cost of not getting configuration settings right up-front was dramatically reduced.

This approach made sense and it became the norm. User settings and preferences would be treated as data, which would make it easy to create a default experience but to allow users to customize it if they were sufficiently sophisticated. And the predecessor to the “Advanced” menu tab was born. But the other thing that was born was subtle complexity, both for the users and for the programmers. Application configurability is second nature to us now (e.g. the .NET .config file), but make no mistake — it is a source of complexity even if you’re completely used to it. Think of paying $300 per month for all of your different telco concerns — the fact that you’ve been doing this for years does’t mean you’re not shelling out a ton of money.

What’s even more insidious is how this mentality has crept into application development in other ways. Notice that I called this practice “preferences as data” rather than “future-proofing,” but “future-proofing” is the lesson that many took away. If you design your application to be flexible enough, you can insulate yourself against bad initial guesses about user preferences or usage scenarios and you can ensure that the right set of tweaks, configuration alterations, and hacks will allow users to achieve what they want without you needing to re-deploy.

So, what’s the problem, apart from a huge growth in the number of available settings in a config file? I’d argue that the problem is the subtle one of striving for configurability as a first class goal. Rather than express this in general, definition-oriented terms, consider an example that may be the logical conclusion to take this thinking as far as it will go. You have some method that you expose publicly, called, ProcessOrder and it takes a parameter. Contrary to what you might think, the parameter isn’t an order ID and it isn’t an order: it’s an object. Why? Because this API is endlessly flexible. The method signature will suffice even if the entire order processing mechanism changes and even if the structure of the order itself changes. Heck, it won’t need to be altered if you decide to alter ProcessOrder(object order) to send emails. Just pass in an “Email” object and add a check for typeof(Email) to ProcessOrder. Awesome, right?


Yeah, ugh. Flexibility run amok. It’d be easy to interpret my point thus far as “you need to find the balance between inflexibility/simplicity on one end and flexibility/complexity on the other.” But that’s a consultant answer at best, and a non-point at worst. It’s no great revelation that these tradeoffs exist or that it’d be ideal if you could understand which trait was more valuable in a given moment.

The interesting thing here is to consider the original problem — the one we’ve long since file away as settled. We shipped a piece of software with a setting that turned out to be a mistake, so what lesson do we take away from that? The lesson we did take away was that we should make mistakes less costly by adding a configurability out. But what if we made the mistake less costly by making rollouts of the software trivial and inexpensive? Imagine a hypothetical world where rollout didn’t mean shipping a bunch of shrink-wrapped boxes with floppy disks in them but rather a single mouse click and high confidence that everything would go well. If this were a reality, hard-coding a log file path wouldn’t really be a big deal because if that path turned out to be a problem, you could just alter that source code file, click a button, and correct the mistake. By introducing and adjusting a previously unconsidered variable, you’ve managed to achieve both simplicity and flexibility without having to trade one for the other.

The danger for software decision makers comes from creating designs with the goal of satisfying principles or interim goals rather than the goal of solving immediate business problems. For instance, the problem of hard-coding tends to arise from (generally inexperienced) software developers optimizing for their own understanding and making code as procedurally simple as possible — “hardcoding is good because I can see right where the file is going when I look at my code.” That’s not a reasonable business goal for the software. But the same problem occurs with developers automatically creating a config file for application settings — they’re following the principle of “flexibility” rather than thinking of what might make the most sense for their customers or their situation. And, of course, this also applies to the designer of the aforementioned “ProcessOrder(object)” API. Here the goal is “flexibility” rather than something tangible like “our users have expressed an interest in changing the structure of the Order object and we think this is a good idea and want to support them.”

Getting caught up in making your code conform to principles will not only result in potentially suboptimal design decisions — it will also stop you from considering previously unconsidered variables or situations. If you abide the principle “hard-coding is bad,” without ever revisiting it, you’re not likely to consider “what if we just made it not matter by making deployments trivial?” There is nothing wrong with principles; they make it easy to communicate concepts and lay the groundwork for making good decisions. But use them as tools to help you achieve your goals and not as your actual goals. Your goals should always be expressible as humans interacting with your software — not characteristics of the software.


The “Synthesize the Experts” Anti-Pattern

I have a relatively uncomplicated thought for this Wednesday and, as such, it should be a reasonably sized post. I’d like to address what I consider to be perhaps the most relatable and understandable anti-pattern that I’ve encountered in this field, and I call it the “Synthesize the Experts” anti-pattern. I’m able to empathize so intensely with its commission because (1) I’ve done it and (2) the mentality that drives it is the polar opposite of the mentality that results in the Expert Beginner. It arises from seeking to better yourself in a a vacuum of technical mentorship.

Let’s say that you hire on somewhere to write software for a small business and you’re pretty much a one-person show. From a skill development perspective, the worst thing you could possibly do is make it up as you go and assume that what you’re doing makes sense. In other words, the fact that you’re the least bad at software in your company doesn’t mean that you’re good at it or that you’re really delivering value to the business; it only means that it so happens that no one around can do a better job. Regardless of your skill level, developing software in a vacuum is going to hurt you because you’re not getting input and feedback and you’re learning only at the pace of evolutionary trial and error. If you assume that reaching some sort of equilibrium in this sense is mastery, you’re only compounding the problem.

But what if you’re aware of this limitation and you throw open the floodgates for external input? In other words, you’re alone and you know that better ways to do it exist, so you seek them out to the best of your ability. You read blog posts, follow prominent developers, watch videos from conferences, take online learning courses, etc. Absent a localized mentor or even partner, you seek unidirectional wisdom from outside sources. Certainly this is better than concluding that you’ve nailed it on your own, but there’s another problem brewing here.

Specifically, the risk you’re running is that you may be trying to synthesize from too many disparate and perhaps contradictory sources. Most of us go through secondary and primary education with a constant stream of textbooks that are more or less cut and dry matters of fact and cannon. The more Algebra and Geometry textbooks you read and complete exercises for, the better you’re going to get at Algebra and Geometry. But when you apply this same approach to lessons gleaned from the movers and shakers in the technosphere, things start to get weird, quickly.

To put a specific hypothetical to it, imagine you’ve just read an impassioned treatise from one person on why it’s a complete violation of OOP to have “property bag” classes (classes that have only accessors and mutators for fields and no substantive methods). That seems to make sense, but you’re having trouble reconciling it with a staunch proponent of layered architecture who says that you should only communicate between layers using interfaces and/or “DTO” classes, which are property bags. And, hey, don’t web services do most of their stuff with property bags… or something? Ugh…


But why ugh? If you’re trying to synthesize these opinions, you’re probably saying, “ugh” because you’ve figured out that your feeble brain can’t reconcile these concepts. They seem contradictory to you, but the experts must have them figured out and you’re just failing to incorporate them all elegantly. So what do you do? Well, perhaps you define some elaborate way to get all of your checked in classes to have data and behavior and, at runtime to communicate, they use an elaborate reflection scheme to build and emit, on the fly, property bag DTO classes for communication between layers and to satisfy any web service consumers. Maybe they do this by writing a text file to disk, invoking a compiler on it and calling into the resulting compiled product at runtime. Proud of this solution, you take to a Q&A forum to show how you’ve reconciled all of this in the most elegant way imaginable, and you’re met with virtual heckling and shaming from resident experts. Ugh… You failed again to make everyone happy, and in the process you’ve written code that seems to violate all common sense.

The problem here is the underlying assumption that you can treat any industry software developer’s opinion on architecture, even those of widely respected developers, as canonical. Statements like, “you shouldn’t have property bags” or “application layers should only communicate with property bags” aren’t the Pythagorean Theorem; they’re more comparable to accomplished artists saying, “right triangles suck and you shouldn’t use them when painting still lifes.” Imagine trying to learn to be a great artist by rounding up some of the most opinionated, passionate, and disruptive artists in the industry and trying to mash all of their “how to make great, provocative art” advice into one giant chimera of an approach. It’d be a disaster.

I’m not attempting a fatalistic/relativistic “no approach is better than any other” argument. Rather I’m saying that there is healthy disagreement among those considered experts in the industry about the finer points of how best to approach creating software. Trying to synthesize their opinionated guidance on how to approach software into one, single approach will tie you in knots because they are not operating from a place of universal agreement. So when you read what they’re saying and ask their advice, don’t read for Gospel truth. Read instead to cherry pick ideas that make sense to you, resonate with you, and advance your understanding.

So don’t try to synthesize the experts and extract a meeting that is the sum of all of the parts. You’re not a vacuum cleaner trying to suck every last particle off of the carpet; you’re a shopper at a bazaar, collecting ideas that will complement one another and look good, put together and arranged, when you get home. But whatever you do, don’t stop shopping — everything goes to Expert-Beginner land when you say, “nah, I’m good with what’s in my house.”


Opening Word is Software Development Fail

I’m going to perform a slight experiment on myself in this post. As I type this second sentence, I have only a general idea for a post in mind, and I’m going to go out on a limb and say that this will be a relatively short post. I won’t come back and edit this paragraph if it turns out not to be, however. I’ll just look stupid. I’m going meta here because my posting cadence has slipped and I’m going to aim to combat that by mixing in some relatively short posts that are quicker to write and read. I’ve tried this before, and it’s sort of like a yo-yo diet where I cut back for a bit and then just kind of bloat back out to where I was. Anywho…

Over the course of my career a fairly common thing that I’ve done at a new company is to set up a wiki for collaboration. Almost invariably, this wiki replaces or, at least, aims to replace a series of Word documents. It’s as though there’s some kind of knowledge collection progression that goes, “nothing, README, Word, Wiki (or, perhaps, Sharepoint),” and I make my home at an organization just long enough to say, “hey, there’s a better option than shared drive/source controlled Word documents.” Why is the next step better? Searchability, not needing that “version history” table at the top, sane linking, changing the emphasis to content over styling, etc.


But, I had a thought today that I’d been sort of missing the point all these years. It’s not that wiki isn’t good, by any means, as a collaboration tool, but it’s that I’m often using it to mitigate the symptoms rather than treat the illness. If, as a developer, you find yourself opening Word to document a process, you’ve failed. If you optimize by documenting in a wiki, you’re just failing in a more searchable, sophisticated, and open-source way (unless you use Sharepoint, and then not open-source and maybe not sophisticated… hiyo, just kidding, but kind of not kidding.)

Is this a harsh thing to say? Certainly. Could you argue that I’m link baiting once you hear what comes next? Probably. But I think there’s an element of truth if you allow yourself to de-stigmatize the word “failure” and interpret it without a value judgment. For instance, today, I failed at being someone with 10,000 RSS subscribers to my blog. It’s true, but not damning. Developers documenting things with Word fall into this same category. You’re failing when you do this, and what you’re failing to do is automate.

I’ve blogged about a similar line of thought with code comments in the past. Comments in method bodies are basically developers saying, “I’m going to punt on making this code expressive and just kinda cheat by explaining this mess in English.” So it goes on a broader level with Word documents. Why do you write Word documents, after all? It’s to explain how to setup your development environment or how to perform a deploy. Maybe it’s to document what needs to happen whenever you add a new feature to the code base or in the event that you need to rollback to a previous version of the application. Whatever it is, you’re faced with some kind of procedure and you declare, “there’s a precise sequence of instructions that needs to be executed, and, as a programmer, I’m going to write them in English and use the next poor sap that happens on them as the runtime interpreter.”

I mean, think about it. If your process is defined well enough to merit a series of numbered steps in a Word document, it’s probably defined well enough to automate. Now, it might be that it’d take you three months to automate and 30 minutes to make the Word document. It might be that there are steps you lack the authority or permission to automate (or even do). It might be that you’re making a user manual or API document. There are any number of practical reasons that you’re not some kind of failure as a person for cracking open Word and explaining how to do something with a computer. You’re not a failure, but you have failed. For whatever reason, you’ve failed to automate. So next time you find yourself reflexively starting Word to make some sort of “writeup” about a technical thing, pause and ask yourself, “would automation of this process be possible and worthwhile?” It might not be, but then again, you might be surprised to find that the answer is “yes.”


Rapid Fire Craftsmanship Tips

The last month has been something of a transitional time for me. I had been working out of my house for a handful of clients pretty much all summer, but now I’ve signed on for a longer term engagement out of state where I’m doing “craftsmanship coaching.” Basically, this involves the lesser-attended side of an agile transformation. There is no shortage of outfits that say, “hey, sign up with us, get a certification and learn how to have meetings differently,” but there does seem to be a shortage of outfits that say, “we’ll actually teach you how to write code in a way that makes delivering every couple of weeks more than a pipe dream.” I believe this state of affairs leads to what has been described as “flaccid scrum.” So my gig now is going to be working with a bunch of developers on things like writing modular code, dependency inversion, test driven development, etc.

This background is relevant for 2 reasons. First of all, it’s my excuse for why my posting cadence has dipped. Sorry ‘bout that. Secondly, it explains and segues into this post. What is software craftsmanship, anyway? I’m apparently teaching it, but I’m not really sure I can answer this question other than to say that I share a lot of opinions about what it means to write code effectively with people who identify this way. I think that TDD, factored methods, iterative, high-communication approaches, failing early, and testable code constitute are efficient approaches to writing software, and I’m happy to help people who want to improve at these things as best I can.

In that vein of thought, I’d like to offer some suggestions for tangible and easy-to-remember/easy-to-do things that you can do that are likely to improve your code. Personally, more than anything else, I think my programming was improved via random suggestions like this that were small by themselves, but in aggregate added up to a huge improvement. So, here is a series of things to tuck into your toolbelt as a programmer.

Make your variable names conversational

Ugh. The only thing worse than naming the variable after its type is then abbreviating that bad name. Assuming you’re not concerned with shaving a few bytes off your hard disk storage, this name signifies to maintainers, “I don’t really know what to call this because I haven’t given it any thought.”

Better. Now when this thing is referenced elsewhere, I’ll know that it probably contains days of some sort or another. They may be calendar days or days of the week, but at least I know that it’s talking about days, which is more than “cb” told me. But what about this?

Any doubt in your mind as to what’s in this combo box? Yeah, me neither. And that’s pretty handy when you’re reading code, especially if you’re in some code-behind or any kind of MVC model-binding scheme. And, of the objections you might have, modern IDE’s cover a lot of them. What if you later want to add Saturday and Sunday and the name becomes out of date? Easy to change now that just about all major IDEs have “rename all” support at your fingertips. Isn’t the name a little over-descriptive? Sure, but who cares — it’s not like you need to conserve valuable bytes of disk space. But with cb name, you know it’s a combo box! Your IDE should give you that information easily and quickly and, if it doesn’t, get a plugin that tells you (at least for a statically typed language).

Try to avoid booleans as method parameters

This might seem a little weird at first, but, on the whole your code will tend to be more readable and expressive if you don’t do this. The reason for this is that boolean parameters are rarely data. Rather, they’re generally control parameters. Consider this method signature:

This is a reasonably readable method signature and what you can infer from it is that the method is going to log output to a file. Well, unless you pass it “true”, in which case it will log to the console. And this tends to run afoul of the Single Responsibility Principle. This method is really two different methods kind of bolted together and its up to a caller to figure that out. I mean, you can probably tell exactly what this method looks like:

This method has two very distinct reasons to change: if you want to change the scheme for console logging and if you want to change the scheme for file logging. You’ve also established a design anti-pattern here, which is that you’re going to need to update this method (and possibly callers) every time a new logging strategy is needed.

Are there exceptions to this? Sure, obviously. But my goal here isn’t to convince you never to use a boolean parameter. I’m just trying to get you to think twice or three times about doing so. It’s a code smell.

If you type // stop and extract a method

How many times do you see something like this:

Would it kill you to do this:

and put the rest in its own method? Now you’ve got smaller, more factored, and descriptive methods, and you don’t need the comment. As a rule of thumb, if you find yourself creating “comment bookmarks” in your method like a table of contents with chapters, the method is too big and should be factored. And what better way to divide things up than to stop typing a comment and instead add a method with a descriptive name? So, when you find you’ve typed that “//”, hit backspace twice, type the comment without spaces, and then slap a parenthesis on it and, viola, new method signature you can add.

Make variable name length vary with scope size

This seems like an odd thing to think about, but it will lead to clearer code that’s easier to read. Consider the following:

Notice that there are three scopes in question: method level scope (i), class level scope (_processedCustomers) and global scope (that gigantic public static property). The method level scope variable, i, has a really tiny name. And, why not? It’s repeated 4 times in 2 lines, but it’s only in scope for 2 lines. Giving it a long name would clog up those two lines with redundancy, and it wouldn’t really add anything. I mean, it’s not hard to keep track of, since it goes out of scope one line after being defined.

The class level scope variable has a more descriptive name because there’s a pretty good chance that its declaration will be off of your screen when you are using it. The extra context helps. But there’s no need to go nuts, especially if you’re following the Single Responsibility Principle, because the class will probably be cohesive. For instance, if the class is called CustomerProcessor, it won’t be too hard to figure out what a variable named “_processedCustomers” is for. If you have some kind of meandering, 2000 line legacy class that contains 40 fields, you might want to make your class level fields more descriptive.

The globally scoped variable is gigantic. The reason for this is twofold. First and most obviously, it’s in scope from absolutely anywhere with a reference to its containing assembly, so it better be very descriptive for context. And secondly, global state is icky, so it’s good to give it a name that discourages people from using it as much as possible.

In general, the broader the usage scope for a variable/property, the more context you’ll want to bake into its name.

Try to conform to the Principle of Least Surprise

This last one is rather subjective, but it’s good practice to consider. The Principle of Least Surprise says that you should aim to minimize the learning curve or inscrutability of code that you write, bearing in mind a target audience of your fellow developers (probably your team, unless you’re writing a more public API). As a slight caveat to this, I’d say it’s fair to assume a reasonable level of language proficiency — it might not make sense to write horribly non-idiomatic code when your team is likely to become more proficient later. But the point remains — it’s best to avoid doing weird or “clever” things.

Imagine stumbling across this bad boy that compares two integers… sort of:

What pops into your head? Something along the lines of, “why is that line about production in there?” Or maybe, “what does a comparison function set some count equal to one of the parameters?” Or is it, “why compare two ints by converting them to strings?” All of those are perfectly valid questions because all of those things violate the Principle of Least Surprise. They’re surprising, and if you ask the original author about them, they’ll probably be some weird, “clever” solution to a problem that came up somewhere at some point. “Oh, that line about production is to remind me to go back and change that method. And, I set customer count equal to x because the only time this is used it’s to compare customer count to something and I’m caching it for later and saving a database write.”

One might say the best way to avoid this is to take a break and revisit your code as if you’re someone else, but that’s pretty hard to do and I would argue that it’s an acquired skill. Instead, I’d suggest playing a game where you pretend you’re about to show this code to someone and make mental note of what you start preparing yourself to explain. “Oh, yeah, I had to add 39 parameters to that method — it’s an interesting story, actually…” If you find yourself preparing to explain something, it probably violates the Principle of Least Surprise. So, rather than surprising someone, maybe you should reconsider the code.

Anyway, that’s all for the tips. Feel free to chime in if you have any you’d like to share. I’d be interested to hear them, and this list was certainly not intended to be exhaustive — just quick tips.


Be Idiomatic

I have two or three drafts now that start with the meta of me apologizing for being sparse in my posting of late. TL;DR is that I’ve started a new, out of town engagement and between ramp-up, travel and transitioning off of prior commitments, I’ve been pretty bad at being a regular blogger lately. Also, special apologies to followers of the Chess TDD series, but my wifi connection in room has just been brutal for the desktop (using the hotel’s little plugin converter), so it’s kind of hard to get one of those posts going. The good news is that what I’m going to be doing next involves a good bit of mentoring and coaching, which lends itself particularly well to vaguely instructional posts, so hopefully the drought won’t last. (For anyone interested in details of what I’m doing, check Linked In or hit me up via email/twitter).

Anywho, onto a brief post that I’ve had in drafts for a bit, waiting on completion. The subject is, as the title indicates, being “idiomatic.” In general parlance, idiomatic refers to the characteristic of speaking a language the way a native would. To best illustrate the difference between language correctness and being idiomatic, consider the expression, “go fly a kite.” If you were to say this to someone who had learned to speak flawless English in a classroom, that person would probably ask, “what kite, and why do you want me to fly it?” If you said this to an idiomatic USA English speaker (flawless or not), they’d understand that you were using a rather bland imprecation and essentially telling them to go away and leave you alone. And so we make a distinction between technically accurate language (syntax and semantics) and colloquially communicative language. The idiomatic speaker understands, well, the idioms of the local speech.

Applied to programming languages, the metaphor holds pretty well. It’s possible to write syntactically and semantically valid code (in the sense that the code compiles and does what the programmer intends at runtime) that isn’t idiomatic at all. I could offer all manner of examples, but I’ll offer the ones probably most broadly approachable to my reader base. Non-idiomatic Java would look like this:

And non-idiomatic C# would look like this:

In both cases, the code will compile, run, and print what you want to print, but in neither case are you speaking it the way the natives would likely speak it. Do this in either case, and you’ll be lucky if you’re just laughed at.

Now you may think that, because of this simple example that touches off a bike-shedding holy war about where to put curly braces that I’m advocating for rigid conformance to coding standards or something. That’s not my point at all. My point more goes along the lines of “When in Rome, speak like the Romans do.” Don’t walk in and say, “hey Buddy, give me an EX-PRESS-O!” Don’t be bad at speaking the way the community does and proud of it.

Here is a much more subtle and iconic example of what I’m talking about. Do you ever see people in C# do this?

I once referred to this as “The Yoda” in an old blog post. “If null is x, null argument exception you throw.” Anyone know why people do this, without cheating? Any guesses?


If you said, “it’s an old C/C++ trick to prevent confusing assignment and comparison,” you’d be right. In C and C++ you could do things like if(x = null) and what the compiler would do would be to assign x to null and then compare it to zero, which would result in it returning true no matter what x had been previously. Intuitive, right? Well, no, not at all, and so C/C++ programmers got into the habit of yoda-ing to prevent a typo from compiling and doing something weird and unexpected.

And, some of them carry that habit right on through to other languages like C#. But the problem is, in C#, it’s pure cargo cult weirdness. If you make that typo in C#, the compiler just barfs. if(x = null) is not valid C#. So the C++ life-hack is pointless and serves only to confuse C# programmers, as evidenced by questions like this (and, for the record, I did not get the idea for my bloopers post name from Daniel’s answer, even though it predates the post — GMTA, I guess).

So, if you’re doing this, the only upside is that you don’t have to change your way of doing things in spite of the fact that you’re using a completely different programming language. But the downside is that you needlessly confuse people. I suspect this and many other instances are a weird, passive-aggressive form of signaling. People who do this might be saying, “I’m a C++ hacker at heart and you you can take my pointers, but you’ll never take MY CONVENTIONS!!!” And maybe the dyed-in-the-wool Java guys write C# with curly brackets on the same line and vice-versa with C# guys in Java. It’s the geekiest form of passive (aggressive) resistance ever. Or, maybe it’s just habit.

But whatever it is, my advice is to knock it off. Embrace any language you find yourself in and pride yourself how quickly you can become idiomatic and rid yourself of your “accents” from other languages. By really seeking out the conversion, you don’t just appear more versed more quickly, I’d argue that you become more versed more quickly. For instance, if you look around and see that no one in C# uses The Yoda, it might cause you to hit google to figure out why not. And then you learn a language difference.

And there’s plenty more where that came from. Why do people use more enums in language X than in language Y? Why do people do that “throws Blah” at the end of a java method declaration? What’s thing with the {} after a class instantiation in C#? Why is it okay in javascript to assign an integer to “asdf”? If you’re new to a language and, instead of asking questions like those, you say, “these guys are stupid; I’m not doing that,” you’re balling up an opportunity to learn about language features and differences and throwing it in the trash. It’ll mean getting further out of your comfort zone faster, but in the end, you’ll be a lot better at your craft.


Recall, Retrieval, and the Scientific Method

Improving Readability with Small Things

In my series on building a Chess game using TDD I’ve defined a value type called BoardCoordinate that I introduced instead of passing around X and Y coordinate integer primitives everywhere. It’s a simple enough construct:

This was a win early on the series to get me away from a trend toward Primitive Obsession, and I haven’t really revisited it since. However, I’ve found myself in the series starting to think that I want a semantically intuitive way to express equality among BoardCoordinates. Here’s why:

This is a series of unit tests of the “Queen” class that represents, not surprisingly, the Queen piece in chess. The definition of “MovesFrom11″ is elided, but it’s a collection of BoardCoordinate that represents the possible moves a queen has from piece 1, 1 on the chess board.

This series of tests was my TDD footprint for driving the functionality of determining the queen’s moves. So, I started out saying that she should be able to move from (1,1) to (1,2), then had her also able to move to (2,2), etc. If you read the test, what I’m doing is saying that this collection of BoardCoordinates to which she can move should have in it one that has X coordinate of 1 and Y coordinate of 2, for instance.

What I don’t like here and am making mental note to change is this “and”. That’s not as clear as it could be. I don’t want to say, “there should be a coordinate in this collection with X property of such and such and Y property of such and such.” I want to say, “the collection should contain this coordinate.” This may seem like a small semantic difference, but I value readability to the utmost. And readability is a journey, not a destination — the more you practice it, the more naturally you’ll write readable code. So, I never let my foot off the gas.

During the course of the series, this nagging readability hiccup has caused me to note and refer to a TODO of implementing some kind of concept of equals. In the latest post, Sten asks in the comments, referring to my desire to implement equals, “isn’t that unnecessary since structs that doesn’t contain reference type members does a byte-by-byte in-memory comparison as default Equals implementation?” It is this question I’d like to address here in this post.

Not directly, mind you, because the assessment is absolutely spot on. According to

If none of the fields of the current instance and obj are reference types, the Equals method performs a byte-by-byte comparison of the two objects in memory. Otherwise, it uses reflection to compare the corresponding fields of obj and this instance.

So, the actual answer to that question is simply, “yes,” with nothing more to say about it. But I want to provide my answer to that question as it occurred to me off the cuff. I’m a TDD practitioner and a C# veteran, for context.

Answering Questions on Language Knowledge

My answer, when I read the question was, “I don’t remember what the default behavior of Equals is for value types — I have to look that up.” What surprised me wasn’t my lack of knowledge on this subject (I don’t find myself using value types very often), but rather my lack of any feeling that I should have known that. I mean, C# has been my main language for the last 4 years, and I’ve worked with it for more years than that besides. Surely, I just failed some hypothetical job interview somewhere, with a cabal of senior developers reviewing my quiz answers and saying, “for shame, he doesn’t even know the default Equals behavior for value types.” I’d be laughed off of stack overflow’s C# section, to be certain.

And yet, I don’t really care that I don’t know that (of course, now I do know the answer, but you get what I’m saying). I find myself having an attitude of “I’ll figure things out when I need to know them, and hopefully I’ll remember them.” Pursuing encyclopedic knowledge of a language’s behavior doesn’t much interest me, particularly since those goalposts may move, or I may wind up coding in an entirely different language next month. But there’s something deeper going on here because I don’t care now, but that wasn’t always true — I used to.

The Scientific Method

When I began to think back on this, I think the drop off in valuing this type of knowledge correlated with my adoption of TDD. It then became obvious to me why my attitude had changed. One of the more subtle value propositions of TDD is that it basically turns your programming into an exercise in the Scientific Method with extremely rapid feedback. Think of what TDD has you doing. You look at the code and think something along the lines of, “I want it to do X, but it doesn’t — why not?” You then write a test that fails. Next, you look at the code and hypothesize about what would make it pass. You then do that (experimentation) and see if your test goes green (testing). Afterward, you conduct analysis (do other tests pass, do you want to refactor, etc).


Now you’re probably thinking (and correctly) that this isn’t unique to TDD. I mean, if you write no unit tests ever, you still presumably write code for a while and then fire up the application to see if it’s doing what you hypothesized that it would while writing it. Same thing, right?

Well, no, I’d argue. With TDD, the feedback loop is tight and the experiments are more controlled and, more importantly, isolated. When you fire up the GUI to check things out after 10 minutes of coding, you’ve doubtless economized by making a number of changes. When you see a test go green in TDD, you’ve made only one specific, focused change. The modify and verify application behavior method has too many simultaneous variables to be scientific in approach.

Okay, fine, but what does this have to do with whether or not I value encyclopedic language knowledge? That’s a question with a slightly more nuanced answer. After years of programming according to this mini-scientific method, what’s happened is that I’ve devalued anything but “proof is in the pudding” without even realizing it. In other words, I sort of think to myself, “none of us really knows the answer until there’s a green test proving it to all of us.” So, my proud answer to questions like, “wouldn’t it work to use the default equals method for value types” has become, “dunno for certain, let’s write a test and see.”

False Certainty

Why proud? Well, I’ll tell you a brief story about a user group I attended a while back. The presenter was doing a demonstration on Linq, closures, and deferred execution and he made the presentation interactive. He’d show us methods that exposed subtle, lesser known behaviors of the language in this context and the (well made) point was that these things were complex and trying to get the answers right was humbling.

It’s generally knowledgeable people that attend user groups and often even more knowledgeable people that brave the crowd to go out on a limb and answer questions. So, pretty smart C# experts were shouting out their answers to “what will this method return” and they were getting it completely wrong because it was hard and it required too much knowledge of too many edge cases in too short a period of time. A friend of mine said something like, “man, I don’t know — slap a unit test on it and see.” And… he’s absolutely right, in my opinion. We’re not language authors, much less compilers and runtimes, and thus the most expedient answer to the question comes not from applying amassed language knowledge but from experimentation.

Think now of the world of programming over the last 50 years. In times where compiles and executions were extremely costly or lengthy, you needed to be quite sure that you got everything right ahead of time. And doing so required careful analysis that could only be done well with a lot of knowledge. Without prodigious knowledge of the libraries and languages you were using, you would struggle mightily. But that’s really no longer true. We’re living in an age of abundant hardware power and lightning fast feedback where knowing where to get the answers quickly and accurately is more valuable than knowing them. It’s like we’ve been given the math textbook with the answers in the back and the only thing that matters is coming up with the answers. Yeah, it’s great that you’re enough of a hotshot to get 95% of the answers right by hand, but guess what — I can get 100% of them right and much, much faster than you can. And if the need to solve new problems arises, it’s still entirely possible for me to work out a good way to do it by using the answer to deduce how the calculation process works.


In the course of writing this, I can think of two valid objections/comments that people might have critiquing what I’m saying, so I’d like to address them. First of all, I’m not saying that you should write production unit tests to answer questions about how the framework/language works. Unit testing the libraries and languages that you use is an anti-pattern. I’m talking about writing tests to see how your code will behave as it uses the frameworks and languages. (Although, a written and then deleted unit test is a great, fast-feedback way to clarify language behavior to yourself.)

Secondly, I’m not devaluing knowledge of the language/framework nor am I taking pride in my ignorance of it. I didn’t know how the default Equals behavior worked for value types yesterday and today I do. That’s an improvement. The reason it’s an improvement is that the knowledge is now stored in a more responsive cache. I maintain having the knowledge is trumped by knowing how to acquire it, and I look at reaching into my own personal memory stores as like having it in a CPU cache versus the memory of writing a quick test to see versus the disk space location of looking it up on the internet or asking a friend.

The more knowledge you have of the way the languages and frameworks you use work, the less time you’ll have to sink into proving behaviors to yourself, so that’s clearly a win. To continue the metaphor, what I’m saying is that there’s no value or sense in going out preemptively and loading as much as you can from disk into the CPU cache so that you can show others that it’s there. In our world, memory and disk lookups are just no longer expensive enough to make that desirable.

Acknowledgements | Contact | About | Social Media