# NDepend

Improve your .NET code quality with NDepend

## SOLID Design: The Interface Segregation Principle (ISP)

After having covered The Open-Close Principle (OCP), The Liskov Substitution Principle (LSP) and the Single Responsibility Principle (SRP) let’s talk about the Interface Segregation Principle (ISP) which is the I in the SOLID acronym. The ISP definition is:

Client should not be forced to depend on methods it does not use.

It is all about interface, the common abstractions available in most OOP language such as C#, VB.NET or Java. A more complete and actionable explanation of ISP is:

ISP splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them. Such shrunken interfaces are also called role interfaces.

## Roles and Responsibilities

When a class implements several shrunken role interfaces, it has several roles which might lead to think that such class has several responsibilities: it would then violate the Single Responsibility Services.

But a role is a finer-grained concept than a responsibility. An example of a role is the IDisposable interface:

This interface has a single method but it is implemented by a wide variety of classes: DB or network connections that need to be closed gracefully, UI elements that need to deallocate some bitmaps in memory… The only thing the IDisposable interface says to clients is that instances of IDisposable class needs a graceful shutdown.

Hence IDisposable represents a technical detail that the client needs to be aware of. It is much finer-grained concept than a responsibility.

## A small interface is not necessarily a good abstraction

A single method interface often makes sense, an IExecutor that Execute(), an IVisitor that Visit(), an IParent that exposes Children { get; }. Often, such minimalist interface should be generic. For example the interface ICloneable available since the .NET Framework v1.1 is nowadays considered as a code smell: when using it the client needs to downcast the cloned Object reference returned to do anything useful with the cloned instance.

ICloneable has another major drawback: it doesn’t inform the client if the clone operation is deep or shallow. This problem is even more serious than the Object reference downcasting one: it is a real design problem. As we can see a minimalist interface is not necessarily a good abstraction. In this example, the lack of information means ambiguity for the client. This would have been better design:

## A fat interface is not necessarily a design flaw

A rule like Avoid too large interfaces can certainly pinpoint most of the ISP violations. A threshold of 10 methods is proposed by default to define a too large interface.

However, as always with code metrics and static analysis, such rule can also spit some false positives. For example this fat interface is valid:

In such case the SuppressMessageAttribute can be used with a proper justification. Such justification embeds in the code itself the design decisions. It makes the source code more understandable and more maintainable:

## ISP and the Liskov Substitution Principle (LSP)

ISP and LSP are like 2 faces of the same coin:

• ISP is the client perspective: If an interface is too fat probably the client sees some behaviors it doesn’t care for.
• LSP is the implementer perspective: If an interface is too fat probably a class that implements it won’t implement all its behaviors. Some behavior will end up throwing something like a NotSupportedException.

Remember the ICollection<T> interface already discussed in the LSP article. This interface forces all its implementers to implement an Add() method. From the Array class perspective, implementing ICollection<T> is a violation of the LSP because array doesn’t support element adding:

The same way many clients will only need a read-only view of consumed collections. ICollection<T> also violates the ISP: it forces those clients to be coupled with Add() / Insert() / Remove() methods they don’t need. The introduction of IReadOnlyCollection<T> solved both ISP and LSP violations.

This example also shows that ISP doesn’t necessarily mean that a class should implement several lightweight interfaces. It is fine to nest interfaces like russian-nesting-dolls. ICollection<T> is a bit fat, it does a lot, read, add, insert, remove, count… But this interface is well-adapted both for classes that are read/write collections and for clients that work on read/write collection. It makes more sense to nest both read/write behaviors into ICollection<T> than to decompose both behaviors into IReadOnlyCollection<T> and an hypothetical IWriteOnlyCollection<T> interface.

Btw, maybe you noticed that ICollection<T> actually doesn’t implement IReadOnlyCollection<T>. In an ideal world it should implement it but IReadOnlyCollection<T> was introduced several years after ICollection<T> and backward compatibility must be preserved: for example this class would have been broken if ICollection<T> was implementing IReadOnlyCollection<T>, because of the explicit interface implementation usage on ICollection<T>.Count:

## Conclusion

ISP is about preventing inadvertent coupling between a client and some behaviors he/she won’t need. Being coupled with something unneeded is a problem:

