The Modern .NET Show

S08E10 - NDepend with Patrick Smacchia: Scaling .NET Code Quality

Sponsors

Support for this episode of The Modern .NET Show comes from the following sponsors. Please take a moment to learn more about their products and services:

Please also see the full sponsor message(s) in the episode transcription for more details of their products and services, and offers exclusive to listeners of The Modern .NET Show.

Thank you to the sponsors for supporting the show.

Embedded Player

S08E10 - NDepend with Patrick Smacchia: Scaling .NET Code Quality
The Modern .NET Show

S08E10 - NDepend with Patrick Smacchia: Scaling .NET Code Quality

Supporting The Show

If this episode was interesting or useful to you, please consider supporting the show with one of the above options.

Episode Summary

This episode centres around NDepend, a static analysis tool for .NET developers, described by Patrick as being mature, having started in 2004. The conversation establishes that unlike tools like Resharper which aid during coding, NDepend is designed for analysing completed codebases—especially large, complex, and often older ’legacy’ systems. It doesn’t simply look for syntax errors, but dives into code quality, maintainability, and potential security issues, providing a high-level understanding of the entire solution, not just individual methods or classes. This holistic view allows developers to pinpoint areas needing improvement and prioritize work effectively.

A key distinction highlighted is between static and dynamic analysis. NDepend operates statically, examining the code directly, whilst dynamic analysis involves running the code and observing its behaviour. The interview emphasized NDepend’s unique approach of quantifying technical debt – the implicit cost of addressing code quality issues – and linking it to estimated effort (time or money) needed for remediation. This allows for informed decision-making, particularly when presenting issues to project managers. Patrick described a useful analogy of technical debt as the ’engine light’ on a car – ignore it at your peril, and you risk bigger problems down the line.

The power of NDepend lies in its use of a query language (CQLinq) built upon C# Linq. This allows developers to construct highly specific analyses, querying the code based on various metrics and criteria. While NDepend provides 150 pre-defined rules, the ability to create custom queries enables targeted investigation of specific concerns within a codebase. Furthermore, NDepend integrates with other tools like Resharper and can import data from code coverage tools, creating a unified picture of code health. The conversation also noted a focus on minimising ‘false positives’ – inaccurate warnings that can clutter analysis results.

Patrick discussed how NDepend is used internally at his company, having been ‘dogfooded’ for two decades. They prioritise reducing technical debt by focusing on areas where tests are lacking, and quantifying the risk associated with untestable or complex code. He highlighted the importance of assertion within code itself, creating a self-documenting, safer foundation that aids testability and code comprehension. The conversation touched upon the integration of AI tools, not as a replacement for developer expertise, but as a potential aid, particularly in analysing AI-generated code.

Episode Transcription

So the interest plays a lot of a huge role. Like for example a security issue, it can take you maybe half a day to fix, or maybe one hour to fix; so it’s very easy to fix. But if you don’t fix it, you get so… you’ll get so many angry users that it may be, it maybe, it will cost you your entire business; you see. So this can be seen as an interest.

- Patrick Smacchia

Hey everyone, and welcome back to The Modern .NET Show; the premier .NET podcast, focusing entirely on the knowledge, tools, and frameworks that all .NET developers should have in their toolbox. I’m your host Jamie Taylor, bringing you conversations with the brightest minds in the .NET ecosystem.

Today, we’re joined by Patrick Smacchia to talk about NDepend, technical debt and the interest it accrues (something that’s often forgotten about), and how NDepend can help you to keep your tech debt (and it’s interest) low.

But the thing we see is that the edge code is usually the code where you get the bugs. So you end up writing some quick tests that can cover 90% of your code, but your 10% here is not tested. And because it’s not well implemented and it’s likely to contain the bug. So, maybe you should refactor your code and make your class testable.

- Patrick Smacchia

Along the way, we talked about the common pitfalls that most developers make when writing code, and how to keep your code both testable and easy to maintain.

So let’s sit back, open up a terminal, type in dotnet new podcast and we’ll dive into the core of Modern .NET.

Jamie : So Patrick, welcome back to the show. It has been a very long time since we last talked. The world has moved, the system we’re about to talk about has moved and improved, and .NET itself has also moved and improved. It’s been an amazing couple of years. How are you doing?

Patrick : Hi Jamie, thanks for the invitation. So I’m doing pretty well. Still working full-time on NDepend in the beautiful island of Mauritius. And yeah, we also moved forward a lot during the last years. I think it was we talked three years ago, just before ChatGPT became a tsunami in the industry. So I think a lot of interesting things to to talk about today.

Jamie : Yeah, yeah.

AI was the thing that it feels like it came out of nowhere. But actually, the LLM technology behind it has been slowly evolving since the 50s, and it’s based on a research paper put out by Google called " all you need is attention," right? Yeah. But everybody goes, o"h, this has come out of nowhere," but actually, it’s been worked on for years and years. So it’s been really interesting to see just how fast that seems to have come about.

Patrick : Yeah, yeah. Honestly, I didn’t see it coming that quick. But yeah, it changed everything.

Jamie : It really did, it really did.

Before we get to that, I was wondering for the folks who maybe haven’t heard your previous episode, which I will be Linqed, folks, so go listen to that because you’ll learn a little bit more about NDepend. We’re gonna talk about NDepend today anyway, but you know, go listen to that one too.

So for the folks who haven’t heard that previous episode, I wonder, would you mind giving folks a real quick brief bio about, you know? the kind of work you do and all that kind of stuff and then we’ll start our conversation after that about NDepend.

Patrick : Yeah sure. So basically NDepend is a is a static analyser and code quality and security tools developed by in .NET for .NET developer. So it’s pretty mature. We started it, I think it was in 2004 and became commercial in 2007, so it’s pretty mature.

It followed all the .NET trends, including Silverlight, if you remember. So we went through all the all the .NET trends, but now there is really one big .NET trend which is .NET Core or .NET 9, and soon .NET 10.

It’s a tool for .NET developer and what it brings you is a good understanding of your codebase, of the quality where you have problems, where the tests are not enough, for example. And it integrates both in the IDE, so mostly Visual Studio, but also it interacts with VS Code and Rider. And also it integrates into your CI/CD and it generates some web reports. So you can use it everywhere in your workflow and also in Azure DevOps and also as a GitHub action.

So basically this is the four the four SKU of the project. So no matter how you work with .NET, how you develop your solution with .NET, it can be here and provide you the information you need to improve your code.

