NDepend

Improve your .NET code quality with NDepend

The Power of CQLinq for Developers

I can still remember my reaction to Linq when I was first exposed to it.  And I mean my very first reaction.  You’d think, as a connoisseur of the programming profession, it would have been, “wow, groundbreaking!”  But, really, it was, “wait, what?  Why?!”  I couldn’t fathom why we’d want to merge SQL queries with application languages.

Up until that point, a little after .NET 3.5 shipped, I’d done most of my programming in PHP, C++ and Java (and, if I’m being totally honest, a good bit of VB6 and VBA that I could never seem to escape).  I was new to C#, and, at that time, it didn’t seem much different than Java.  And, in all of these languages, there was a nice, established pattern.  Application languages were where you wrote loops and business logic and such, and parameterized SQL strings were where you defined how you’d query the database.  I’d just gotten to the point where ORMs were second nature.  And now, here was something weird.

But, I would quickly realize, here was something powerful.

The object oriented languages that I mentioned (and whatever PHP is) are imperative languages.  This means that you’re giving the compiler/interpreter a step by step series of instructions on how to do something.  “For an integer i, start at zero, increment by one, continue if less than 10, and for each integer…”   SQL, on the other hand, is a declarative language.  You describe what you want, and let something else (e.g. the RDBMS server) sort out the details.  “I want all of the customer records where the customer’s city is ‘Chicago’ and the customer is less than 40 years old — you figure out how to do that and just give me the results.”

And now, all of a sudden, an object oriented language could be declarative.  I didn’t have to write loop boilerplate anymore!

Continue reading The Power of CQLinq for Developers

old computer, future legacy code

Legacy Code for Developers: Managing your Manager

Here’s a campfire horror story of legacy code that probably sounds at least somewhat familiar.

One day, your manager strolls by casually, sipping a cup of coffee, and drops a grenade in your lap.  “Do you think we can add an extra field to the customer information form?”  Sure, it may sound innocuous to an outsider, but you know better.

The customer information form is supported by something written almost a decade ago, by a developer long departed.  Getting that data out of the database and onto the form prominently features a 60,000 line class called DataRepositoryManagerHelper and it also makes use of a gigantic XML file with odd spacing and no schema.  Trying to add a field to that form casts you as Odysseus, navigating between Scylla and Charybdis.  In fact, you’re pretty sure that author of the legacy code made it necessary for the assigned developer to cut off and sacrifice a finger to get it working.

Aware of all of this, you look at your manager with a mix of incredulity and horror, telling her that you’ll need at least 6 weeks to do this.  Already swirling around your mind is the dilemma between refactoring strategically where you can and running exhaustive manual testing for every character of the source code and XML that you change.  It’s now her turn to look incredulous and she says, “I’m just asking for a new field on one form.”  You’ve told her before about this, and she’s clearly forgotten.  You’re frustrated, but can you really blame her?  After all, it does sound a little crazy.

Continue reading Legacy Code for Developers: Managing your Manager

A Manager’s Guide to Legacy Code

If you have a sadistic streak and manage a team of software developers, it’s probably high entertainment to dredge up some old, dusty piece of software and then to task them with maintaining it. If, on the other hand, you’re a normal human being and you’re asking this because it’s necessary for your business, you brace yourself.  After all, this is legacy software, and the reaction of the team is likely to be quite predictable.

 

Alright, let’s take a look at this thing.  Oh, man, look at that right there.  A global variable.  And — oh my god — there are dozens of these things.  Who even wrote this?  And, look at this over here.  That’s the kind of idiotic, backward code that we used to have to write 20 years and 6 language versions ago when this code was current.  But even when it was current, this code was horrible.  This was obviously written by a trained ape.

 

When you’re a developer, the only thing worse and more contemptible than the uninformed code you wrote years ago, is the code that someone else wrote years ago.  Not only is it alien to you in makeup and reasoning, this legacy code also features patterns that have gone out of date or even been forgotten.

But lest you, as a manager, assume that this is simply a matter of developers being prima donnas, consider that an encounter with legacy code bothers developers precisely because it renders them less effective. They’re professionals, wanting to do good work, and the lead balloon you’ve dropped in their lap is an impediment to that.

Continue reading A Manager’s Guide to Legacy Code

NDepend vs. ReSharper

