Download presentation
Presentation is loading. Please wait.
Published byBlaise Hawkins Modified over 9 years ago
1
How to make the most of Code Analysis Patrick Smacchia NDepend Creator and Lead Developer Build Stuff Lithuania - 11th Dec 2013
2
Introduction to NDepend Contract, Unit Test and Code Coverage Designing to make the UI testable Detect regressions early with Code Rule On Clean Code Structure
3
Introduction to NDepend
4
Tool for.NET Developers I’ve created in April 2004 Became commercial in February 2007 Tool specialized in static analysis of.NET code Integrate in Visual Studio (2013, 2012, 2010, 2008) Integrate in Build Process to produce reports Soon 4.000 companies client worldwide JArchitect (for Java) CppDepend (for C++) NDepend Facts
5
Code Rules written with C# LINQ syntax Dependency Graph and Matrix Code Diff Code Metrics, Treemap Trending Code Coverage … NDepend Features
6
How do we use NDepend to build NDepend?
7
Contract, Unit Test, Code Coverage
8
Microsoft Code Contract library Suitable for the public surface of your product API Standardized (documentation, compiler check…) Not adapted for an intensive usage (slow compilation) System.Diagnostics.Debug.Assert() Adapted for an intensive usage, everywhere in your code Only work in DEBUG mode At least it doesn’t slow down production execution Code Contracts in.NET
9
Pretty much the same thing. Really!! In both cases we want to check for assertions. In both cases we want a failure if a condition is not fulfilled, because it means correctness violation Code Contracts MUST fail if not fulfilled at unit test running time Advantage: You can run an automatic test with few assertions, but still get the contracts assertions verified. Code Contracts vs. Unit Tests
10
100% ! … less is not enough! Often we hear: the last 10% are too costly to be covered Why is it too costly? Because this last 10% code is not well testable Hence it is not well designed Hence it is error-prone Nobody wants to let the most error-prone code uncovered by test, do you? How much Code Coverage is needed?
11
100% … at least needed for core business logic classes that contain the application complex logic NDepend entire code base: 79% covered 100% coverage also means all contracts get checked Isolate in some special classes uncoverable code Blocking methods: MessageBox.Show() OpenFileDialog() Hard to repro error cases: IO.UnauthorizedException catch … How much Code Coverage is needed?
12
3 major.NET tools to obtain Code Coverage from automatic tests run: VS Code Coverage JetBrains dotCover NCover Ndepend can import Code Coverage from any of these tools Code Coverage
13
NDepend rules and Code Coverage // Types tagged with FullCoveredAttribute should be 100% covered warnif count > 0 from t in Application.Types where t.HasAttribute ("NDepend.Attributes.FullCoveredAttribute".AllowNoMatch()) && t.PercentageCoverage < 100 let notFullCoveredMethods = t.Methods.Where( m => m.NbLinesOfCode> 0 && m.PercentageCoverage < 100 && !m.HasAttribute("NDepend.Attributes.UncoverableByTestAttribute".AllowNoMatch())) select new { t, t.PercentageCoverage, t.NbLinesOfCodeNotCovered, notFullCoveredMethods, t.NbLinesOfCode, t.NbLinesOfCodeCovered }
14
NDepend rules and Code Coverage // Types 100% covered should be tagged with FullCoveredAttribute warnif count > 0 from t in JustMyCode.Types where !t.HasAttribute ("NDepend.Attributes.FullCoveredAttribute".AllowNoMatch()) && t.PercentageCoverage == 100 && !t.IsGeneratedByCompiler select new { t, t.NbLinesOfCode }
15
NDepend rules and Code Coverage // From now, all types added or refactored should be 100% covered by tests warnif count > 0 from t in JustMyCode.Types where // Match methods new or modified since Baseline for Comparison... (t.WasAdded() || t.CodeWasChanged()) && //...that are not 100% covered by tests t.PercentageCoverage < 100 let methodsCulprit = t.Methods.Where(m => m.PercentageCoverage < 100) select new { t, t.PercentageCoverage, methodsCulprit }
16
NDepend rules and Code Coverage // Types that used to be 100% covered but not anymore warnif count > 0 from t in JustMyCode.Types where t.IsPresentInBothBuilds() && t.OlderVersion().PercentageCoverage == 100 && t.PercentageCoverage < 100 let culpritMethods = t.Methods.Where(m => m.PercentageCoverage < 100) select new {t, t.PercentageCoverage, culpritMethods }
17
Designing to make the UI testable
18
A kernel object, referencing a grape of objects, that is shared amongst all UI panels The kernel hold access to Application states (currently running an analysis?, session opened? …) Application context (user preferences, licensing options, theme…) Application actions (open/close session, show/hide panel…) Session states (analysis result loaded, diffed?…) Session actions (build a graph, edit a code query…) … NDepend UI Design
20
Suitable to write UI integration tests, that pilot the UI. Not much assertions are done in unit-tests bodies … …but thousands of code contracts nested in UI code are covered by test run. Hence they are checked! NDepend UI Design and Tests foreach (var panelKind in new[] { PanelKind.StartPage, PanelKind.ProjectProperties, PanelKind.Matrix, PanelKind.Graph…}) { InvokeOnUIThread( () => m_Kernel.App.Actions.SetActivePanel(EventSender.Main, panelKind)); InvokeOnUIThread( () => m_Kernel.App.Actions.ShowPanel(EventSender.Main, panelKind)); }
21
NDepend UI Design Ruled Generic rules can be written to enforce design decisions like: Panels shouldn’t use each other Demo // Panels shouldn't use each others warnif count > 0 let panelsNamespaces = Application.Namespaces.WithNameWildcardMatch("NDepend.UI.Panels.*") from nUser in panelsNamespaces.UsingAny(panelsNamespaces) from nUsed in panelsNamespaces.UsedByAny(panelsNamespaces) where nUser.IsUsing(nUsed) select new { nUser, nUsed }
22
Detect Regressions early with Code Rules
23
Code Rules like Types that used to be 100% covered but not anymore Methods that could have a lower visibility Avoid transforming an immutable type into a mutable one Potentially dead Types Class with no descendant should be sealed if possible Constructor should not call a virtual methods … Not so much about keeping the code clean for the sake of it. Code Rules
24
More often than not, a green rule that suddenly gets violated, sheds light on a non-trivial bug. It is all about regression. It is not intrinsically about the rule violated… …but about what happened recently, that provoked a green code rule to be now violated. Demo! The importance of Green Zone
25
On Clean Code Structure
26
What’s common about most of projects packaged into one large assembly? Nancy.dll NHibernate.dll Mscorlib.dll System.dll The code is completely entangled into namespaces dependencies cycle! Common structure problem
27
The problem comes from the lack of definition of the notion of components in.NET. A component is a group of cohesive classes (cohesive in the sense, one get used => all get used). There is no clear definitions about how to package these classes other than the notion of.NET assembly (or VS project). Consequences: Real-world applications are made of hundreds of.NET assemblies Only one structure rule: Avoid cycles
28
But.NET assembly is a physical artefact: One assembly one physical file Not fun to deploy hundreds of assemblies Not fun to reference dozens of assemblies of a library (and maintain these referenced) A component is a logical artefact Finer-grained than assembly => an assembly should contain many components This is why I advocate namespace to be the right granularity to define component Only one structure rule: Avoid cycles
29
250 namespaces spawned over 10 assemblies Design of NDepend
30
For a public API, its practicaly impossible! For an application the code rule Avoid namespace mutually dependent usually gives good hints about what to do, How? Because developers usually know about high level and low level code. For example, the rule say that mscorlib System namespace shouldn’t use any other namespace Typically, resolving all namespaces mutually dependent will result into a well layered code structure. How to get rid of cycles?
31
Two ways to get rid of an unwanted namespace dependency: Move type(s) from one namespace to another Create an Inversion of Control by defining abstractions (interfaces), in a new lower namespace Try it! This is much cheaper to achieve than expected, and getting rid of spaghettis is priceless! Because only code structure is touched (class def, interfaces def, namespace def) Code flow (method bodies) is left untouched. How to get rid of cycles?
32
Introduction to NDepend Contract, Unit Test and Code Coverage Designing to make the UI testable Detect regressions early with Code Rule On Code Structure Questions?
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.