Jamie : Awesome. First thing about that then is: it’s a static analyser. So you know we get we get the people listening from all over the journey into .NET. I wonder, could you break down what a static analyser is? I know you touched on a couple of things there that are related to that, like giving you advice on things that you can maybe improve, and looking for bugs that you may have missed and stuff like that.

From a software engineering, computer science-y background, what is a static analyser, right? I know I need one, but what is it?

Patrick : That’s a very, very good question.

So basically the world of analyser, of code analyser, is divided in two. There are static analyser and there is dynamic analyser. So static it’s very easy, it just analyses your code, your source code, you develop every day. While the dynamic analyser is running your code, so for example it can run through a test or through a profiler. So it runs your code and it gathers data from running your code.

So you get these two worlds of data that are the static, which is the the source code side, and the dynamic, which is the execution side.

Jamie : Okay. And then it uses that information to give me a bit of a an idea of things that I maybe need to look at with my code. So for instance, I’m you know, if folks are familiar with say Resharper and StyleCop and .editorconfig, it’s not those things, right? It’s a little bit more involved than that, right?

Patrick : It’s a bit different.

Resharper is actually, it interact with Resharper. We’ll talk, that’s a new thing we introduced. So I’ll talk about it later. Basically, we use Resharper, we are addicted to Resharper like a lot of people, or maybe to wider for those that quit Visual Studio.

We use it a lot for writing code, you know, Resharper is the champion of writing code. And it tells you a lot of things also about your code. "You can refactor this this way. This portion of code you can remove because the compiler can infer it." It’s very good at doing this these things.

And what I like to say is that Resharper is good to look at your code in a micro… like, in the scope of a class or of a method, it’s really good to have Resharper with you. That can help you write your code.

Why a tool for NDepend? It’s more about wide solution analysis or even multiple solutions. If you… I mean in the terms of SLN file in Visual Studio. So if you have a large legacy, NDepend is good at looking this large legacy at a wall, and at telling you where you should improve your code, where it should be refactored, why do you get all this maintainability problem?

So the really two usecase of NDepend is when you have a big legacy, and a lot of enterprise level people have a big legacy these days in .NET, and you cannot fix bug and you cannot add feature without a lot of pain because your code is not well tested, because it has been written by many different people with a lot of turnover. You know, all this, all this problem end up with a large code base that is difficult to maintain. And NDepend is here to address this kind of problem.

Jamie : Okay, okay. So I’m seeing like, and please correct me if I’m wrong. Something like a Resharper or similar tools is useful for when I’m hands on the keyboard, typing the code. I’ve got the idea in my head. I’m converting it to C# and typing it out, right?

Patrick : Yes.

Jamie : Whereas NDepend is a little bit more like I’ve written the code, you know, I’ve gone through it, I’ve made sure that it makes logical sense, I’ve done whatever checks I need to, I’ve written my tests, but I want to know whether I’ve unintentionally done something like maybe created a memory leak or something like that.

Patrick : Is that more like Yes.

Jamie : Okay.

Patrick : Yes, absolutely. But memory leak is more in the dynamics analyser side.

Jamie : Ah, right, okay.

Patrick : NDepend is more like, "you can simplify your code. You should test this code, or maybe you should focus on the new code." Because it has a baseline system. That’s a very important point of NDepend that it works with a baseline, meaning like typically the baseline is the the last version in production. So the one that you’ve tested a lot, like of course you put a lot of automatic test, but as everyone when you put something in production you take a few days to make sure everything everything is fine. And then this is your baseline and from there and NDepend will tell you, "we’ll focus on refactor code. Or new code, new class,new method." And will tell you what you should do to improve this fresh code.

Jamie : Oh right, okay. So I’ve written some code. Rather, I already have some code in production. I already know how many requests I can throw at it, how much memory it’s using, all that kind of stuff. I already know what it’s doing. I make some changes and then I can compare what the new, like how much memory or throughput or whatever the new code will have. And then I can make decisions as to whether that’s a good change or a bad change, right?

Patrick : Yeah, yeah, but it’s more about static version. It’s not so much about memory leak. It’s more about, like, &quopt;you introduced this new class but you didn’t test it," for example.

Jamie : Oh right, yeah.

Patrick : And it will put a point in telling you that, about the new code, which is more important because the existing code is already running in production.

Another way of seeing it is that maybe you have plenty of class that were not tested in the sense of unit test, but you can you can think that your user are actually testing it, you know. If you don’t get some production issue somehow it’s working. But you want some new code and it’s the time to to make sure you’ve admitted some test and to do the thing well.

Jamie : Right. No, I understand. My apologies for mixing up the static and dynamic side of it.

Patrick : Yeah, no problem, no problem.

An analogy I like to say is: it’s the difference between a class and an object. A class it’s a static thing. It’s, you write, public class and then you write your class and then at one time the class gets instantiated, and some object a product. But there is no object in the static world and there is… and yes there is the class in the dynamic world, but we are more talking about instantiation of the class which are objects.

Jamie : Okay, okay. So then so because… so I’ve written my code, I give it to NDepend, I say, "hey, you know, tell me about the things I need to know about this." Is it gonna give me a report? I can then maybe turn to project manager or whoever and say, "cool, I’’ve delivered, like the baseline first version of my solution to this user story or this feature. But I need some extra time to work on these particular things," right? And then I can then work with that project manager to figure out is this going to be a problem or should I add these extra features, right?

Patrick : Yes, absolutely.

Jamie : That’s good. Yeah, because peer reviews can only get you so far, right? I’ve fallen afoul of peer reviews because… how do I put it? My own personal view is that, like, nobody gets the UI for a merge request, pull request, correct, right? Because all I see are the changes in the file. I don’t see what the changes bring about. Whereas it feels like from our conversation I can use NDepend to bridge that gap, right? I can see the changes I’ve made.

Patrick : Yeah, yeah.

Jamie : But I can actually see the effect that those changes might have in the wider context, right?

Patrick : Yeah, yeah, yeah.

So it can mix a lot of things. So for example, I was talking about the baseline, so the new change, the refactor code, etc. But it can mix it with a lot of interesting points, like for example some sort of measure of the complexity.

So you can get some complexity score, for example, and you can mix it for example with code coverage. And what’s interesting is that at the end, with all this information, you can target for example, new code that is not well tested and that is complex, for example. So you can target all these different dimensions in one tool. And then you can focus on what should be really improved.