• In the best case it is a waste: this forces the client to consume precious brain-cycles to consider something he/she doesn’t need.
• In the worst case it is error-prone: the client ends-up misusing the extra behaviors, like attempting to add an element to an array through ICollection<T>.Add().

As for all SOLID principles, ISP is better applied if you practice test-first, or at least, if you write tests and code at the same time. ISP is about the client perspective and writing tests transforms you for a while into a client of your code.

Out of curiosity I wrote this code query that can be re-used to attempt to measure compliance with the ISP.

This query estimates the ratio of usage of the methods of an interface over the maximum usage (maximum usage being when all types consuming an interface call all methods of the interface). Some work would be needed to transform this experimental query into a formal rule. For example the query needs to be smart about methods overloaded that can arguably be considered as a single method.

Nevertheless here are the raw results for non-public interfaces of the .NET framework implementation. Only non-public interfaces are considered because we need to also analyze some real clients of the interface:

## Are SOLID principles Cargo Cult?

My last post about SOLID Design: The Single Responsibility Principle (SRP) generated some discussion on reddit. The discussion originated from a remark considering SOLID principles as Cargo Cult. Taking account the definition of Cargo Cult the metaphor is a bit provocative but it is not unfounded.

cargo cult is a belief system among members of a relatively undeveloped society in which adherents practice superstitious rituals hoping to bring modern goods supplied by a more technologically advanced society

The recent Boeing’s 737 Max fiasco revealed that some parts of their software have been outsourced to $9-an-hour engineers. Those engineers shouldn’t be blamed for not achieving top notch software taking account the budget. Nevertheless it is clear that a lot of software written nowadays look like this cargo cult plane. For many real-world developers, SOLID principles are superstitious rituals whose primary goal is to succeed during job interview. The SRP article underlines that SRP is the only SOLID principle not related to the usage of abstraction and polymorphism. SRP is about logic partitioning into code: which logic should be declared in which class. But SRP is so vague it is practically useless from its two definitions. Definition 1: A class should have a single responsibility and this responsibility should be entirely encapsulated by the class. Definition 2: A class should have one reason to change. One can justify any class design choice by tweaking somehow what is a responsibility or what is a reason to change. In other words, as someone wrote in comment: Most people who “practice” it don’t actually know what it means and use it as an excuse to do whatever the hell they were going to do anyways. We can feel bitterness in those comments, certainly coming from seasoned developers whose job is to fix mistakes of$9 an hour engineers.

## SOLID Principles vs. OOP Patterns

We must remember that SOLID principles emerged in the 80s and 90s from the work of world-class OOP experts like Robert C. Martin (Uncle Bob) and Bertrand Meyer. Software writing is often considered as an art. Terminologies such as clean code or beautiful code have been widely used. But art is a subjective activity. In this context, SOLID principles necessarily remain vague and subject to interpretation. And this is what makes the difference between a SOLID principle and an OOP pattern:

• A SOLID Principle is subjective. It helps to guide the usage of powerful concepts of Object Oriented Programming (OOP).
• An OOP Pattern is objective. It is a set of recipes to implement a well identified situation with the OOP concepts.

Despite a restraint number of keywords and operators, the OOP toolbelt of languages such as C# or Java is very rich. With a few dozens of characters it is possible to write code that puzzle experts. C# especially gets richer and richer with many syntactic sugars to express complex situations with just a few characters. This power is a double edged sword: seasoned developers can write neat and compact code. But on the other hand it is easy to misuse this power, especially for junior developers and all those that write code just to pay their bills.

## Always keep in mind the KISS principle

Someone wrote in comments: “SOLID encourages abstraction, and abstraction increases complexity. It’s not always worth it, but it’s always presented as the non-plus ultra of good approaches.”

The only reason to be for abstraction in OOP is to simplify the implementation of a complex business rule.

• Abstracting Circle, Rectangle and Triangle with an IShape interface will dramatically simplify the implementation of a shape drawing software.
• On the other hand, creating an interface for each class is a waste of resource: not every concepts in your program deserve an abstraction.

This is why the Keep It Simple Stupid KISS principle should be always kept in mind: don’t add up extra implementation complexity on top of the business complexity.

## SOLID and Static Analysis

