NDepend

Improve your .NET code quality with NDepend

Your Guide to Winning Arguments About Code

Your Guide to Winning Arguments About Code

The whole “tabs versus spaces” thing occupies sort of an iconic position in the programmer world.  It represents the impossibility of winning arguments that are unwinnable by their very nature.  These are so-called religious wars — our techie version of The Butter Battle Book but without the Cold War overtones.

But this and arguments like it rarely actually play out in team rooms and offices.  At least, that’s always been my experience.  I’ve only ever witnessed live “tabs versus spaces” arguments happen ironically.

Actual Arguments in the Programmer World

So here’s how it really goes down.

You take a job with a company, excited about the new office, the shorter commute, and the bump in pay.  You’re riding high.  But then the onboarding starts with the codebase.

Greg, the most senior member of the group, walks you through the codebase with a slightly smug affect of obvious pride.  The codebase has everything you could ever want, according to Greg.  To your mounting horror, this includes

  • Inheritance hierarchies that are inscrutable, dark, and deep (with miles to go before you sleep).
  • A generous portion of global state.
  • Liberal use of reflection, often for no discernible reason.
  • And, of course, an extensive, homegrown “framework.”

Greg finishes with a flourish: “So, anytime you need to add a new feature, you just open GodClass.cs, scroll down to line 12,423, add another method, and get started!”

You’re new, and you’re not entirely sure that this isn’t an elaborate prank, so you swallow and say, “Oh…great!” while already planning the lengthy suggestions document that you’re going to put together.  And so the stage is set for what will become a never-ending string of arguments of variable politeness about the codebase.

Swap my hypothetical specifics for yours, but the formula is the same.  Someone is asking you to exist in a codebase that you have philosophical reservations about, which will force you to write code you don’t like.

Winning Arguments: How Does One Define This?

I’ve now set the stage, but what does it actually mean to “win” an argument?  This is pretty hard to define in a lot of contexts, such as people arguing on Facebook about politics or fighting at dinner.  Is it the one who got the last word in?  The one who was louder?  The one who didn’t simply give up?

Luckily, in your quest to de-Greg your new company’s codebase, “winning” is easier to define (if admittedly something of a loaded term).  You win if, by mutual consent, however grudging, the thing you think should happen winds up immortalized in the team’s source control.  And the mutual consent part matters.  Just slamming something into source control and being forced to revert later by an angry Greg doesn’t count.

You win when your argument carries the day and results in concrete action.  So let’s look at some techniques for making that more likely.

Continue reading Your Guide to Winning Arguments About Code

Functional Programming Makes Your Code Not OO...And Thats It

Functional Programming Makes Your Code Not OO…And That’s It

Over the course of the fall and winter, I’ve been gaining momentum with code research posts.  Today, I bring that momentum to bear on the subject of functional programming.  Or at least, on functional style of programming in C# codebases.

But before I do that, let me provide a little background in case you haven’t caught the previous posts in the series.  It started with me doing automated static analysis on 100 codebases to see how singletons impact those codebases.  Next up, I used that data to look at how unit tests affect codebases.  That post generated a lot of buzz, so I enlisted a partner to help with statistical analysis and then boosted the codebase sample size up to 500.

At the end of that last post, I suggested some future topics of study.  Well, now I’ve picked one: functional programming.

What Is Functional Programming?

The idea with this post is mostly to report on findings, but I’d be remiss if I didn’t provide at least some background so that anyone reading has some context.  So first, let’s cover the topic of functional programming briefly.

Functional programming is one of the major programming paradigms.  Specifically, its calling card is that it disallows side effects.  In other words, it models the rules of math, in which the result of the function (or method) is purely a deterministic function of its inputs.

So, in pseudo-code, it looks like this:

This is a functional method.  But if you do something like this

or like this

then you’re out of the functional realm because you’re adding side effects.  These two modified versions of Add() each concern themselves with the world beyond processing the inputs to add.  (As an aside, you could “fix” this by passing the global variable or the _databasePlopper dependency to the method as a parameter.)

Now, take note of something because this matters to the rest of the post.  While C# (or any other object-oriented language) is not a functional language, per se, you can write functional methods in C#.

Continue reading Functional Programming Makes Your Code Not OO…And That’s It

An Introduction to Clean Architecture

