"Simpler" Is Subjective: How Bad Assumptions About Architecture Kicked My Ass

I'm doing some heavy refactoring on a project that I've recently joined but that has been underway for months. The code is a mishmash of different styles and an uncertain architecture, so my task up to this point has been to make it more consistent, testable, and readable.

One of the issues I was tasked with was improving the data access layer. The system was using a pattern known as Repository for its data access layer, and the individual Repositories (the classes which both write data to and retrieve data from the database) are fairly dumb; they just do exactly what they say they do, without any validation or anything. Get, add, edit, delete, search; that's it.

The service interface layer of this app is an ASP.NET Web API application, so that app's Controllers need some way to get data from the database. In simple scenarios, the Controllers can just call the Repositories directly. However, the previous development team also included another layer of static classes between the Controllers and the Repository, called the Logic layer. The full architecture looked something like this:


I had a problem with the Logic layer. For the majority of the functionality the app handled, the Logic layer just called a Repository method and didn't do anything else. Further, it was a set of static classes, and therefore couldn't take advantage of the dependency injection scheme that I wanted to use in the Controllers. It seemed to me like an unnecessary layer of architecture, and so I removed it; the Controllers now called the Repositories directly.


Long time readers will know that this is par for the course for me: I'm an extreme deletionist and any code we keep must have a reason to exist.

On the surface, the architecture change makes sense. I'd been preaching to this group that controllers need to be small, repositories should only do data access, and less architecture is better than more. Seemed like a no-brainer to me. Little did I realize the no-brainer was me.

Did you catch the mistake I'd made? I'd waltzed into this project, taken over, and declared that I knew better than the two developers who had been working this project for six months prior. I had (unintentionally, to be sure) declared that my opinion on how this app should be constructed was more important than theirs, simply because it had worked for me in the past. I had given myself a golden hammer, and now everything looked like a nail.

I, of course, didn't notice at all. The other two did. For this post we'll call them Rajit and Dave. Here's how that conversation went:

Dave: Hey Matt, did you remove the Logic classes that Rajit and I set up?

Matthew: Sure did! I couldn't see that they were doing anything different than if the controllers called the Repository classes directly. So I moved all that code to the Controllers. Now we don't need anything between Controllers and Repositories. It's a simpler design overall.

Rajit (stunned): ...Um, OK, it is simpler, kind of. But remember, this API will need to call other APIs to get all the data we need to send back to the requesting application. Where would it do that?

Matthew (realizing the mistake, not wanting to admit it): Well, wouldn't it do that in the Controllers....?

Dave (annoyed): But didn't you say that we want to keep the controllers small? Why bloat them like this when we could do the extra, non-database-access code in a different layer then just call that from the controller? Or are we not worrying about bloat on the controllers? Which is it?

Matthew: Because...well...(facepalm)

It's easy to fall into the trap of "I've seen this before and X worked, so I'll just do X again". Programmers (including myself) are busy people, often over-worked, and don't necessarily have time to consider all possible solutions to a given problem. Sometimes, the lack of time (or foresight, as is the case here) comes back to bite us in a big way.

Dave and Rajit were right, of course: we ought to have that extra layer to do things like consolidate calls from other web services and make multiple Repository submissions. I hadn't immediately found the Logic layer's reason to exist and had removed it, when in reality there was a purpose for this layer; I had just missed it. I still objected to the Logic layer being a set of static classes, so eventually Dave, Rajit, and I compromised to include a new set of Service classes:


The Services could call the Repositories and any other services, and because they were no longer static, we could inject them into the Controllers. I got my simpler architecture, and Rajit and Dave got their extra layer. Everyone's happy.

Point is, don't just assume that every app needs the same architecture. There are a myriad of software patterns for this reason: each of them has a different purpose, a different use case. They aren't all interchangeable. Don't assume the solution to a given problem is the same as a similar problem you've encountered before. Similarity does not mean sameness.