Not too long ago, someone asked me for a comparison of ReSharper (commonly and affectionately abbreviated R#) and NDepend.  I didn’t really grok the question, so I asked, “in what sense?”  The response was, “well, let’s say NDepend vs ReSharper — which makes more sense for a given person?”  Bemused, my slightly snarky quip in response was, “doctor vs dentist — which makes more sense for a given person?”

I went on to clarify the analogy.  Doctors and dentists both provide healthcare services, so, in this sense, one could theoretically view them as competitors.  But practically speaking, that competition is going to be rare or nonexistent.  There is an intersection between what the tools offer, as would be the case if a dentist noticed a throat infection or a doctor needed to peer into your mouth.  And yet that intersection is small because the two products, like doctors and dentists, have fundamentally different charters.

I’ll return to that in a bit, though.

Continue reading NDepend vs. ReSharper

The Better Code Book – Our MVPs of 2015

We firmly believe spaghetti belongs on the dinner table and not in code. Our mission when starting NDepend was to create a tool to make best coding practices easier to maintain and improve. Writing has always been part of our message (see Patrick Smacchia’s work on CodeBetter.com) and we are proud to present our favorite pieces of writing from around the web in the last year, collected in what we are calling the Better Code Book.

We wanted to focus not only on how people use NDepend to improve their code for developers and architects, but also how to use static analysis in a broader, management sense. We are extremely grateful for our contributors in this project. Let us introduce them:

Bjørn Einar Bjartnes is a developer at the Norwegian Broadcasting Corporation. His current role is a backend developer at the API team, serving web, mobile, TV clients and more metadata about programs- and video-streams. He holds a MSc in Engineering Cybernetics and has a background from the petroleum industry, which has probably shaped his view on systems design. Also, Bjørn is active in the local F# Meetup and a proud member of the lambda club, playing with all things useless related to computers. You can also follow him on Twitter: @bjartnes

Jack Robinson is a twenty-something student in his final year of a degree in Software Engineering at Victoria University of Wellington. Currently an Intern Developer at Xero, he enjoys writing clean code, playing a board game or two with his friends, or just sitting down and watching a good film. You can read not just his musings on computer science, but also reviews on films and more at his website jackrobinson.co.nz

Prasad Narravula is a programmer, architect, consultant, and problem-solving leader.  He helps teams in agile development essentials- feedback loops to fail fast, enabling (engineering) practices, iterative and incremental design, starting at the right place, discovery, and learning. When time permits, he writes at ObjectCraftworks.com.

Erik Dietrich, founder of DaedTech LLC, is a programmer, architect, development coach, writer, Pluralsight author, and technologist. You can read his writing and find out more about him at http://www.daedtech.com/ and you can follow him on Twitter @daedtech.

Anthony Sciamanna is a software developer from Philadelphia, PA who has worked in the industry for nearly 20 years. He specializes in leading and coaching development teams, improving development practices for cross-functional teams, Test-Driven Development (TDD), unit testing, pair programming, and other Agile / eXtreme Programming (XP) practices. He can be contacted via his website: anthonysciamanna.com

Tomasz Jaskula is a software craftsman, founder and organizer of Paris user groups for F# and Domain Driven Design. He focuses on creating software delivering true business value which aligns with the business’s strategic initiatives and bears solutions with clearly identifiable competitive advantage. He is currently working for a big French bank building reactive applications in F# and C#. In his free time, he runs a startup project on applying machine learning with F# to the recruitment field, speaks at conferences and user groups, and writes blogs and articles for a French magazine for coders called “Programmez !” You can visit his site jaskula.fr

Continue reading The Better Code Book – Our MVPs of 2015

upstate farm, where dead code goes

That Code’s Not Dead – It Went To a Farm Upstate… And You’re Paying For It

When it comes to pets, there’s a heartbreaking lie that parents often tell little children when they believe that those children are not yet ready to wrap their heads around the concept of death.  “Rex went to a nice farm in the countryside where he can run and play with all of the other animals all day!”  In this fantasy, Rex the dog isn’t dead — he lives on in perpetuity.

Memoirs of a Dead Method

In the source code of  an application, you can witness a similar lie, but in the other direction.  Code lives on indefinitely, actively participating in the fate of an application, and yet we call it “dead.”  I know this because I’ve lived it.  Let me explain.

You see, I’m a method in a codebase — probably one that would be familiar to you.  My name is GetCustomerById(int id) and I hail from a class called CustomerDaoMySqlImpl that implements the interface ICustomerDao.

I was born into this world during a time of both promise and tumult — a time when the application architects were not sure whether the application would be using SQL Server or MySQL.  To hedge their bets, they mandated data access interfaces and had developers do a bit of prototyping with both tools.  And so I came into this world, my destiny taking a single integer and using MySQL to turn that integer into a customer.

Continue reading That Code’s Not Dead – It Went To a Farm Upstate… And You’re Paying For It

Let’s Build a Metric 6: Cyclomatic Complexity Explained

In the last installment of this series, I talked a good bit about lines of code. As it turns out, the question, “what is a line of code?” is actually more complex than it first appears.  Of the three different ways I mentioned to regard a line of code, I settled on “logical lines of code” as the one to use as part of assessing time to comprehend.

As promised, I sent code to use as part of the experiment, and got some responses. So, thanks to everyone who participated. If you’d like to sign up for the experiment, but have yet to do so, please feel free to click below.

Join the Experiment

Here is the code that went out for consideration. I’m not posting the results yet so that people can still submit without any anchoring effect and also because I’m not, in this installment, going to be updating the composite metric just yet.

The reason that I’m discussing this code is to show how simple it was. I mean, really, look at this code and think of all that’s missing.

  • There are no control flow statements.
  • There are no field accesses.
  • There is no interaction with collaborators.
  • There is no interaction with global state.
  • There is no internal scoping of any kind.

These are purely functional methods that take an integer as input, do things to it using local declarations, and then return it as output.  And via this approach, we’ve fired the first tracer bullet at isolating logical lines of code in a method.  So let’s set that aside for now and fire another one at an orthogonal concern.

Before, I talked about the meaning of a line of code.  Now I’d like to talk about the meaning of complexity in your methods.  Specifically here, I’m referring to what’s called “cyclomatic complexity.”  Cyclomatic complexity is a measure of the number of path’s through a piece of source code.  Let’s see a few examples to get the hang of it.

Consider the following method from the Pawn class in the Chess TDD codebase.

This method has a cyclomatic complexity of 1 because there is only one path through the code. Contrast that with the following method from the Board class.

The cyclomatic complexity of this method is 2 because there are two paths through it.

  1. The if condition evaluates to true and the method throws an exception.
  2. The if condition evaluates to false and the method finishes executing.

Be mindful that “if” isn’t the only way to create multiple paths through the code.  For instance, this method also has a cyclomatic complexity of 2 because of the ternary operator creating two different execution paths.

Cyclomatic complexity can increase quite rapidly, particularly when nested conditionals enter the equation. This method has a cyclomatic complexity of 4, and you can see it already is starting to get hard to figure out exactly why.

Imagine what it starts to look like as methods have things like large degrees of nesting, switch statements, and conditional after conditional. The cyclomatic complexity can soar to the point where it’s unlikely that every path through the code has even ever been executed, let alone tested.

So it stands to reason that something pretty simple to articulate, like complexity, can have a nuanced effect on the time to comprehend a code base. In the upcoming installment of our experiments, I’d like to focus on cyclomatic complexity and its effect on method time to comprehend.

But I’ll close out this post by offering up a video showing you one of the ways that NDepend allows you to browse around your code by cyclomatic complexity.

 

 Let’s Build a Metric 7: Counting the Inputs >

< Let’s Build a Metric 5: Flavors of Lines of Code

Why Should Managers Care About Static Analysis?

I’d like to talk a bit today about how, if you’re a dev manager for a team or teams that are responsible for .NET code bases, NDepend will help you lower your blood pressure and sleep better at night.  But first, bear with me as a I introduce and explain myself a bit.  It’ll be relevant.  I promise.

There’s been a relatively unique fluidity to my career, particularly in recent years.  The first 10 years or so of my professional career featured somewhat of a standard path from developer to management, with milestone stops along the way earning me designations like “senior” developer, team lead, and architect.  At the end of my salaried career, I had earned myself a CIO role, presiding over all development and IT operations for a company.  And, while I enjoyed the leadership responsibilities that came along with that sort of role, I ultimately decided to go off on my own into consulting, where I’d have more variety and a more fluid set of responsibilities.  These days, I do a combination of development coaching, management consulting, and content creation to earn my living.

The reason I mention all of this is that I’ve had success as a developer, architect, manager, and consultant to all of the above, and that multi-disciplined success has given me unique perspective on the interaction among those roles.  It’s shown me that, above all, what you need to be successful is the ability to trust your dev team.  But trust doesn’t come easily.  You didn’t get to where you are by blindly trusting anyone who tell you a pleasant story.

Here’s your essential conundrum as a manager.  You’re managing a team of intelligent humans that are doing things you don’t understand.  You can protest and claim to understand what they’re doing, but you don’t.  I learned this in my travels as a manager, even managing a team of .NET folks who turned to me to answer their toughest technical questions.  I may have had years and years of professional development on them, but I wasn’t there in the weeds with them, dealing with the challenges that they were, day in and day out.  I had to trust them because keeping my nose in their affairs didn’t scale.  So no matter how well you might understand the surrounding technologies and principles, you don’t understand what they’re doing at any given moment.

There’s a tendency toward entropy that kicks in when you’re managing people whose labor you don’t understand.  A lot of managers in this situation have to fight a panicky impulse to regain control via micromanagement.  I can’t really tell if they’re making good decisions in their coding, but I can make sure they’re getting in no later than 9, leaving no earlier than 5, writing at least 100 lines of code per day, and keeping unit test coverage about 90%.  You may laugh, but it’s a natural impulse, particularly in the face of a slipped deadline or low quality release.  The C-suite wants answers, and you’re caught in the middle, scrambling simultaneously to provide them and to figure out how to prevent this in the future.  You didn’t get ahead in your career through passivity, so the impulse is to seize control, even if perhaps you realize it’s a misguided impulse.

NDepend provides help here.  It allows you to keep an eye on metrics that aren’t obtuse if you structure things right.  I cannot overemphasize this caveat.  Renowned systems thinker W. Edwards Deming once explained that, “people with targets and jobs dependent upon meeting them will probably meet the targets – even if they have to destroy the enterprise to do it.”  Translated into our terms for this post, what this means is that if you measure your team’s productivity by them producing 100 lines of code per day, they will produce 100 lines of code per day, even if it means creating unstoppable death stars of terrible code.  So disabuse yourself of the notion that you can use this tool to evaluate your developers’ performance, and understand instead that you can use it to identify potential trouble spots in the code.

Pair with a developer or your team’s architect, and use NDepend’s phenomenal reporting capabilities to create a big, visible report on the state of your team’s code.  Here are some ideas for things that might interest you:

  • Which sections of the code are most heavily depended on, so that I can have a heads up when they are changed?
  • How coupled is a module to the rest of the code base?  So, for instance, if I wanted to swap in a new database solution, how hard would that be?
  • Are the most troublesome areas of the code base getting worse, staying the same, or improving?
  • Is the team’s development practice generally in line with commonly accepted good ideas?
  • What does the architecture of the code actually look like (as opposed to some design document that was written and may be out of date)?
  • Are there currently any code violations that the team has identified as critical mistakes?

When I was managing teams, I certainly would have been interested in the answers to these questions for strategic planning purposes.  How dependent you are on a database or whether a feature implementation has touched a dicey section of the code is valuable information for making important decisions (maybe it’s not worth considering a database switch and maybe we should add in more testing than usual for the upcoming release).

Not only can NDepend give you this information, but it can be integrated with your build to furnish it in a very clear, easy, and visible way.  Picture it integrated with your team’s build and delivered to your inbox in digest format on a daily basis.  This is possible to do with your build tool — you could work with the developers on your team to design a build customization where you can see if an area of the code is getting worse or how much coupling there is among the modules in the code.

Imagine it.  Instead of wondering whether your developers are actually working and whether they’re making good decisions, you can partner with them to keep you in the loop on important characteristics of the code, and also to keep you out of their hair for the details it’s better for them to worry about.  You get your information and early detection scheme, and they benefit from having an informed manager that asks intelligent questions only when it makes sense to do so.  And for you, that all adds up to better sleep and lower blood pressure.

Toward Bug Free Software: Lines of Defense

Hurrah!! Last week we released NDepend v6 RTM. Once again we relied on a 2 months private beta-testing period and a one month Release Candidate period to do our best to release a polished and stable product.

I’d like to talk about our lines of defense to fix as many bugs as possible. Except a few pieces of software in the world that can afford mathematical demonstrations to prove they are bug-free (like plane and some medical ones), all other pieces of software, including NDepend, rely on an empirical approach to chasing bugs and fixing them. An empirical approach is an evidence based approach that relies on direct observations and experimentation in the acquisition of new knowledge. An empirical approach will never lead to a bug-free product, but it can help a lot in keeping the number of bugs low, and make it so that bugs happen in rare enough situations that won’t have any impact on most user’s experience.

I could write many blog posts about each line of defense, after more than a decade applying them there is so much to say, but I want this post to be synthetic.

Production Crash Logs

Crashes are due to unhandled exceptions. Unhandled exceptions are due to situations at runtime that were unexpected, this typically includes:

  • null reference access,
  • division by zero,
  • disposed object accessed,
  • invalid cast,
  • wrong method call parameters,

A bug doesn’t necessarily lead to a crash, but a crash necessarily mean that there is a bug. Certainly the most important line of defense against bugs is to log all production crashes and relentlessly fix them all. The .NET Framework offers several unhandled exception access points, including:

In some environments like Visual Studio hosting, these access points don’t work and you’ll have to write code to catch all exceptions in all possible handlers of your program.

Of course some users are disconnected from internet, or behind a proxy, and you won’t get those production crashes. Our statistics show that this concerns only 20% of users at most. So being aware of 80% of all production crashes is certainly enough to have a good measure of what’s going wrong in a production. And because Windows and .NET are highly sophisticated technologies that are constantly evolving, you can expect plenty of issues that never occurred on your team’s machines! For example, the NDepend v6 Release Candidate Period shows us that users running NDepend v6 RC on a fresh Windows 8.1 or Windows 10 install, experienced crashes because of a P/Invoked win32 method that our code calls. Oddly enough this P/Invoked method behaves differently when .NET v3.5 is not installed on the machine!

The key to successful production crash logs, is to get as many useful data as possible per log. For example here is a production crash below we had a few week ago. When the same issue lead to several crash logs, we can start doing data mining on it. Do they all occur with the same stack trace? with the same high DPI resolution? on the same Windows platform version ? on the same machine only? Notice also the stack frames improved with IL offset retrieved with the StackFrame.GetILOffSet() method. Many times in the past, this alone lead us to the root cause.

ProductionCrash

 

You’ll notice that we only log crashes, we don’t have other forms of runtime logs, like logging every major event that happen (button clicked, panel opened, analysis started…). Our experience with logging events is that ultimately we logged too much or not enough of them. In both cases, the information that could help fixi a particular issue is then lost or hard to find. We found out that having verbose crash logs was enough. Sometime we can ask a user a question, like which action did you do just before the crash, but in the vast majority of real-world cases, this information is implicitly contained in the stack trace. For the same reason we don’t use remote debugging nor Windows dump files. In our context, custom and verbose production crash logs are enough.

Code Covered by Automatic Tests and Code Contracts

Not only are production crash logs an important line of defense, but they also demand just a few days of dedicated work to set up.

Having automatic tests is the second line of defense. Contrary to production crash log,s not only does it require a lot of work, but it even changes (forever) the way you write code. After a decade of writing automatic tests, a lot of conclusions can be made. In my attempt to remain synthetic in this post, let’s try to summarize the most relevant ones in a few points:

  • The number of tests is absolutely meaningless.  When it comes to unit/automatic tests, the king measure is the percentage of code covered by tests.
  • A high percentage of code covered by tests is not enough, everything that can be checked must be checked. In almost all literature related to unit testing, you’ll read that checks are assertions in unit test code. Few actually realize that assertions in the code itself are at least as important as assertions in unit-test code. There is a scientific terminology for assertions in code: Code Contracts. The important thing about code contracts is that they must fail both at manual-test time (see later) and at automatic-test time.
  • In NDepend, we use more than 20K simple Debug.Assert() in code. These are our contracts. Debug.Assert() are removed in production code. This is ok for us since we want maximum performance and having some sophisticated assertions at runtime can significantly slow down an application. Hence we decided to sacrifice an important line of defense in the name of performance. By using MS Code Contract that could let have assertions fail in production, we could increase the number and the accuracy of production crash logs. This is a choice you must make depending of your application. Let’s precise that NDepend.API actually supports MS Code Contract for its great ability to provide active documentation to users.
  • How much coverage is enough? My answer is 100%.
    • Typically, developers don’t want to lose time writing tests to cover say, properties getter and setter. My point is twofold: typically you can write higher level tests that will cover these + if these getters and setters contain assertions, this is even better.
    • Typically, developers claim that 10% of a class is difficult to test, it takes as much effort to test this 10% as it does to test the remaining 90%. Once again, they don’t want to lose time! My point is that this 10% of code is by definition not easily testable, as a consequence this code is both complex and not-well designed, and as a consequence it is certainly highly-bug-prone. So basically, the highest bug-prone portion of code ends up being not covered by automatic tests!! This is non-sense but this is the reality in most dev shops.
    • Typically, developers say that not everything is coverable by tests and I agree. Code calling blocking methods like MessageBox.Show() is just not coverable, this is why such calls must be mocked. Some other UI code can be especially tricky to test. The approach we use for this is that we designed our UIs in a way that the underlying code can be triggered by unit tests (some would say automated by tests) and then, we mostly rely on assertions in UI code itself to catch any potential regression. Of course when possible, assertions in tests are welcome and of course such UI code is highly decoupled from non-UI logic that has its own set of tests. Doing so has been proving work for our dev shop.
    • I’ll add that when a class or a group of classes are 100% covered by tests, experience shows that the innocent fact that suddenly a coverage hole appears, often means that there is a new problem, either in the code, in test code, or  in both. More often than not, we discovered regression bugs this way that were not caught by assertions. This is why we use tooling (aka NDepend) to check that all code that used to be 100% covered must remain 100% covered.
    • Last but not least, when a bug is fixed, if the fixed code portion is already covered by tests, it is easy to write assertions specific to the fix to avoid any regression in the future. And when most classes are 100% covered, more often than not it is a matter of minutes, or even seconds, to write such assertions.
  • If your application is successful enough, the code base will grow over the years. Finally, the biggest benefit you can expect from writing coverage-oriented automatic tests, is that the number of regression issues will remain under control because it won’t be proportional to the growing size of the code base. Keep in mind that only code covered by tests whose result is asserted somehow is protected by this line of defense.

Let’s illustrate this section with the NDepend 82.6% code coverage visualized with the NDepend metric view. We abide by our rules.

Coverage

Static Analysis and Code Review

I see static analysis as unit tests, but instead of exercising the code dynamically, static analysis exercises properties that can be inferred from the code. In the previous section for example, I wrote that if a class was 100% covered by tests, it must remain 100% covered by tests.  And I even underlined that if a hole suddenly pops up in this perfect coverage, more often than not, understanding the root cause of the hole will lead to a bug fix. This illustrates how static analysis is actually a line of defense against bugs.

In the previous analogy between static analysis and unit-tests, a test is actually a code rule. NDepend makes it easy to write custom code rules, it is just a matter of writing a C# LINQ query based on a fluent API, for example:

Code rules involving code coverage and diff after setting a baseline are especially suited to hunt regression bugs. But static analysis can handle many other properties of the code and it is not only related to bugs but also to code maintainability.

  • Code metrics: for example, methods with too many loops, if, else, switch, case… end up being non-understandable, hence non-maintainable. Counting these through the code metric Cyclomatic Complexity is a great way to assess when a method becomes too complex.
  • Dependencies: if the classes of your program are entangled, effects of any changes in the code becomes unpredictable. Static analysis can help to assess when classes and components are entangled.
  • Immutability: types that are used concurrently by several threads should be immutable, else you’ll have to protect state read/write access with complex lock strategies that will end up being un-maintainable. Static analysis can make sure that some classes remain immutable.
  • Dead code: dead code is code that can be removed safely, because it is not invoked anymore at runtime. Not only can it be removed, but it must be removed, because this extra code add unnecessary complexity to the program. Static analysis can find most of dead code in your program (yet not all).
  • API breaking change: if you present an API to your client, it is very easy to remove a public member without noticing and thus, breaking your clients code. Static analysis can compare two states of a program and can warn about this pitfall.
  • API usage: some APIs are intended to be used carefully. For example, a class that hold disposable fields must be itself disposable in general, except when the disposable field lifetime is not aligned with the class instances lifetime, which then sounds like a design problem.

The list of code properties that can be exercised by static analysis is endless. And the quoted ones refer to NDepend’s capabilities, some other tools like Resharper or CodeRush offer some other sorts of static analysis to warn about micro potential issues, like if a foreach variable is accessed from a closure for example, this can lead to major problems.

Static analysis is not only about directly finding bugs, but also about finding bug-prone situations that can decrease code understanding and maintainability.

Concerning code review, I don’t have much to say. This is static analysis except that the logic is statically checked by human instead of being checked by automatic rules. Thus it is highly imperfect and time consuming, yet we still practice it because experience shows that it helps finding issues that can hardly be found otherwise. The key to code review is to do it on bug-prone code, which include refactored code and new code that haven’t reached production yet.

Manual Tests and Beta Testing

No matter how good a team is at the previously explained lines of defense, if it fails at manual tests and beta testing, the end product will be buggy and ultimately unusable.

Because not all bugs lead to obvious crashes, tests done by humans are essential. For example, only a potential user can notice an incoherent numerical result in a UI.

Manual testing is like code review, highly imperfect and time consuming, and a team cannot capitalize on it. Yet, experience shows that it helps finding issue that can hardly be found otherwise.

We mentioned previously code contracts, they work hand in hand with manual tests. When, during a manual test session, I have the chance to break an assertion, this actually makes me happy 🙂 because I know that this is a great opportunity to fix a bug before it reaches the next release line.

Manual testing actually includes user feedback. Users are paying for a product and one main goal is to offer them a bug free product. Nevertheless, de-facto users are also testers and listening carefully to a user’s bug report and relentlessly struggling to fix them is an essential line of defense. Of course this does not only apply to bugs, but also to feature improvements, new feature suggestions, documentation gap, and much more, but these are another topics.

Using NDepend to Make You a Better Programmer

If you’re a software developer, particularly of the newly minted variety, the concept of static analysis might not seem approachable.  It sounds academic.  It sounds architect-y.  It sounds complicated.  I’ve seen this reaction from a lot of people in my career and I think that’s too bad.

If you delve into its complex depths, static analysis can be any and all of these things, but with the developers I mentor and coach, I like to introduce it as a game that makes you better at what you do.  You can use static analysis to give yourself feedback about your code that is both fast and anonymous, allowing you to improve via trial and error, rather than by soliciting feedback from people much more tenured than you and sometimes wincing as they lay into you a little.  And, perhaps best of all, you can calibrate the quality of your code with the broader development world, rather than just pleasing the guy who has hung around your company long enough to default his way into the “tech lead” role.

 

NDepend Rules

 

 

Take a look at some of the feedback that NDepend offers about your code.  “That method is too big” isn’t particularly intimidating, is it?  I mean, you might wonder at what you could do to compact a method, but it’s not some kind of esoteric rule written in gibberish.  You run NDepend on your code and you can see that there is some number of methods that the broader development community considers to be “too big.”

From there, you can start looking at ways to write smaller methods and to refactor some of your current ones to sneak in under the warning number.  This is the essence of gamification — you change the way you write code to get rid of the warnings.  You get better.  And it’s gratifying.

As you do this, another interesting thing starts to happen.  You start noticing that other developers continue to write large methods and when you run NDepend on their code, they light up the console with errors, whereas you do not with your code.  And so, you can have conversations with them that start with, “you know, this static analysis tool I’ve been using wants us to have smaller methods, and I’ve been working a lot on that, if you ever want a hand.”

You gain a reputation as being knowledgeable.  Before you know it, you can cite widely accepted static analysis rules and the design goals they imply.  You know these rules, and, via gamification, you have experience molding code to comply with them.  Even in cases where you might wind up overruled by the local team lead or architect, it’s no longer a simple matter of that person saying, “because I said so,” and just ending the conversation.  They have to engage with you and present cogent counter-arguments to your points.  You’re participating in important discussions in ways that you never have before.

If it sounds like I’m speaking from experience, I am.  Throughout my career, I’ve been relentless about figuring out ways to improve my craft, always trying to be a better programmer.  Early on, I was unsatisfied with a lot of arguments among developers around me that I knew boiled down to nothing more than personal preference, so I went out in search of empirical methods and broader knowledge, and that search brought me to static analysis.  I read about data and science behind particular choices in approaching software, and I schooled myself to adopt the approaches that had brought the best results.

Somewhere along that journey, I discovered NDepend and its effect on my approach to writing code was profound.  My methods shrank and became less complicated.  My architectural and design skills improved as I made it a point to avoid dependency cycles and needless coupling.  I boosted unit test coverage and learned well established language practices.  It was not long before people routinely asked me for design advice and code reviews.  And from there, it wasn’t long before I occupied actual lead and architect roles.

So, if you want to improve your craft and nudge your career along, don’t pass on static analysis, and don’t pass on NDepend.  NDepend is not just a tool for architects; it’s a tool for creating architects from the ranks of developers.  You’ll up your game, improve your craft, and even have some fun doing it.