I am in the .NET static analysis industry since 2004. At that time I was consulting for large companies with massive legacy apps that were very costly to maintain. Books like Robert Martin’s Agile Principles, Patterns, and Practices made me realize that the source code is data. This data can be measured with code metrics. And the same way relational data can be crawled with SQL queries, code as data can be crawled with code queries. For example:

This query will objectively match complex methods not fully covered by tests. There are situations where one can argue that static analysis returns false positives but there is no justification for complex methods not well tested.

Not all aspects of SOLID principles can be objectively measured and verified. However static analysis can help bring objectiveness. For example:

## SOLID and Testability

Regularly applying such rules will avoid taking SOLID too far to the point it becomes detrimental. However there are still all those aspects of SOLID, and code design in general, that must be left to creativity and interpretation. Experience in software development helps a lot here: over the years one refines his/her gut feeling about which design will increase flexibility and maintainability.

By definition juniors developer have no experience. However anyone can relentlessly struggle for 100% code coverage by tests. Being able to fully cover your code means, by definition, that your code is testable. Testability doesn’t come by chance. The properties that leads to full testability are the same properties that leads to high maintainability. Those properties include:

• Easiness to use API
• Domain classes well isolated
• Careful map of logic to classes
• Short classes and short methods
• Cohesive classes
• Abstractions and polymorphism used judiciously
• Careful management of states mutability

Not everyone is a senior developer with a passion for well designed code. As a consequence Cargo Cult usage of SOLID principles is common. To improve the design some objectivity needs to be added in the development process. Here are my 3 advices for that:

• KISS principle first, always struggle for simplicity: if it is complicated it is not SOLID.
• Use static analysis to automatically monitor some measurable aspects of SOLID. Gross violations of code quality rules and metrics are also SOLID principles violations.
• Refactor your code until it becomes seamlessly 100% coverable by tests. Code that cannot be easily 100% covered by tests is not SOLID.

## Exploring .NET Core 3.0 new API

.NET Core 3.0 is representing a major step for the .NET community. It is interesting to analyze what’s new in the API directly from the compiled bits. In this post I will first explain how to diff .NET Core 3.0 against .NET Core 2.2 with NDepend, and then how to browse diff results.

Arguably the biggest progress of .NET Core 3.0 will be the support for Winforms and WPF on the Windows platform. Since everything is new here, compare to .NET Core 2.2, we won’t analyze this part. However it will be interesting to analyze .NET Fx Winforms/WPF APIs vs .NET Core 3.0 Winforms/WPF APIs in another post (that I finally wrote here).

## Analyzing two versions of .NET Core with NDepend

It takes a few minutes to download NDepend trial, install it and start VisualNDepend.exe, and it takes a few minutes to compare .NET Core 3.0 against .NET Core 2.2. If you want to browse the diff on your machine, expect 5 to 10 minutes to get hands-on.

First Start VisualNDepend.exe and click Compare 2 versions of a code base:

For both builds, choose Add Assemblies in Folder:

• Choose C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.2.2  for Older Build
• Choose C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.0.0-preview-27324-5 for Newer Build

Respectively 156 and 161 assemblies are gathered. Click Ok to run two analysis, on older and newer build. Both analysis results will be then diffed automatically.

## Querying new API

Let’s start with a few CQLinq code queries to explore the new .NET Core 3.0 APIs:

This query match all new public code elements, including new assemblies, namespace, types, methods and fields:

Use the NDepend query result to browse this large new API set : 5 new assemblies, 83 new namespaces, 297 new types, 4 924 new methods and 307 new fields. Note that code elements with pink background are not matched by the query, they are just here for preserving the code hierarchy in the result:

Download here this long list obtained by exporting the query result to excel. For a better result formatting I actually used this refined query to show properly parent assemblies/namespaces/types in excel columns:

It is interesting to just focus on the 297 new public types with the code query below. Download the list here or browse the same list at the end of this post.

It is also interesting to browse the new 1.101 public methods and 38 public fields added on public types that existed already in .NET Core 2.2.  Download this list here.

## API Breaking Changes

NDepend proposes 6 default rules to browse API breaking changes.

These rules matche 19 public types removed from .NET Core 2.2 (see list below) 176 public methods removed and 36 public fields removed

## Listing Methods Changed