An Introduction To Clean Architecture

It seems to me that the topic of software architecture has attracted a lot of interest in the last few years. And among many different flavors and styles of software architecture, there’s one that attracts even more interest than the others. I’m talking about the clean architecture, proposed and evangelized by Robert C. Martin, a.k.a. Uncle Bob. (And for the rest of this post, it’s simply referred to as “clean architecture.”)

By employing clean architecture, you can design applications with very low coupling and independent of technical implementation details, such as databases and frameworks. That way, the application becomes easy to maintain and flexible to change. It also becomes intrinsically testable.

We’ll start today’s post not by explaining what clean architecture is right away. We’ll first dive into the problems that high coupling can cause in software projects. Then we’ll proceed to see the more mainstream solution to these problems.

Finally, we’ll explain the flaws with this solution, showing why and how clean architecture can be the piece of the puzzle that was missing for your application to achieve its full potential.

“Desperation” of Concerns

If you have at least a couple years of software development experience under your belt, then I can almost guarantee you’ve heard the term “separation of concerns.” It’s a principle that shows up quite often when talking about software architecture.

One of its incarnations is in the form of advice: “Separate presentation from business logic.” It’s very sound advice and I agree with it wholeheartedly, but the problem is that it’s not so easy or clear how to put it into practice, especially for beginners.

In practice, what ends up happening is that logic business frequently leaks to the application’s UI. And the same can go the other way around: it’s not so rare to find business logic code concerning itself with UI concepts, such as colors, markup languages, font sizes, and what have you.

And things can get even worse when you add data access to the mix. How does one free oneself from this mess?

Continue reading An Introduction To Clean Architecture

Unit Tests Correlate With Desirable Codebase Properties

Unit Tests Correlate With Desirable Codebase Properties

Today, I give you the third post in a series about how unit tests affect codebases.

The first one wound up getting a lot of attention, which was fun.  In it, I presented some analysis I’d done of about 100 codebases.  I had formed hypotheses about how I thought unit tests would affect codebases, and then I tested those hypotheses.

In the second post, I incorporated a lot of the feedback that I had requested in the first post.  Specifically, I partnered with someone to do more rigorous statistical analysis on the raw data that I’d found.  The result was much more clarity about not only the correlations among code properties but also how much confidence we could have in those relationships.  Some had strong relationships while others were likely spurious.

In this post, though, I’m incorporating the single biggest piece of feedback.  I’m analyzing more codebases.

Analysis of 500 (ish) C# Codebases

Performing static analysis on and recording information about 500 codebases isn’t especially easy.  To facilitate this, I’ve done significant work automating ingestion of codebases:

  • Enabling autonomous batch operation
  • Logging which codebases fail and why
  • Building in redundancy against accidentally analyzing the same codebase twice.
  • Executing not just builds but also NuGet package restores and other build steps.

That’s been a big help, but there’s still the matter of finding these codebases.  To do that, I mined a handful of “awesome codebase” lists, like this one.  I pointed the analysis tool at something like 750 codebases, and it naturally filters out any that don’t compile or otherwise have trouble in the automated process.

This left me with 503 valid codebases.  That number came down to 495 once adjusted for codebases that, for whatever reason, didn’t have any (non-third party) methods or types or that were otherwise somehow trivial.

So the results here are the results of using NDepend for static analysis on 495 C# codebases.

Continue reading Unit Tests Correlate With Desirable Codebase Properties

Value Objects A Tool for Self-Documented Code and Fewer Errors-01

Value Objects: A Tool for Self-Documented Code and Fewer Errors

Have you ever heard of value objects? I bet you have. Even though they’re talked about a lot less than I’d like, they’re still talked about enough that many developers have at least some passing familiarity with the term.

“Passing familiarity” isn’t good enough, though. So that’s what we’re fixing with this post. Today you’re going to learn what value objects are and how you, as a C# developer, can harness their power to make your code clearer, self-documenting, and less error-prone.

What Are Value Objects?

Value objects are one of the building blocks of domain-driven design, as proposed by Eric Evans on his seminal book Domain-Driven Design: Tackling Complexity in the Heart of Software.

Simply put, a value object is an object that represents a value. And I’m aware that sounds excruciatingly obvious and even boring when said this way. So, what’s all the fuss about it?