(Also, it helps if you actually talk to people who have more experience than you on a given project. Just sayin'.)

Anybody screwed up like this before? Alternately, any of you lovely readers find an over-architected app and pare it down successfully? Was there a better pattern for this app that Rajit, Dave, and I could've used? Share in the comments!

Happy Coding!

The Bug Is In Your Code

Have you ever been hunting a bug and been absolutely sure that it was in someone else's code, only to find out that, nope, it was in yours all along? I sure did. Come along with me as we explore my latest minor failure and remind ourselves that, most of the time, the bug is in your code.

An Emperor Gum Moth, a large, brown, hairy insect, seen in flights. Emperor Gum Moth from Wikimedia, used under license

Well, hopefully that bug isn't in your code, but you never know.

Bad Assumptions, Bad Actions

We inherited a new application, a chat system built using SignalR and .NET 4.5, which we needed to deploy to a brand-new IIS8 server box. The system consists of two pieces: a hub, which acts as the "server" for the broadcast system, and the client web application, which received broadcasts. At the time we inherited the system, the hub had already been deployed; we just needed to get the client app on the correct server and we'd be good to go.

The deployment itself went off without a hitch; the web app was accessible to the right people, let us log in, basically worked. Or so it seemed.

As part of sanity-checking the deployment, we programmers logged in and tried to create conversations and send messages through the chat system. We could create messages just fine, but after the first message was sent, no further messages could be transmitted. A quick debugging showed that the SignalR piece on the web client was failing at some point while trying to reach the hub.

We checked and double-checked the web client settings, and couldn't find anything that might cause this error. That's when we went to the server team, pointed out our problem to them, and asked if they could help us figure out what exactly was going on here. Clearly this was a server or connections issue; it was deployed onto a clean IIS8 machine which may not have gotten the correct settings applied, and SignalR was failing to connect. That means network problems, right?

Except, the server team couldn't find anything wrong. They did whatever server magic they do (I'm SO not a server guy) and didn't detect any problems. Yet our debugging suggested that the error was in the network; possibly permissions or access-related. For a few days we went back-and-forth over this, arguing and haggling and posturing until we were so bloody tired of even talking to the other side.

I went back to try to debug this again, still flustered because I was convinced that this was a network problem, but the network team couldn't find any explanations for why we might be getting this error. Come on, network guys, it's obviously some kind of network issue, and you can't even find it?! This can't be my fault! Bewildered (and kinda angry) at their lack of insight, I stepped through the web client code once more.

It CAN Be Your Fault

It was during this bug hunting session that I decided to re-read the actual text of the connection error message I was seeing:

SignalR: chathub.[MethodName] failed to execute. Error: the underlying provider failed on Open.

Hmmm, I thought, that error only appears after initiating a hub request; seems to take about a minute to appear. So it clearly is hitting the hub, it's just not getting any response back. Now that I'm thinking about it, I've often seen that "underlying provider failed on Open" error when something fails to connect to a database... Crap.

It was like a lightbulb came on in my head.

The Centennial Light, which has been on continuously since 1901

I quickly started rummaging through the hub settings (remember that it was deployed before we took ownership of this application). Sure enough, the profile of the hub that had been deployed to production was using a connection string that connected it to our staging database server, not the production one. With the wrong connection string, the hub couldn't connect to the database (since in our company, production servers cannot contact staging ones, and vice-versa), hence it was throwing that error. We could create conversations because that happened in the web app, which had the correct production connection string, but sending messages after creation of the conversation required the hub to work.

All of this, of course, meant that the error was not the server team's fault. It was mine, as my team (including me as the lead developer) was responsible for this app now. I didn't deploy the hub, and I didn't write it, but this bug was my responsibility, and I failed to research it enough.

This is what happens when we assume the solution and don't take the time to do our own thorough research. I was so certain that the hub had been deployed correctly and that our settings were correct that the only remaining possible issue, to my mind, was the network settings. After reaching that erroneous conclusion, I became blinded to the possibility that the bug was still in my code.

Of course, it was in my code, and of course, I blamed other people for what was ultimately my responsibility. Not exactly my finest moment, I'll admit.

This is yet more proof that we're all (especially me) not as smart as we think we are. Most of the time, the bug is in our code. Not in a library, not in some other person's service, not in the network, not "somewhere else". In our code.