Exploring the API evolution is useful for API consumers. For those working on the framework .NET Core itself, it is interesting to also browse implementation changes. The NDepend search by change panel proposes various options for that. Note that this search panel is actually a code query generator. The Edit query button proposes to edit and refine the currently generated query.

Another interesting point is that it is a semantic implementation change. All matched methods do behave differently at runtime. This makes this tool ideal to plan code change review without bothering with formatting and comments change.

Matched code elements can be highlighted in the metric view. From the screenshot above we can see at a glance that System.Xml and System.Data are much more stable than System.RunTime for example. By zooming in the view, we can get more information about which code was churned.

In the query result panel, a code element is underlined when its implementation changed. If you have compiled both source versions on your machine and analyzed those compiled versions, you can right click an underlined method and directly compare the diff in source code.

I hope you see value both in the results offered and in the how-to-diff procedure that can be applied to any .NET code base, assuming you have 2 versions to compare.

## New .NET Core 3.0 types

Here is the list of the 297 new types added to .NET Core 3.0.

## Advanced Code Search : A Case Study

This morning I stumbled on a complex test to write. The need was to create and show a custom Form (written with Windows Form) that relies on the System.ComponentModel.BackgroundWorker to do initialization stuff without freezing the UI. The test is complex because after creating and showing the form, it must wait somehow to release the UI thread for a while to let the BackgroundWorker achieve the RunWorkerCompleted on the UI thread.

I know that this is something we’ve done in the past and I know this is tricky enough to not reinvent the wheel. But with a test suite of over 13.000 tests this is quite challenging to find where we did that. So I decided to use NDepend querying facility to search.

First I analyze all NDepend assemblies, test assemblies included. Then I generate a code query to match all classes that derive from Form. This can be done from the NDepend Search panel : search Form by name in third-party types and then use a right-click menu to generate the code query:

The CQLinq code query generated is:

60 classes are matched:

Let’s refine this query to match all methods that create any of those form classes.This could be achieved by iterating over (all methods) x (all form classes), but the NDepend.API extension method ThatCreateAny() acts like a join and operates in a linear time. For our search scenario, waiting a few seconds to get a search result is not a problem. But for a code rule written with CQLinq, this is important to run it as fast as possible in a few milliseconds, to run all queries and rules often in Visual Studio within a few seconds, hence the query performance entry on the documentation.

280 methods are instantiating some form classes. Let’s refine the query to match only tests method. The cleanest way would be to check for the usage of TestAttribute, but here just checking for parent assemblies names that contain “Test” is enough:

Still 122 test methods matched.

Before filtering the result even more, let’s refine the query to display for each test the form class(es) it instantiates. This can be achieved with a LINQ range variable formsCreated that we use in the result:

We can now browse which form(s) are instantiated by each test:

Finally let’s browse only tests that use some asynchronous related code. Many ways can be used to check for asynchronous usages. The easiest way is certainly to look at methods called by a test method, and check which ones have named related to async stuff. I tried a few words like “Async” “Sync” “Thread” “TimeOut” “Wait”… and “Wait” worked:

In the source code of the highlighted test I had everything I needed for my scenario, including a link to a tricky stackoverflow answer that we found years ago. I found what I needed within a few minutes and had a bit of fun. I hope the methodology and the resulting query can be adapted to your advanced search scenarios.

## Log4net vs NLog: A Comparison of How They Affect Codebases

Ah, the old “versus” Google search.  Invariably, you’re in the research stage of some decision when you type this word into a search engine.  Probably not something like Coke vs Pepsi.  Maybe “C# vs Java for enterprise projects” or “angular vs react.”  Or if you landed here, perhaps you’re looking at “log4net vs NLog.”

With a search like this, you expect a certain standard script.  The writer should describe each one anecdotally, perhaps with a history.  Then comes the matrix with a list of features and checks and exes for each one, followed by a sober list of strengths and weaknesses.  Then, with a flourish, I should finish with a soggy conclusion that it really depends on your needs, but I maybe kinda sorta like one better.

I’m not going to do any of that. Continue reading Log4net vs NLog: A Comparison of How They Affect Codebases

## The Singleton Design Pattern: Impact Quantified