And for that, one thing that is important with NDepend, which is the backbone of the tool, is what we call a code query or CQLinq. So this is code query which is based on C# Linq. Okay, the same C# Linq that you are using every day. And everything is a C# Linq in NDepend. So a rule, for example, it’s a C# Linq.

So for example if you want a rule where you don’t want a base class to use derived class, it can be as simple as From T in ApplicationTypes Where T is using TDerivative for example it really looks like that. It’s pretty fluent and then Select T and then you can get a lot of details. So everything is a code query and I will mention more later.

And another other point interesting is that every issue,everything that NDepend wants to tell you is quantified through a technical debt metric. Technical debt it’s a famous analogy that I think you’ve you heard about because now it became very famous. I think it was coined, like, 15 years ago.

So technical debt is about: I have problems in my code which are not functional problems. The code is is working fine, the tests are passed. But I have a more like maintainability problem. Like I call it quick and dirty. So now I need to take some time to improve the quality of my code, to improve the overall maintainability. Especially if you are working in a critical business like automotive or financial, etc. So now you need to dedicate some time. At this time it’s a technical debt remediation.

So typically the technical debt is the estimation of how long it will or how much in terms of money, it can be duration of money, how much it’s gonna cost me to fix the problem. And what’s interesting is that NDepend is trying to tell you some estimation about technical debt. And it’s working pretty good. I mean we have very good feedback from the user in terms of estimation because NDepend knows every aspect of your code, as I mentioned earlier. So it’s using formulas involving all aspects of your code.

For example, you have a method which is very complex. You have a lot of loop, you have a lot of if, else switch case, etc. And this method is not tested. Okay, so NDepend analyze all these particular points and will tell you, "this method will take maybe three hours if you want to test it fully," well maybe now it’s a bit cheaper with an AI tool, but it will take that that amount. Yeah we all use it, we all use it. It will take you that amount of effort to make sure that all cases in your method is tested. And maybe it’s time also to split the method in smaller one, or maybe smaller class, smaller structure, etc. to make your code easier to read and understand.

So there are these two things that the quantification of your problem through technical debt. And that everything is a code query because unlike other tool, any other tool actually, except NDepend is a bit like LinqPad; LinqPad is very popular because it lets you write some Linq query up against your database or whatever. So NDepend, it lets you write, Linq query against your code to gather some information. And that’s very powerful because the other tool it’s more like: you have checkbox, you have combo box I want to check that complexity is no bigger than 15, for example. So you get some menu like that, or like some control, like textbook, etc. Well NDepend, it’s an integrated language, so you you can really write everything, you can really ask everything about your your code base.

Jamie : I think there’s two things I really want to focus on that you’ve just said there, and we’ll come back to the Linq query bit that’s integrated in a moment, because I’d love to discuss the ability to, sort of, build those queries and run that, and just use your code and the metrics behind it as a database. We’ll come back to that in a moment.

But you were talking about technical debt, right? Everybody knows the phrase. Everybody has a slightly different de definition of what technical debt is, and I feel like every definition of technical debt is valid, right? But I like the idea of being able to look at technical debt and, you know, with the help of say NDepend or, you know, some other system, whatever you want to use, know exactly how much it will cost to fix the technical debt, right?

Because I often say to you know my clients, when I say, "hey, we’ve got some technical debt." I see their eyes glaze over, right? They’re not paying attention. And so I say to them, "’the reason we need to fix the technical debt is because imagine you’re driving your car along the freeway, the motorway, the autobahn, whatever you want to visualize, right? You’re driving it really fast. At the speed limit for that road, but you’re driving really fast. You’re late for a meeting, an in-person meeting, right? And you’re pushing the car as as hard as you can to get there in time and you’re stressed. And then the little engine light keeps bLinqing and saying, something’s wrong with the car. Something’s wrong with the car. And you think, don’t worry. I’ll leave that. I’ll leave that. We’ll fix that later. I need to get to the meeting. The meeting is super important. And imagine you don’t get to the meeting, right? Because the engine stops working. That’s technical debt.". Right? And that’s what I say to people. And then they totally they they kind of get it from that point onward, right?

Patrick : Yeah, yeah, yeah. I think that’s a very good way to explain it.

So in in technical term, at first, technical debt at first, I think it was Ken Beck that called it, the term. So the technical debt at first it was all the code that is not automatically tested. So you can sort of infer it from code coverage. So NDepend is not a code coverage tool, but it can import code coverage from any and all the .NET tools that produce code coverage. That’s usually the code that is not tested, is a huge part of your technical debt.

I mean nowadays for me and the team it’s so natural to write tests. I mean we are on the total application we have almost 90% tested code. "Almost tested code" means that class is 100% tested and we couldn’t be where we are now without all this investment in tests. because that’s really an investment that we pay a lot later. Because when we break the code, when we add new features, fix bug, etc. So many times one of our 20,000 tests remind us that are run several times a day. One of these tests remind us, "hey, you look at that, you broke this particular thing." And it really literally happens every day or maybe every week. But very often we can break some code without knowing it, but the test bring you confidence that you can do some huge change in your code, some huge refactoring that are often necessary without breaking the end user feature or even introducing a bug.

So tests are very important. So that’s why at the first technical debt was mostly focused on test and it still is. But then with a tool like NDepend, we added since the the metric is about effort in terms of time, human time or money. You can add whatever you want. You can add complexity, you can add misuse of object-oriented programming, for example, object-oriented complexity. You can you use it in terms of the SOLID principles, okay, which are tightly coupled with object oriented. You can use it in terms of naming or in terms of commenting. WWhatever you you think about, you call how you can improve it. The improvement can be quantified as something in technical debt.

And at the end of the day, typically on a real legacy, that is not so well tested, maybe three quarter or two-third of your amount of technical debt will be about untested code and then you get this remaining amount of technical debt that comes from the thing that could be improved.

Jamie : Right. I’m just sort of thinking, if I put my project management hat on, I can then I get that information. I know which part of my code needs to focus on the code quality based on what you were saying. I can then say, "cool. Okay, so I know two-thirds of my code needs code quality uplift." Maybe it’s not being tested. I can then go, "what are the hot paths through my code and focus on that," right? Rather than my dev team comes to me and says, "two-thirds of my code base aren’t tested and it all needs to be tested, and I don’t know how much it’s gonna cost, and the world’s gonna fall down, and the roof’s gonna cave in, and everybody’s gonna be, nobody’s gonna have any friends anymore, and it’s all gonna be the world’s worst thing ever." Because that’s typically how technical debt is reported to project managers.