Continue reading Value Objects: A Tool for Self-Documented Code and Fewer Errors

Delegation as a developer Building the Next You

Delegation As a Developer: Building the Next You

“I love me some me!”  

Yes, there’s more than just an ounce of truth in that statement said by the great NFL receiver Terrell Owens.  Terrell loved some Terrell. In fact, if you knew one thing about the man, it’s that he loved himself. Most of us can hide it a little bit better than Terrell, but we’ve all been guilty of this sentiment at one time or another. We suffer from pride and do our best to counteract it with humility.  I’ll admit it—as a software developer, after I write a solid, beautiful piece of code, my pride gets a first-class ride on the ego train!

Why start an article about delegation with an eccentric statement about ego?  The truth is we’re all good at what we do.  We spend time honing our craft, studying our industry, and trying to better ourselves.  Eventually, through experience, we’re able to understand and execute on things that less senior developers just can’t.  Our peers and managers recognize this, so we begin the journey to the role of leader.  And that leadership role doesn’t just entail learning all of the new frameworks and extensions. It also means learning a new set of skills.  One of those skills is delegation.

The Quandary of Leadership

When I was first recognized as a leader on my team, the recognition was extremely rewarding.  I had worked hard as a developer on this team and naturally stepped into some very minor leadership roles along the way.  I was honored to be selected as the team lead, and soon the team was coming to me for direction while the boss was looking to me for updates on how the team was performing.  

Rather quickly, I found myself thrust into a lonely middle ground. Management expected me to keep my team on task, and I was also trying to meet my standard deliverables.  It was obvious that keeping the team running and efficient required some new skills, and these skills weren’t the kind of things I could obtain by entering commands on my keyboard and getting results.  

These were skills that required—gulp—talking to people and finding out what makes them tick. Oh, and guess what? These skills had no tangible output. There was no rewarding pull request with a peer review after finding out that Jack needs a little more help with CSS and could use some training there.  There was no successful build notification after discovering that Diane had some issues going on at home and it was starting to impact her work output.  While I spent time building relationships with my team members, guess what I was NOT doing?  Producing!

All my career to this point was spent producing. Talking and relationships were a side gig that never got much attention, but they unknowingly got me much further along in my career than I like to admit.  I always liked to think that I would be promoted on technical merit, but it seems that managers are always looking for the next manager, and the technical merit is just expected.  

This transition from producer to leader presented me with a new skill set to learn and start putting into practice.  

Continue reading Delegation As a Developer: Building the Next You

Following the Software Architecture Career Path

Following the Software Architecture Career Path

I can recall a certain day in my career with remarkable clarity.  I say remarkable because this happened well over a decade ago, when I was a relatively fresh-faced software engineer.  My manager had called me in for a chat — quarterly review or some such. He said something that stopped me in my tracks.

“Do you want to follow the technical track or the management track in your career?”

Yikes!  I remember panicking.  On an otherwise unremarkable morning, I had unexpectedly come to a crossroads in my career.  Did I want the organizational clout and higher paychecks of management?  Or would I stick with the technical stuff that I so loved?

Of course, this turned out to be a comical overreaction on my part.  My answer didn’t, in any way, bind me for life.  And the whole thing was something of a false dichotomy anyway.  But it did get me thinking about what I would later regard as the software architecture career path.

The Software Architecture Career Path

I certainly wasn’t alone in my confusion over what becomes of programmers as they advance in their careers.  Some continue programming indefinitely, while others, eagerly or reluctantly, become managers and climb the corporate ladder.  But the software architecture career path splits the difference in a confusing variety of ways.

I challenge you to find a job title with as much variance as “software architect.”  The title itself has many different flavors:

  • Software architect
  • Application architect
  • Technical architect
  • Solutions architect
  • Enterprise architect

You get the idea.  But beyond the title variance, you also see wide diversity in responsibilities.  Some architects are literally just programmers with developmental job titles.  Others are highly technical, mentoring developers and approving of solutions.   Still others are more like project managers or business analysts.  It really varies.

And in this variance lies opportunity.  You can take the opportunity to find a role that suits you well in terms of responsibilities while also advancing your career.