This post has been about a month in the offing.  Back in August, I wrote about what the singleton pattern costs you.  This prompted a good bit of discussion, most of which was (as it always is) anecdotal.  So a month ago, I conceived of an experiment that I called the singleton challenge.  Well, the results are in.  I’m going to quantify the impact of the singleton design pattern on codebases.

I would like to offer an up-front caveat.  I’ve been listening lately to a fascinating audiobook called “How to Measure Anything,” and it has some wisdom for this situation.  Measurement is primarily about reducing uncertainty.  And one of the driving lessons of the book is that you can measure things — reduce uncertainty — without getting published in a scientific journal.

I mention that because it’s what I’ve done here.  I’ll get into my methodology momentarily, but I’ll start by conceding the fact that I didn’t (and couldn’t) control for all variables.  I looked for correlation as a starting point because going for causation might prove prohibitive.  But I think I took a much bigger bite out of trying to quantify this than anyone has so far.  If they have, I’ve never seen it.

### A Quick Overview of the Methodology

As I’ve mentioned in the past on this blog, I earn a decent chunk of my consulting income doing application portfolio assessments.  I live and breathe static code analysis.  So over the years, I’ve developed an arsenal of techniques and intellectual property.

This IP includes an extensive codebase assessor that makes use of the NDepend API to analyze codebases en masse, store the results, and report on them.  So I took this thing and pointed it at GitHub.  I then stored information about a lot of codebases.

But let’s get specific.  Here’s a series of quick-hitter bullets about the experiment that I ran:

• I found this page with links to tons of C# projects on GitHub, so I used that as a “random” selection of codebases that I could analyze.
• I gave my mass analyzer an ordered list of the codebase URLs and turned it loose.
• Anything that didn’t download properly, decompress properly, or compile properly (migrating for Core, restoring NuGet packages, and building from command line) I discarded.  This probably actually creates a bias toward better codebases.
• Minus problematic codebases, I built all solutions in the directory structure and made use of all compiled, non-third-party DLLs for analysis.
• I stored the results in my database and queried the same for the results in the rest of the post.

I should also note that, while I invited anyone to run analysis on their own code, nobody took me up on it.  (By all means, still do it, if you like.)

### Singleton Design Pattern: the Results In Broad Strokes

First, let’s look at the scope of the experiment in terms of the code I crunched.  I analyzed

• 100 codebases
• 986 assemblies
• 5,086 namespaces
• 72,615 types
• 501,257 methods
• 1,495,003 lines of code

From there, I filtered down raw numbers a bit.  I won’t go into all of the details because that would make this an immensely long post.  But suffice it to say that I discounted certain pieces of code, such as compiler-generated methods, default constructors, etc.  I adjusted this so we’d look exclusively at code that developers on these projects wrote.

Now, let’s look at some statistics regarding the singleton design pattern in these codebases.  NDepend has functionality for detecting singletons, which I used.  I also used more of its functionality to distinguish between stateless singleton implementations and ones containing mutable state.  Here’s how that breaks down:

## Static analysis of .NET Core 2.0 applications

NDepend v2017.3 has just been released with major improvements. One of the most requested features, now available, is the support for analyzing .NET Core 2.0 and .NET Standard 2.0 projects. .NET Core and its main flavor, ASP.NET Core, represents a major evolution for the .NET platform. Let’s have a look at how NDepend is analyzing .NET Core code.

## Resolving .NET Core third party assemblies

In this post I’ll analyze the OSS application ASP.NET Core / EntityFramework MusicStore hosted on github. From the Visual Studio solution file, NDepend is resolving the application assembly MusicStore.dll and also two test assemblies that we won’t analyze here. In the screenshot below, we can see that:

• NDepend recognizes the .NET profile, .NET Core 2.0, for this application.
• It resolves several folders on the machine that are related to .NET Core, especially NuGet package folders.
• It resolves all 77 third-party assemblies referenced by MusicStore.dll. This is important since many code rules and other NDepend features take into account what the application code is using.

It is worth noticing that the .NET Core platform assemblies have high granularity. A simple website like MusicStore references no fewer than 77 assemblies. This is because the .NET Core framework is implemented through a few NuGet packages that each contain many assemblies. The idea is to release the application only with needed assemblies, in order to reduce the memory footprint.