But because I have the report, I can turn to the project manager or whatever and say, "look, right? This is the code base, right? We need to invest in putting some tests here. This is roughly how much it’s going to cost, how long it’s going to take, how many hours, how many sprint points, how many whatever, t-shirt sizes, whatever," right? I can say to that person, "this is what we need to do before we move forward because this is our legacy codebase. And it needs to to have some some maintenance on it. This is how we can maybe even split it across three or four sprints, right?" It then helps that person to then visualize the amount of work and and plan that, right?

Patrick : Yeah. And also to remark. First, because I mentioned the baseline earlier, NDepend can tell you about the the the new technical debt you introduced since the baseline. Which part of your code is impacted, is it refactor code, is it new classes, etc. So it can help you focus on the new the new debt that you created. And second, the debt is for not necessarily the sticky out metric that you… I mean it’s very important to know how much it will cost you. But another important thing is about the the interest because it’s a financial metaphor. You have a debt like to nowadays all the occidental countries have huge debt, but the biggest problem of the debt are interest, especially these days that the rates we all suspect that the rates will go up. So the interest plays a huge role. Like for example, a security issue it can take you maybe half a day to fix or maybe one hour to fix so it’s very easy to fix. But if you don’t fix it, you’ll get so many angry users that maybe it will cost you you entire business. So and this can be seen as an interest.

So NDepend end also try to evaluate the interest from your code also. You try to understand what, so not only for each issue or each range of issues, it will offer you an estimation of the effort, but also it would try to tell you how much days per year, so in terms of duration per year, you will lose if you don’t fix. As long as you don’t fix it. So combining the two metrics you can get, you can prioritize the fix you need to do.

Jamie : That makes a lot of sense, right? The interest part is the thing that I feel like a lot of people miss out on. I’m not gonna make any friends with the phrase with the words I’m about to use, but my feeling working with a lot of people in enterprise is, "that is something we have to pay off in the future. And I, as project manager, delivery manager, as decision maker, may not be here in the future. Therefore, it’s not my problem." However, interest right now is my problem, right? If I have a credit card and I have $2,000 debt on that credit card, the $2,000 is kind of scary. But like you said, the interest is scarier. Because that’s gonna that’s costing me money and I’m not doing anything about it, right?

Patrick : Yeah, the interest are really the reason why you want to focus on improving the the quality and the security of your code. Why is it important to spend time on these points.

Jamie : Absolutely, absolutely. And I think that’s where maybe the technical debt analogy tends to fall over. Because, like I said, paying off the technical debt is something we do in the future because that’s what you do with debt, right? I get a mortgage, I pay it off in the future. I live in the house now, right? And I feel like, personal perspective, the idea of technical debt as a metaphor doesn’t work because lots of people are okay with debt, right? Because there is, I suppose good debt, the mortgage that you pay, or maybe you have a car that is on a lease or something like that, right? In most situations, and not every situation, but in most situations is okay to have that debt And so therefore technical debt seems like it’s okay.

Patrick : Yeah, but usually it’s not. And what’s really interesting for us here is that we are the dog-fooding NDepend since two decades, since it exists, since two two decades. And everything that we say, all this discourse works. It just works. As I told you, we are almost ninety percent covered on the code, which means that there is very, very little covered and tested, which is very important. So there is very little chance for a new bug introduced to reach production because usually it’s got automatically before then we fix it manually; but automatically we get the information, "hey, here there is there are some tests not passing, so this is a problem." so all those is really working and I cannot imagine. So sometimes we can see that we have clients that are not there, they have a huge legacy and not a solid test suite, and that that’s a pity because nowadays it should be part of your curriculum as a developer, And as a team it’s really important to make sure that your code is tested and abide by the good quality principle because it will become very difficult in the future, if not yeah.

Jamie : Absolutely. I love that you are dog-fooding it, right? You can’t build a code quality system without checking the quality of your own code, right? And, you know, we’ve talked previously about NDepend has been around for a long time. And so you will have built up some tech debt and you will have built up…. but well okay, the assumption will be that you’ve built up code paths that don’t have tests and don’t have coverage and don’t have this, that, and the other. But by using NDepend to check NDepend, you know that the rules that NDepend has helped with improving the quality, right?

Patrick : Yeah. And also with a huge focus on reducing the amount of false positives. So false positive is a threat for all static analysers. So we constantly focus on fixing some. So for example, like two days ago, user reported that some xunit (tests) now generate some classes and NDepend knows about code generated. It has a lot of heuristic to know which code is handcrafted and which code is generated. And so we took a chance to fix that and to make sure that the this new xunit generated class won’t be reported anymore.

So that’s how we work. We are relentlessly fixing everything we can hear from our huge user base, and so it’s very interesting to polish again, and again, and again. It’s kind of never-ending but .NET is never ending. It’s always progressing. Things are always changing. There is always new trend. So it’s a big passion. It’s really interesting.

Jamie : And it means as well that you’re not just adding something into the feature set for the sake of, "well, there’s this new metric that we can measure," right? It’s actually something that you are measuring and you are working on right?

Patrick : Yeah, exactly. And that user are requesting also very often.

Jamie : There’s two things you mentioned earlier on. You briefly mentioned AI in passing, and we’ll come back to that in a moment, but you also mentioned the ability that you have, this Linq-like query, to be able to actually say, "hey, go get me some results in my code quality analysis and show me that, and break that down using where clauses and stuff." I wonder if you could talk a little bit about that. Because I know that building abstract syntax trees, and things like that, it takes a lot of effort, sort of, that needs to be tested. And how in the heck did you test that? But also like how in the heck does it work?

Patrick : So we yeah, so concerning the build building a Linq to editor. So typically we use Roslyn. So we are very fortunate in .NET that the entire compiler is open source, but that’s really good. So we embed a Roslyn version to make sure that it can work side-by-side with the Roslyn version you get in Visual Studio or Visual Studio Code, for example. So that simplified a lot. At first, like you said, we had some our own tricks and heuristics. We had like a .NET Framework core dump which is not here anymore in a .NET Core. But Roslin is this definitely much much better also for IntelliSense and things like that. So we are very fortunate to have that.