Jeff Atwood put this another way: he wrote that the first rule of programming is that it is always your fault. If you assume that the problem exists in code you are responsible for, you are more likely to actually locate the bug (because most of the time, it genuinely is there). Even if you don't locate the bug, you've learned enough about the system in the process that you should have a much better idea of where it might exist.

Assume that the bug is in your code! Only after you've proven that it isn't can you start to explore other possibilities.

We've all seen how my forgetting to check my code thoroughly ended up making me look like an idiot. Has this ever happened to you, or even some "friend" that you know (wink wink)? Share in the comments!

Being a Better Lead Developer

I've mentioned before that I'm what my company calls a "lead" developer, which means I'm in charge of projects, not people. It is my responsibility to assign work, conduct code reviews, divvy up tasks, etc. It may sound like this position means doing a lot of paperwork (and, in fairness, sometimes it means exactly that) but for the most part I love my job.

That said, leadership is not a quality you are born with, as I can personally attest to. For most of my school days and the first five years of my professional career, I was the opposite of a leader; a loner, content to lurk all day in my ivory tower and only emerge when I'd solved some problem, be it calculus or my essay for English class. I didn't listen to others, I was never wrong, I didn't ask why because I already "knew" the answer. I was the classic nerd, the anti-social, sci-fi loving, helps-all-the-people-with-their-homework-but-never-gets-a-date 80's-movie geek. I'm still that guy to some degree.

Four years ago, I was laid off from a job I didn't particularly like and my whole viewpoint changed irrevocably. I had felt like I had no control in that situation, and I was sick of being only a sidekick in my game of life and not the main player. I needed to do something else, something fulfilling, and I slowly came to realize that for me, being a teacher was what I liked to do. I'd truly enjoyed assisting my classmates with their schoolwork, and now I wanted to help others.

A presenter points toward code on a screen Teacher, information and computer science by Wonderlane, used under license.

Two years ago, an opportunity arose in my organization for a lead developer role, and I quickly volunteered. I had no previous leadership experience, and up until that point becoming anything other than a code monkey hadn't even been a consideration for me. But I saw my opportunity to teach, to guide, to help, and I grabbed it and didn't let go. Finally I had some measure of control back.

Since I haven't been either fired or demoted in the time that I've been a lead, I can conclude that I'm doing an acceptable job. I think. At any rate, while I've found this position largely to my liking, there's been a few things I needed to learn on the way. In my case, four ideals have helped me become a better lead developer and could help out those of you who might wish to be (or already are) a leader of some kind in your organization. I try to keep these ideals in mind every day I'm at my desk.

So what are they? Glad you asked!

Delegation Is Your Friend

There's only one of me (as far as I know), and as such if I ever wanted to have time to do something else I had to consciously try to not do everything myself. After all, what good are having teammates if you never give them anything to do?

A to-do list Tuesday to-do list by Stacy Spensley, used under license.

When I was promoted to lead, I kept thinking in terms of my time. Oh, I know this project, this will only take a couple hours which promptly fell apart because I was already stretched too thin. Sixteen two-hour tasks that are all due tomorrow are too many balls in the air for one programmer to juggle, no matter how capable they think they are. I was forced to start giving some of my balls away to trusted, capable members of my team...

Are we done giggling now? Good.

As I was saying, we can't do everything by ourselves, so we have to trust others to do some of it for us. Trust is the hard part; it takes a while to be able to trust anyone with something we give them. But once that trust is established, we'll be able to assign tasks and code to our teammates and know that they'll get it done correctly, efficiently, completely.

You can't do it all yourself; delegation is your friend.

Listen Up

Ever woken up in the middle of a conversation and realized that you had no idea what the other person was saying? (If you have: just smile and nod. Eventually they will leave.) This is something we should not ever do when talking with your teammates. They are our eyes and ears into the code that you may not be personally familiar with; you need them to squash bugs and implement features and run tests that you may not be very skilled at doing, or even able to do at all. But if we are to hear what they are telling us, we need to be able to listen to them.

A drawing of differently-colored ears, above each of which is a letter in the word Listen by Ky, used under license.