NDepend v2017.3 has a new heuristic to resolve .NET Core assemblies. This heuristic is based on .deps.json files that contain the names of the NuGet packages referenced. Here we can see that 3 NuGet packages are referenced by MusicStore. From these package names, the heuristic will resolve third-party assemblies (in the NuGet store) referenced by the application assemblies (MusicStore.dll in our case).

## Analyzing .NET Standard assemblies

Let’s be clear that NDepend v2017.3 can also analyze .NET Standard assemblies. Interestingly enough, since .NET Standard 2.0, .NET Standard assemblies reference a unique assembly named netstandard.dll and found in C:\Users\[user]\.nuget\packages\NETStandard.Library\2.0.0\build\netstandard2.0\ref\netstandard.dll.

By decompiling this assembly, we can see that it doesn’t contain any implementation, but it does contain all types that are part of .NET Standard 2.0. This makes sense if we remember that .NET Standard is not an implementation, but is a set of APIs implemented by various .NET profiles, including .NET Core 2.0, the .NET Framework v4.6.1, Mono 5.4 and more.

## Browsing how the application is using .NET Core

Let’s come back to the MusicStore application that references 77 assemblies. This assembly granularity makes it impractical to browse dependencies with the dependency graph, since this generates dozens of items. We can see that NDepend suggests viewing this graph as a dependency matrix instead.

The NDepend dependency matrix can scale seamlessly on a large number of items. The numbers in the cells also provide a good hint about the represented coupling. For example, here we can see that  22 members of the assembly Microsoft.EntityFrameworkCore.dll are used by 32 methods of the assembly MusicStore.dll, and a menu lets us dig into this coupling.

Clicking the menu item Open this dependency shows a new dependency matrix where only members involved are kept (the 32 elements in column are using the 22 elements in rows). This way you can easily dig into which part of the application is using what.

## All NDepend features now work when analyzing .NET Core

We saw how to browse the structure of a .NET Core application, but let’s underline that all NDepend features now work when analyzing .NET Core applications. On the Dashboard we can see code quality metrics related to Quality Gates, Code Rules, Issues and Technical Debt.

Also, most of the default code rules have been improved to avoid reporting false positives on .NET Core projects.

We hope you’ll enjoy using all your favorite NDepend features on your .NET Core projects!

## Understanding Cyclomatic Complexity

Wander the halls of an enterprise software outfit looking to improve, and you’ll hear certain things.  First and foremost, you’ll probably hear about unit test coverage.  But, beyond that, you’ll hear discussion of a smattering of other metrics, including cyclomatic complexity.

It’s actually sort of funny.  I mean, I understand why this happens, but hearing middle managers say “test coverage” and “cyclomatic complexity” has the same jarring effect as hearing developers spout business-meeting-speak.  It’s just not what you’d naturally expect.

And you wouldn’t expect it for good reason.  As I’ve argued in the past, code coverage shouldn’t be a management concern.  Nor should cyclomatic complexity.  These are shop-heavy specifics about particular code properties.  If management needs to micromanage at this level of granularity, you have a systemic problem.  You should worry about these properties of your code so that no one else has to.

With that in mind, I’d like to focus specifically on cyclomatic complexity today.  You’ve probably heard this term before.  You may even be able to rattle off a definition.  But let’s take a look in great detail to avoid misconceptions and clear up any hazy areas.

### Defining Cyclomatic Complexity

First of all, let’s get a specific working definition.  This is actually surprisingly difficult because not all sources agree on the exact method for computing it.

How can that be?  Well, the term was dreamed up by a man named Thomas McCabe back in 1976.  He wanted a way to measure “the number of linearly independent paths through a program’s source code.”  But beyond that, he didn’t specify the mechanics exactly, leaving that instead to implementers of the metric.

He did, however, give it an intimidating-sounding name.  I mean, complexity makes sense, but what does “cyclomatic” mean, exactly?  Well, “cyclomatic number” serves as an alias for something more commonly called circuit rank.  Circuit rank measures the number of independent cycles within a cyclic graph.  So I suppose he coined the neologism “cyclomatic complexity” by borrowing a relatively obscure discrete math concept for path independence and applying it to code complexity.

Well then.  Now we have cyclomatic complexity, demystified as a term.  Let’s get our hands dirty with examples and implications.

## Understanding the Difference Between Static And Dynamic Code Analysis