And so concerning the language itself, Linq is a language that you know about, I know about, every every .NET developer knows about. So that’s really interesting that we got this language that appeared after NDepend in 2008 and it was very hot at that day, like, "hey you have a query language that looks like SQL at that time. Why don’t you migrate to Linq?" So it took us two years to, unless we have it in Linq. But it was like at that time Linq was coming from nowhere. It was not something expected. And having the ability to to have an abstract query language in C# was really nice because NDepend analyzes C# and also VB .NET code, but mostly C#. So it’s really interesting to be able to query with C# with with C#. So it’s really interesting.

But also you query your code through and that makes it a bit different than Rsolyn analyser. You query your code through an API, a big framework that we provide. So, for example, when you are developing some Roslyn analyser which is a wonderful technology that NDepend can import too. For example, imagine you want to infer the complexity of your code, then you have to write some code like you have to to count the number of if, the count the number of else to assess the complexity of the loop, etc. And this kind of thing, NDepend offers, you right out of the box, from the language. So typically you can just write FROM method in application method WHERE for example the method complexity is higher than 20 and the method was added since the baseline. Okay, it really looks like that, it’s very fluent. And for example, the method is not enough tested, and the method, for example, has not enough comments, etc. etc.

So you can query this kind of thing. And we offer 150 rules by default that are using all this framework, and language and that you can very easily customize. You can fork and you can also create your own. We have also some search panel that is basically a query generator. So you can, instead of writing the query itself, it generates the query behind the back, and then you can try to generate a query that you find interesting. And then there is a button "edit query" and you can you can edit the query and try to refine it to your exact need. So it can be very interesting, for example, if you are developing a UI and a typical UI with database and you don’t want the UI, for example, to access directly the database, okay; you want you want some layer in it, you can very easily say, "that code is my UI, that code is my database, and I don’t want there any connection between this," sort of thing. So when you become proficient by using SQLing you can go one step further in really querying your code, defining some some subset in your code and knowing what you want in terms of interaction or quality or testing or whatever. So that makes it very powerful.

Jamie : Right, right. And then you say there’s a whole bunch of rules, around 150, that are already provided. What kind of things are they looking at? Like just as a, if you were to pick three of these predefined rules, what kind of things are they looking at in my code base?

Patrick : So typically code smell. Okay. So code smell it’s a popular term that the industry is now using. Like I wanted to say it in French, but it say what it says, like the code you don’t want to put your hand in it. It’s not there is a code. So it will be very good at pinpointing you which code is not good.

Also in terms of object-oriented usage, imagine you have an interface to implement it, you need to implement like 15 methods that they become very hard to, typically we want to segregate such interface into smaller interface. Like for example, IDisposable. I like it to say it as an example because it is disposable. It has only one responsibility, which is disposing this, freeing the resource used by your object, and it has only one method for that. For example, you can you can have a list of disposable, and dispose all the objects with no knowledge if it’s network connection, if it’s UI handle; it can be whatever behind, but you can all dispose them in a shot for example. So that’s a very good interface and that defines well what is this notion of responsibility. So NDepend will help you.

So I said a code smell. Now it’s more about objects. Okay, so you have these three it is five solid principles that are very famous in the industry, coined by Uncle Bob. Which by the way was at the heart of the start of NDepend for the story. Uncle Bob. I think it was in 2002 or 2003, he published a book explaining all these principles and at that time I was a consultant in .NET, and I had the idea of writing a tool to try to measure the compliance to all these principles. Okay, so that was the initial goal of NDepend. So object-oriented usage is very very important in terms of low coupling, high cohesion, all these things that can be measured directly from your code. So it’s important to get some numbers, some metrics because instead of talking with your colleague, "yeah, it’s not that bad, it’s okay," no no, you you have bad numbers, so it’s bad, it’s really objective. So it can be it can be interesting.

So it’s narrowly for three, but some are particular like, for example, architecture. Okay, NDepend has some rules that can detect which part of your code are a real mess. And I have to say, usually, it’s a bit cruel if you have a large legacy, with a large project where everything is using everything. So NDepend will spot this kind of thing. It will tell you about the amount of technical debt your repo represents. And it’s typically the same time that you are not using enough the abstraction, like typically interface. So every class of your project are using every other class.

So things, for example, of the class String okay the everywhere everybody in the world in the .NET world, and even in the Java world, is using the class String. Imagine now you have you you pinpoint a bug in the implementation or you want to change something in the implementation, for example, for more performance. Then it’s very sensitive because everybody is using in every possible way you can imagine of and just changing this feature just a little bit will certainly break a lot of code. And this is what happened in your codebase when you have a lot of code integrated: you have some class that are used by everywhere and often it’s even like in s cycle. Like you have a class using another class, using another class, etc. And just changing it a little can break all the other code. And this is where abstraction shine, specifically the abstraction you you use are interfaces. So an interface, not only it lets you define a single responsibility, also it’s supposed to not change very often. Because you put a lot of effort in designing the interface. Okay? And also the user code doesn’t know about the implementation behind the interface. So if you change the implementation behind the interface, there are much less chance that you’re gonna break the code that using through the interface. Because he didn’t know all the little tricks you could do with your code. He didn’t try to guess what’s behind. Okay? And all those are about object, are about SOLID all the discussion I just have but I think it’s very important to use it correctly.

So architecture is about that, is about not having some muddy code, like big big ball of mud they call it in the US. So they try to know about this big ball of mud and help you give you advice to introduce interface. Imagine you have two namespaces using each other, it will tell you, "this one, this direction is not white, this direction is white but not the other one. So you should introduce this interface, etc. etc." with an estimation of the technical debt.

Also you have some all the code coverage fee and all code coverage rule that they are very important, because you can write some smart rules. Like this class was hundred percent covered by test during the baseline and it’s not anymore. And this is a use case that very often happen. Okay, very often because we use it so we know you are touching something in a class, and maybe you didn’t even think about testing it or the tests were not exhaustive; so NDepend can catch this kind of thing.

And it can also catch mixing other dimension like the complexity. Like if you have just a record DTO object, if it’s not hundred percent covered, it’s okay. Also I would say it’s not that okay, because if testing other classes ddesn’t hundred percent cover all your property maybe there are some property that are not useful. But that’s another bad. Don’t focus on this one because there is basically no code, it’s just a record, so there is no implementation.