This is a particularly difficult thing for me because listening requires focus, but practice has slowly improved my ability to concentrate and fully comprehend what others are saying. If someone is talking at me, it is my job to ensure that they are also talking to me; communication is a two-way street. To do this, I follow two guidelines:

  1. Look at their eyes. This forces me to pay attention to what they are saying.
  2. Mentally repeat back what they just said. I find that repetition helps me retain knowledge, so forcing me to repeat to myself what the other person just said is invaluable in helping me digest what it means.

This was wildly uncomfortable for a natural introvert like me when I first started, but as I kept at it I slowly got acclimated to actually looking at people and remembering what they were saying. It's still tough to focus during some conversations (particularly when the topic at hand is contentious or difficult to talk about) but I'm getting better. I truly believe that you cannot be a good leader without being a good listener.

Listen to those around you, and pay attention to what they are saying.

Since I see that you are nodding in agreement (I'm glad we see eye-to-eye on this) I'll move right along.

Be Willing to Be Wrong

Pssh. Whatever. I'm never wrong! It's you guys who are wrong, not me!

An angry-looking housecat, with the phrase Modified from angry tiger by Jaqen, used under license

If you know a programmer that acts like this, you have my permission to slap them. Hard. Repeatedly, if necessary.

We must be willing to entertain the idea that we are wrong at all times. If we constantly believe that we could be mistaken, we become more willing to consider other points of view, other ideas. Part of listening and comprehending is the ability to consider someone else's opinion with the same weight as our own. If we're never wrong, can anybody else ever be right?

Here's an example: say you assign a small bug to one of your junior developers. You give them directions about how to reproduce the bug and how to fix it, and send them off on their way. A little while later, they submit their changes for code review, but when you look over their solution you find that they ignored your counsel and squashed the bug a different way. As it turns out, an objectively better way.

Some programmers would be annoyed that the junior didn't heed their advice, and those people make terrible leads. Ingenuity and creativity are to be celebrated, encouraged, and wasting time being upset that some punk didn't take your obviously sublime advice to heart doesn't help us deliver a product; in fact, it does just the opposite, because now you'll waste time trying to persuade the junior that your way is the One True Way TM rather than getting anything done.

Be willing to be wrong, so that you can objectively consider the possibility that others may be right.

Use The Most Powerful Word

There's a fine line to walk, though, since if we got to a lead position it is unlikely we will be wrong all of the time. This is where the most powerful word, the most important question we can ever ask comes in handy. It's so simple that many adults simply forget to use it at all, but five-year-olds use it all the time.


Why did you choose to do it that way, instead of the way I told you to do it? Why are these requirements part of this sprint? Why does the button need to be on the right instead of centered in the div? Why does our team sit on this floor rather than the other, and why do we not all sit together?

A reporter raises his hand to ask a question at a press conference Reporter raising hand at US Army press conference, used under license

The reasoning is simple: questions lead to answers, answers lead to understanding, and understanding is your responsibility as a lead. Our focus needs to be the bigger picture: how all of the individual stories or tasks fit together, how the end user expects the application to work, how the team will get from A to B during the development process. We need to understand the scope of what we are trying to accomplish in order to actually accomplish it.

Before understanding, though, comes questioning. Ask why, early and often, and don't quit until you get some kind of an answer, especially if it's an answer you don't like, because those kinds of answers are gateways to either comprehension (meaning you are wrong) or clarification (meaning the other person is wrong). Don't be arrogant, don't be brash, just be kind but persistent and you'll get an answer.

Question everything!

Why should I listen to you?

Glad you're already asking the important questions.

You shouldn't listen to me! At least, not without trying some of these things for yourself. I'm just some guy on the internet. But I have been a lead developer for two years, I haven't screwed it up yet, and these four things - delegation, listening, willingness to be wrong and asking "why?" - have been instrumental in my constant quest to learn, to understand, to become a better developer. Maybe, hopefully, they'll help you as well.

And if they don't, well, just smile and nod. Often that gets the job done too.

A diagram, showing a Boss vs leader by John Lester, used under license.