I’m going to cover some relative basics today.  At least, they’re basics when it comes to differentiating between static and dynamic code analysis.  If you’re new to the software development world, you may have no idea what I’m talking about.  Of course, you might be a software development veteran and still not have a great idea.

So I’ll start from basic principles and not assume you’re familiar with the distinction.  But don’t worry if you already know a bit.  I’ll do my best to keep things lively for all reading.

### Static and Dynamic Code Analysis: an Allegory

So as not to bore anyone, bear with me as I plant my tongue in cheek a bit and offer an “allegory” that neither personifies intangible ideas nor has any real literary value.  Really, I’m just trying to make the subject of static and dynamic code analysis the slightest bit fun on its face.

So pull your fingers off the keyboard and let’s head down to the kitchen.  We’re going to do some cooking.  And in order to that, we’re going to need a recipe for, say, chili.

We all know how recipes work in the general life sense.  But let’s break the cooking activity into two basic components.  First, you have the part where you read and synthesize the recipe, prepping your materials and understanding how things will work.  And then you have the execution portion of the activity, wherein you do the actual cooking — and then, if all goes well, the eating.

### Static and Dynamic Recipe Analysis

Having conceived of preparing the recipe in two lights, think in a bit more detail about each activity.  What defines them?

First, the recipe synthesis.  Sure, you read through it to get an overview from a procedural perspective, rehearsing what you might do.  But you also make inferences about the eventual results.  If you’ve never actually had chili as a dish, you might contemplate the ingredients and what they’d taste like together.  Beef, tomato sauce, beans, spicy additives…an idea of the flavor forms in your head.

You can also recognize the potential for trouble.  The recipe calls for cilantro, but you have a dinner guest allergic to cilantro.  Yikes!  Reading through the recipe, you anticipate that following it verbatim will create a disastrous result, so you tweak it a little.  You omit the cilantro and double check against other allergies and dining preferences.

But then you have the actual execution portion of preparing a recipe.  However imaginative you might be, picturing the flavor makes a poor substitute for experiencing it.  As you prepare the food, you sample it for yourself so that you can make adjustments as you go.  You observe the meat to make sure it really does brown after a few minutes on high heat, and then you check on the onions to make sure they caramelize.  You observe, inspect, and adapt based on what’s happening around you.

Then you celebrate success by throwing cheese on the result and eating until you’re uncomfortably full.

## The Role of Static Analysis in Testing

“What do you do?”

In the United States, people ask this almost immediately upon meeting one another for the first time.  These days, I answer the question by saying that I do IT management consulting.  That always feels kind of weird rolling off the tongue, but it accurately describes how I’ve earned a living.

If you’re wondering what this means, basically I advise leadership in IT organizations.  I help managers, directors, and executives better understand how to manage and relate to the software developers in their groups.  So you might (but hopefully won’t) hear me say things like, “You should stop giving out pay raises on the basis of who commits the most lines of code.”

In this line of work, I get some interesting questions.  Often, these questions orient around how to do more with less.  “How can we keep the business happy when we’re understaffed?”  “What do we do to get away from this tech debt?”  “How should we prioritize our work?”  That sort of thing.

Sometimes, they get specific.  And weird.  “If we do this dependency injection thing, do we really need to deploy as often?”  Or “If we implement static analysis, do we still need to do QA?”

I’d like to focus on the latter question today — but not because it’s a particularly good or thought-provoking one.  People want to do more with less, which I get. But while that particular question is a bit of a non sequitur, it does raise an interesting discussion topic: what is the role of static analysis in testing?

### Static Analysis in Testing: An Improbable (But Real) Relationship

If you examine it on the surface, you won’t notice much overlap between testing and static analysis.  Static analysis involves analyzing code without executing it, whereas QA involves executing the code without analyzing it (among other things).

A more generous interpretation, however, starts to show a relationship.  For instance, one could argue that both activities relate deeply to code quality.  Static analysis speaks to properties of the code and can give you early warnings about potential problems.  QA takes a black box approach to examining the code’s behavior, but it can confirm the problems about which you’ve received warnings.

But let’s dive even a bit deeper than that.  The fact that they have some purview overlap doesn’t speak to strategy.  I’d like to talk about how you can leverage static analysis as part of your testing strategy — directly using static analysis in testing.