For the rest of this post, I’m going to talk about how to take advantage of this opportunity.  What skills do you need, and how do you find success?  Bear in mind, I’m also going to describe the different flavors of architects in somewhat broad strokes.  The industry doesn’t have a great consensus on what each of these roles really means, so I’m basing this on my own experience.  Whatever you call the different flavors of architect is less important than what they do in their roles and whether the role might suit you.

Continue reading Following the Software Architecture Career Path

Cargo Cult Programming is the Art of Programming by Coincidence

Cargo Cult Programming Is the Art of Programming by Coincidence

I first learned about cargo cult programming a few years ago. I remember thinking back then, “What a strange name for a programming-related concept.”

If you share my past self’s astonishment, then today’s post is for you!

First, you’ll see what cargo cult programming is and why you should care. Then, we’re going to look at some practical examples, using the C# language. Finally, we’ll close with advice about what you can do, as a developer, to avoid falling into this trap.

Cargo Cult Programming: Doing Stuff Just Because

According to Wikipedia, “Cargo cult programming is a style of computer programming characterized by the ritual inclusion of code or program structures that serve no real purpose.”

In other words, it’s when a developer writes code without really understanding it. The developer may use a very trial-and-error approach—maybe copy and paste some code from somewhere else and then tweak it and test it until works, or sort of works. Then the developer will stop tweaking the code, for fear it will stop working. In the process, maybe they leave some lines of code that don’t do anything.

Or maybe they tried to use an idiom they picked up from another developer while failing to understand that the contexts are different and it’s useless in the current situation.

Finally, it might just be lack of education: maybe the developer has a poor mental model of how the tools they’re using really work.

Why is Cargo Cult Programming a Problem?

As Eric Lippert puts it, cargo cult programmers struggle to make meaningful changes to a program and end up using a trial-and-error approach since they don’t understand the inner workings of the code they’re about to change.

This is not so different from what the Pragmatic Bookshelf calls “programming by coincidence”:

Fred doesn’t know why the code is failing because he didn’t know why it worked in the first place. It seemed to work, given the limited “testing” that Fred did, but that was just a coincidence.

That single sentence pretty much sums it up for me: if you don’t know how or why your code works, neither will you understand what happened when it no longer works.

Continue reading Cargo Cult Programming Is the Art of Programming by Coincidence

The unit test effect study, refined

The Unit Test Effect Study, Refined

About a month ago, I wrote a post about how unit tests affect (and apparently don’t affect) codebases.  That post turned out to be quite popular, which is exciting.  You folks gave a lot of great feedback about where we might next take the study.  I’ve incorporated some of that feedback and have a followup on the unit test effect on codebases.

Summarized briefly, here are the high points of this second installment and refinement of the study:

  • Eliminating the “buckets” from the last time.
  • Introducing more statistical rigor.
  • Qualifying and refining conclusions from last time.

Also, for the purposes of this post, please keep in mind that non-incorporation of feedback is not a rejection of that feedback.  I plan to continue refinement but also to keep posting about progress.

Addressing Some of the Easier Questions and Requests

Before getting started, I’ll answer a few of the quicker-to-answer items that arose out of the comments.

Did your analysis count unit test methods when assessing cyclomatic complexity, etc.?

Yes.  It might be interesting to discount unit test methods and re-run analysis, and I may do that at some point.

Can you show the code you’re using?  Which codebases did you use?

The scraping/analysis tooling I’ve built using the NDepend API is something that I use in my consulting practice and is in a private repo.  As for the list of specific codebases, I’m thinking I’ll publish that following the larger sample size study.  In the most general terms, I’m going through pages like this that list (mostly) C# repos and using their links.

What about different/better categorization of unit test quality (test coverage, bolted on later vs. written throughout vs. demonstrably test driven)?  

This is definitely something I want to address, but the main barrier here is how non-trivial this is to assess from a data-gathering perspective.  So I will do this, but it will also take time.

Think of even just the anecdotally “easy” problem of determining TDD vs. non-TDD.  I approximated this by positing that test-driving will create a certain ratio of test methods to production methods since any production method will be preceded by a test method (notwithstanding future extract method refactorings).  We could, perhaps, do better by auditing source control history and looking for a certain commit cadence (modification to equal numbers of test/production classes, for instance).  But that’s hard, and it doesn’t account for situations with large batch commits, for instance.

The upshot is that it’s going to take some doing, but I think we collectively can figure it out.

Continue reading The Unit Test Effect Study, Refined