But NDepend will help you more focus on the complex implementation, also on the edge case that maybe you didn’t bother testing. And here I have an interesting remark that I like to say to client, "like how often here, look at that class, it’s 90% tested, it’s much enough for me. I did my job, the job is done. But you let 10% why didn’t bother writing the test for this 10%?" And then usually you get insight, "yeah, but these one are difficult, those are edge case. Maybe exception or things like that. They are not easy to reproduce." But the thing we see is that the edge code is usually the code where you get the bugs. So you you end up writing some quick test that can cover 90% of your code, but your 10% here is not tested and because it’s not well implemented, and though it’s likely to to contain the bug. So maybe you should refactor your code and make your class testable. There is also some people that say that "testable equals good design." So, typically, if your code is well tested, it’s easy to write a test, then it’s a good sign that it’s well designed.

And also finally there are some other aspects that can be like for example dead code. So like like the other two, like Resharper, for example, code that you can comment or even better discard. You have some security. Like for example, software composition analysis, NDepend can help you with that. It knows about the security problem with the version of the NuGet package that you’re using. So it can tell you that you should migrate to another higher version. It can tell you also that different components it happens very often, different parts of your code, different projects are using for example Log4Net in different versions. And that that can be a problem. So it can normalize the version of the components you are using, and this kind of thing. Or many other in terms of encapsulation, immutability, naming convention, source file organisation, .NET base class library usage, all those kinds of of things.

Jamie : I really appreciated your point there about test coverage and how perhaps in your DTOs you you maybe don’t need a hundred percent. Because it gave me a flashback to a time when I was… a client of mine had said, "uh, yeah, we need to improve test coverage." And I improved test coverage across what I thought was the the core business logic. And they said, "yes, but we need to improve test coverage over here in these DTOs and these," you know, it’s there were they were we call them anaemic classes, right? They didn’t have any logic in them. They were just places to store related properties, right?

And I was, shall we say I was paid a considerable amount of money, to add pointless tests. And it cost them a lot of money to have me add these tests, right? And then the the other thing that I noticed was that a lot of the tests that were covering the business logic that predated me working on the code. They were tests, they didn’t actually test anything. There were no assertions. It was just, you know, set up: we would do like the arrange assert act, right? I’m sorry, arrange act assert, right? We didn’t have the assert loop, it just arrange and act. Which meant that technically the code base was covered with tests, but the tests didn’t actually test anything.

Patrick : Yeah. And I have to say something also on this point, that has a good that you mentioned assertion because I’m a big fan of assertion. And I’m a big fan of assertion inside the code. So no matter which framework accession library you are using, it’s very important to have assertion in your code. Because then it can make sense to write some test to exercise your code and even if the test doesn’t have any assertion, all the assertion in code will be exercised. And that can help a lot. So typically try to assert everything that can be asserted.

So with the C# nullable. We can be really from about half of the assertion that where that were about assert that this reference is not null. So the nullable C# feature help a lot in reducing the number of assertions. But everything that you can assert, every range of value for your your integer, your float, your any variable, you can put also some counter that are only used during the the debug side with some pragma. All those that are very important.

And I give you an example, it’s about the UI testing. Is a pain in the, uh, for everybody. I don’t know, it’s not my language, so I don’t know how rude is it, so I don’t say it. So it’s a pain for everybody. And if you put tons of associations inside your UI, you always check about state. of your control the state that are displayed in UI, etc. If your code is stuffed with tons of assertions, it really makes sense to write test to instantiate your UI as it was a user, to try to do some action with it. There are some design patterns that can really help you a lot with that. And then even if there is not so much assertion in the test itself All the assertions ins inside the UI will be exercised and and it’s priceless. It’s it can help you a lot.

Jamie : So you you mean inside the inside the actual code, right? Not inside a black. So like I have say I have a method that goes out and does some kind of HTTP request, right? Really bad example, but let’s say, right? Does an HTTP request Let’s say that that could come back the request the response could come back null. So we assert that the response is not null and then carry on, right? Rather than if response is null, go do this. It just assert No, no.

Patrick : Exactly. No, no, but the assertion, so yeah, that’s that’s a very good example about the point I want to underline is that there is a big distinction about the thing that you can assert, and the thing that are exceptions. So you should handle it maybe with exception or error. So typically if you could do a HTTP request and you don’t get the the answer you expect, it’s not a bug in your code. It’s maybe a bug in production or it’s maybe a bug in the network or whatever, but it’s not a bug in your in your code.

So the assertion should be kept really for what if an assertion no matter it’s in your code or in your test fail, it’s a bug. It’s not an environment problem like a network failure, for example. So network failure is good to test failure. So you can write test when, for example, there is no connectivity for your application and it is very good to handle that and to write with that, but it’s not exactly what I wanted. Me, and my concern here it’s really about the bug, it’s really about the code function the way you you want it to function.

Jamie : Ah, okay.

Patrick : It makes sense?

Jamie : Yeah, I’m just trying to think of a different example then, because obviously that wasn’t covering the kind of thing that you were talking about.

Patrick : Imagine you just write an assertion at the beginning of your method, this particular parameter should never be null. This is typically on our assertion because if it’s non null, it means that somewhere I have a bug that provoked the nullness of this preference

Jamie : Right. So we’re saying that we’ve got some kind of method in it. I’m running a class that you’re consuming, right? My class has a method called Print. And it takes some message to print, right? I have said to you in my implicit contract that the message to print can never be null, right? But you pass me, instead of passing me a string, you pass me the actual null object right, just you calling print(null) right? Then I put an assertion in there to say that message cannot be null.

Patrick : Yeah.

Jamie : That is protecting me from the bug where wherein the parameter, like you said, is set to the null value instead of maybe a string or an object, right?

Patrick : Yeah. And I prefer an assertion than just throwing an exception yourself. So, typically you can code if this parameter is null throw null reference exception. I prefer an assertion, especially if my code is the caller. Of course, if your code can be anybody in the world, if your caller can be anybody in the world, of course you need to to to send an exception to tell the caller it’s not good. But if for example it’s an internal method, I think the assertion is better suited because you master the caller code. You see the distinction? So you you don’t want bugs into the caller code. But if you don’t if you don’t have a hand on the caller code, then of course it’s better. Not only to have tests to have a code that will throw an exception but also some tests that verify that if you pass new you will get an exception. So typically throwing an exception becomes part of your logic.

Jamie : Yeah, yeah, and that makes sense, right? Because the contract between the caller and the method is: "you are going to pass me an some kind of object or some kind of variable you want me to print. You are not going to pass me a null. And so therefore it’s not actually an exception when you pass me null. You haven’t called me correctly. So I’m just gonna assert and just return immediately. You didn’t do it right. Do it right."

Patrick : Yeah.

Jamie : That makes sense because then, like you said, both sides of the call, you calling my code and my code dealing with your parameters, we have to, like you said, add more logic to either side. When you are calling, you need to wrap it in a try-catch in case I return a null ref. And then I need to, before I do anything, do an if check to return a null if you’ve given me null, right? If we remove that possibility. All of that code can be removed, right?

Patrick : Yeah, but it’s not so we talk about null that is typically solved by the nullable, but for example, it can be the state of an object. I pass you a reference to an object. Let’s make sure that the object is initialized the way I want. It can be a loop, loop invariant as we call it. Typically you are doing some complicated thing in a loop. For example, you are mutating some state during a complex loop that requires a lot of cognitive attention to be understood, and something that can really relieve you a lot from a lot of cognitive is to put [an] assertion about the invariant in your loop. Make sure, for example, that this index is never zero or is never minus one, etc. I never fall down. And if you put invariant assertion inside your loop not only is, at one time it will tell you if you have a bug if the variant is is broken, but also for the developers that are reading you code it’s also a very good indication that you don’t expect this invariant to never be violated.

Jamie : Okay. Yeah, that makes sense.

Patrick : And then, if you exercise this code with some test and you don’t have much, which can happen for example in the UI context, but in some other contexts you don’t have much to verify inside the test itself. At least you exercise all the assertion, all the contract we can say in your code. And of course you have to make sure that if an assertion is failing, the test is failing too. That’s not assertion in code, I mean And that’s very important.


You know that moment when a technical concept finally clicks? That's what we're all about here at The Modern .NET Show.

We can stay independent thanks to listeners like you. If you've learned something valuable from the show, please consider joining our Patreon or BuyMeACoffee. You'll find links in the show notes.

We're a listener supported and (at times) ad supported production. So every bit of support that you can give makes a difference.

Thank you.


Jamie : Shifting gear slightly then, we talked about there’s some new stuff coming in NDepend. And you mentioned AI. Now you mentioned that and you said, "we’ll come back to that." Does that mean that you’re hinting that there are AI features within NDepend, or are you just saying AI is a thing and we’re over here doing NDepend things and it’s different?

Patrick : First AI: for all our entire industry, AI it helps us be much more productive so everybody loves it. But it’s also a threat for every one of us. No matter what you’re doing, you can see it as a threat. So hopefully for a static analyser tool it can be used to check generated code, "genAI code," they call it.

So typically you have AI that you just integrate some chatGPT code or some Copilot code. This code can be checked by tools like NDepend. So not only you can make sure it complies with the kind of code you have, with the set of rules you want in place. But also it can tell you about some things about the correctness. If it tells really what you want to do. So you can have some warning popping about generated code that you integrated a bit too quickly. Or it can tell you about you integrated some code but you didn’t have the test. So you can also use AI to generate the test, but at the end of the day at a point you have to make sure that the correctness of the code is good, it does exactly what you want. So a tool like NDepend can help you with that.

Concerning the other side: so for that it’s very good for tools that check the code, I think. It’s now more and more code is produced with thanks to AI tool and it’s less and less handcrafted by human and understood by human. So there is the "vibe coding" phenomenon where everybody is kind of mocking it, because it looks like the younger developer: it just works so they integrate it but they don’t try to understand it. So having tools like a safety net to just, by looking, having another automatic eye that look at the code can help you find some issue.

And the other side is integrating AI in the NDepend tooling set. So we’re not yet there. Of course we are thinking a lot about it What we want to avoid, at any price, is to put some AI feature that user don’t want. And just yesterday Microsoft released the first preview of Visual Studio 2026. Which is very exciting. And if you look at comments, of course they they put unusual amount of effort in Copilot, which is the AI tool inside Visual Studio and Visual Studio Code. And we see a lot of Developer grunting, I think "grunting" is a good verb. I’m not sure they’re not happy with it. And I read very carefully on the Reddit sub, etc.

All the comments I think it’s very interesting to to read comments from your peer. And from what I understand, and also by discussing with clients, is that there is a misunderstanding in the industry between the, on one side you get the younger vibecoder, which is it inexperience but that can generate code for what his client is asking him very quickly. So it’s kind of blessing for him. Maybe it can generate an entire web shop in a few minutes instead of one week or two. So it’s very interesting.

So that’s one end of the spectrum, but the other end, which is more like me and you, and user of any of tool like NDepend, and maybe also we say the user of Visual Studio. On the other end of the spectrum you get the enterprise developer that is dealing with a massive legacy. Legacies also can be plural. And for him, the AI help will be totally different. Sometime Copilot is very smart, even on a large code base like NDepend. Sometimes I can see it, "hey, you understood it." But also very often it’s totally not in the point. So it’s a good productivity tool, but I don’t see it replacing the enterprise developer anytime soon because it doesn’t scale on the large code base.

And so I see a lot of people moaning about Visual Studio 2026 having so much so much Copilot. And maybe it’s because that people that are using Visual Studio are maybe the experienced and seasoned developer that are using it for large legacy code and they care more, for example, about performance or about any tool that can facilitate a daily job than the typical Visual Studio Code user that is maybe younger, that is the the the scale of the application is maybe smaller. So for them, that’s the success of Cursor which is the the the fork of a Visual Studio Code which is focused.

So yeah, so I think that there is a spectrum with these two hands. and and all this to say that we are reluctant to just add AI just for the sake of it that the user doesn’t necessarily want. So, for example, we could have AI that instead of writing your code query, you could ask query in a natural language and maybe under the hood a code query could be generated and return the same the same data. So that could be interesting as a query generator, but we are studying it, but we are we are not yet there.

Jamie : Yeah, you’re you’re exercising caution, right?

Patrick : Yeah.

Jamie : And I like that. You know, there’s a number of clients that I have had in the past year or so. So we’re recording this around September 2025. I’ve had a lot of clients, or potential clients because they once I’ve explained to them that, "maybe you don’t want this." They’ve come to me and they’ve said, "we need to have AI in our product because it’s the big thing and we you know it’s great and it’s brilliant." I’m like, "yeah, totally. Except what is it your product does?" "Oh well, you know, it’s printing books." "Right, okay, where are you gonna put AI in that?" Right? You know, it’s like there needs to be some caution exercised in how to integrate.

Patrick : But from the business perspective, putting AI in your product is smart. Because, for example, if you’re looking about investor, AI is really big buzzword. So maybe… you see what I mean? At NDepend because we are really developer, we are reluctant to just put AI for the buzz and… but for some other product maybe it’s worse even if it’s a useful AI, can pimp the adoption of the product or maybe the reputation of the product. So yeah we just cover the technical side, but on the business side it can make sense. Even even if it’s not that.

Jamie : I mean it would make sense from a consumer side, if someone is using NDepend, maybe to use AI to read through the reports it gives me, and then give me an idea of roughly the areas that need the most work, and maybe costings or maybe scores of complexity and things like that. That makes sense. But actually dealing with the code.

Patrick : Yeah, maybe generated plain English, 12 lines summarising the reports. "Hey you did good with this new since the baseline, but maybe you should have a look there and there. Instead of looking [at] some charts and some numbers, maybe thatwill be a good good one." Yeah.

Jamie : Yeah, absolutely.

We’re running low on time, Patrick. And I feel like could talk all day about the different things that NDepend does, and all of the new features that it has and since we last spoke, and why folks should check it out. But I think maybe the best thing that that they can do is maybe go to the website, look through the documentation, maybe watch a few of the videos and see what it is that it it gives them. So where’s the best place for folks to go?

Patrick : So NDepend.com. So you have a free trial, full feature to try. So I suggest even just… we really try to make the process very smooth. So you just download the trial, it’s very lightweight, like under under twenty 20 megabytes, which is nothing these days. Like someone told me, I know some flashlight Samsung application that weighs more. So just download the trial and in less than four, no five minutes but three-four minutes, you can have a first report about your code that tell you some interesting things.

Some just things about the new features: we have a new product is about the web reporting. We really pimp the report so now it should, I hope it will help help you a lot. And also something very interesting is that we are importing the results that you obtain from your Roslyn analyser, and or from the Resharper rule they have a name for that the Resharper code, they have another name, but anyway this is the Resharper rule. So what it means is that you can have a 360-degree view about every kind of issue you can have on your code from Roslyn, from Resharper, and from NDepend, or this in one product. And integrated.

Jamie : Okay. I’m hoping that folks will go to the web and check out all of those new features. I like being able to get like a 360 view of everything. That’s really useful. And yeah, although all the different reports that I can generate, really, really cool.

So we’ve already said NDepend.com is probably the best place to go to. You can get the trial version there, couple of minutes of work, and you’ve got your first report, right? Is that the best place to learn about it too? Is it like NDepend.com/docs or is it docs.ndepend.com or something like that?

Patrick : Ndepend.com. We also have a video section if you don’t want to download the trial. Those videos we spend a lot of time, few hours on each minute. What I mean is that they are really polished to tell you the most in the less time because we really value the time of our user and clients.

So we have like maybe 15 five minutes videos. So no matter what you can be interested in for NDepend, no matter it’s about the architecture, code quality, CI/CD, etc., there is a short video that you can watch. And that will explain the feature, how to use it, and what it can the use case and what it can bring you.

Jamie : Amazing. All right, cool. Well, I’ll make sure there’s links to that in the in the show notes. So press through the show notes. There’s a link there already where you just press that and it’ll take you straight through it.

So Patrick, what about catching up with what NDepend are working on, what you’re working on, that kind of thing. Are you LinedIn,are you not? I mean, it’s totally fine to not be online these days. That’s not a problem.

Patrick : So, well typically we use maybe it’s the only way, we use a lot of email. We communicate a lot for with our user by email. But yeah, I’m only in LinkedIn, Patrick Smacchia. NDepend is on LinkedIn, too. But I have to say that after all these years I put more on the my private LinkedIn, which is certainly a mistake. So you will find a lot of information on my private LinkedIn.

We have a blog also on ndepend.com, we have a blog that we really try to cover all the .NET subjects, tricky .NET subject, all these the new C# features. Like for example the new extension method that coming. The new .NET feature, like for example, the new .NET 10, dotnet run C# file, which is pretty cool.

If you have question about all this new stuff or also complex stuff like how a weight async really works under the hood, etc. Our goal is to be the best resource for all these tricky side. So we spend a lot of effort in writing a blog post that can teach you something interesting, especially in this world where the world is bloated with AI generated content which is very low quality, and all our content is handcrafted, and it’s designed for learners. But also medium to seasoned developers that really want to learn something the right way. So of course ChatGPT can help you a lot. But if you want to have a human vision on the thing, maybe you can go on the blog.

Okay, so we are also talking about code quality, everything that that the NDepend does. And yeah, and also we have a Twitter, of course, and everything.

Jamie : Amazing. Well I’ll get links to all of those and put those in the show notes as well.

So again, if you’re listening in, don’t be diving across your dashboard you’re driving to work to try and write all these down. They’ll be in the show notes, folks. And depending on the the app that you’re listening to, you’ll be able to access those show notes after you’ve listened, or just go through to the website: dotnetcore.show and it’s all there.

Patrick, it’s been fantastic catching up with you, and I feel like I could talk to you all day about NDepend and all of the things.

Patrick : Same for me.

Jamie : But we’re running out of time.

Patrick : Let’s catch up in a couple of years.

Jamie : Definitely.

Patrick : And we’ll have more to say, but it was really nice. Thanks for the invitation.

Jamie : Excellent. Thank you very much, Patrick.

Patrick : Thank you Bye-bye.

Wrapping Up

Thank you for listening to this episode of The Modern .NET Show with me, Jamie Taylor. I’d like to thank this episode’s guest for graciously sharing their time, expertise, and knowledge.

Be sure to check out the show notes for a bunch of Linqs to some of the stuff that we covered, and full transcription of the interview. The show notes, as always, can be found at the podcast's website, and there will be a Linq directly to them in your podcatcher.

And don’t forget to spread the word, leave a rating or review on your podcatcher of choice—head over to dotnetcore.show/review for ways to do that—reach out via our contact page, or join our discord server at dotnetcore.show/discord—all of which are Linqed in the show notes.

But above all, I hope you have a fantastic rest of your day, and I hope that I’ll see you again, next time for more .NET goodness. I will see you again real soon. See you later folks.

Follow the show

You can find the show on any of these places