posts - 47, comments - 14, trackbacks - 438748

Cached @ 10/11/2008 8:46:23 AM

Control ASP.skins_anothereon001_controls_blogstats_ascx

My Links

News

Archives

Post Categories

Blogs

Cached @ 10/11/2008 8:46:23 AM

Control ASP.skins_anothereon001_controls_singlecolumn_ascx

Wednesday, August 20, 2008

Reflector to go to RedGate

Lutz Roeder has decided to move on from Reflector.  RedGate will be taking over the project from now on.  Fortunately, they have agreed to maintain the community edition of the software.

http://blog.lutzroeder.com/2008/08/future-of-net-reflector.html

posted @ Wednesday, August 20, 2008 9:21 AM | Feedback (0) | Filed Under [ Tools ]

Tuesday, August 19, 2008

NDepend Part II - Beginning CQL

In my continuing use of NDepend on both my work and home projects, I have been investigating CQL more and more, especially from the perspective of use in continuous integration.  NDepend provides some incredibly powerful analysis features and I find the idea that constraints can be applied and warnings reported as part of day 1 builds to be extremely appealing.  I'm all about keeping code clean, constrained, and consistent.  NDepend provides another great tool in my kit to ensure that my own code is marshalled to my standards from the very first line that is written.  As David Muhondro put so eloquently in his blog post, NDepend is static analysis on steroids.  When most users encounter CQL for the first time, the response is "wow, this looks really powerful, now what does it mean?".  I've started by taking the stock queries that are included in a basic NDepend project and understanding what they mean and the warnings that they are expected to generate.  By understanding the warnings and their purpose in the project, I began to understand how I could tweak those queries and even write my own to enforce the rules I'd like my code to live by.

Let's start by looking at an example.  After creating a new NDepend project and pointing it at a list of assemblies to analyze, the default CQL queries that are included are grouped into the following categories:

  • Code Quality
  • Design
  • Unused Code / Dead Code
  • Encapsulation
  • Diff / Changes / Evolution
  • Test Coverage
  • Purity / Immutability / Side-Effects
  • Naming Conventions
  • .NET Framework Usage
  • Statistics
  • Samples of Custom Constraints
  • Constraints extracted from Source Code

I started by looking at the Unused Code / Dead Code queries, specifically at the Potentially unused methods query.  By double-clicking on the query it is opened in the CQL query editor and displays the following:

// <Name>Potentially unused methods</Name>
WARN IF Count > 0 IN SELECT TOP 10 METHODS WHERE
MethodCa == 0 AND // Ca=0 -> No Afferent Coupling -> The method is not used in the context of this application.
!IsPublic AND // Public methods might be used by client applications of your assemblies.
!IsEntryPoint AND // Main() method is not used by-design.
!IsExplicitInterfaceImpl AND // The IL code never explicitely calls explicit interface methods implementation.
!IsClassConstructor AND // The IL code never explicitely calls class constructors.
!IsFinalizer // The IL code never explicitely calls finalizers.

Breaking it Down
Let's break this down a little.  First of all it is important to realize that this is not SQL, despite any similarities in the syntax.  The first line selects the top 10 methods that satisfy the query and then raises a warning if the total number of methods is greater than 0.  The reason for the seemingly superfluous top 10 selection is that if the count is greater than zero then those top 10 will be displayed as the results of the query.  To avoid swamping with noise the query is restricting to only the first ten offenders.  The next line is the first part of the WHERE clause and looks for methods with an CruiseControl to bring these warning and reports into the daily life of your projects.  While static analysis en masse isn't for everyone (not even for me), a small list of CQL queries can help you perform necessary housekeeping without having to do the hard hunting work yourself.  The inevitable question is whether or not this overlaps with FxCop.  There is some overlap, but they are both just tools from which you should pluck the best of the functionality you like and strike down the cruft that gets in the way.  There are some cases where writing an FxCop rule specific to your application is a good thing, however I'm finding that writing CQL queries for warnings lends itself a little better to how I think about static analysis in the first place.  The key is finding that sweet spot in the middle.

posted @ Tuesday, August 19, 2008 11:25 AM | Feedback (0) | Filed Under [ Software ]

Wednesday, July 30, 2008

Designing for Testability

Automotive manufactures have long been on the vaunted TDD bandwagon.  For years they have harnessed the amazing potential of unit testing, verifying components individually prior to the expensive and time-consuming exercise of assembling them to make a completed vehicle.  Integration testing in the automotive world is very expensive and to find that a single component failure has wasted a fleet of test vehicles as well as many months of construction and fabrication is close to unacceptable.  However, they have also long faced the question of when and where to design for testability; a line still not clearly defined in any industry.

It makes perfect sense that if a component is to be tested in isolation from the system it will eventually be integrated with that a certain amount of planning is necessary in order to facilitate that testing.  This means that certain designs, while technically and functionally brilliant, may need to be modified if they are ever to be tested.  The question is where to draw the line.  All too often in software engineering the line is drawn firmly on one side or the other, rarely in a position of balance.

I can understand on a modern motor vehicle with multiple on-board computers performing a variety of related tasks that there is a need to interface with and test those computers thoroughly.  I'm sure that to the component manufacturers the need for extra diagnostic access ports and programmable interfaces is a hindrance to their development; after all they are working in a very closed system.  However, to the test engineers the ability to simulate all manner of failures and receive highly detailed information about everything the computer is doing is absolutely indispensible.  They cannot guarantee the component functions correctly without it.

Unfortunately this desire for components to be testable can easily get out of hand.  Consider that a test engineer is tasked with ensuring that the onboard computer functions at various speeds.  Unforuntately his equipment is bulky and doesn't fit inside the vehicle.  Even at low speeds he finds that keeping up with a car in motion requires him to run alongside pretty quickly.  Should he require that the car not go faster than 8mph in order to ensure that he can completely guarantee the functionality of the computer for the legal range of speeds he is able to test?  Something tells me that the manufacturer wouldn't be able to sell too many of that particular model.

Instead the test engineer must find other ways to test the car at high speeds.  Custom models of the car are constructed that allow a connected rig to be tethered to the car, carrying all of the the test equipment alongside even at high speeds.  At even higher speeds, motion simulations and car treadmills are employed to allow for testing that the tethered rig is unsafe for.  The design of the car wasn't limited to a maximum speed of 8mph, rather a compromise was found to allow the right balance of functionality and testing.

In software engineering, we have a variety of tools and frameworks at our disposal to accomplish similar testing of software.  Unit testing frameworks, mock frameworks, dependency injection containers; they are tools.  Each plays a specific role and solves a particular flavor of problem, however none of them are all-encompassing and all of them require thought before use.

There is a growing epidemic of code grown out of the desire for "high coverage" unit testing.  However, some of the motivations behind this testing appear to have taken an 8mph turn somewhere; for the worse.  In an effort to improve code quality, the initiatives towards testing have started to build 8mph cars with 6 wheels and no doors.  In terms of test coverage the cars are truly superb, but from the outside many consumers are left scratching their heads and wondering where it all went wrong.

I usually find that if a particular design decision is inhibiting the testability of a component, one of three things is happening:

  1. The design is so tightly coupled and stable that no testing could hope to penetrate the darkness of the black box surrounding it.  (i.e. a dll with one 5,000 line method inside that does "something")
  2. The design is so abstract that is doesn't actually do anything.  (i.e. a dll containing only interfaces - test that suckas!)
  3. The testing tool being applied is the wrong one for the job.

As a software engineer, I can fix 1 and 2.  Fortunately with good design and architecture we can actually prevent 1 and 2 from ever reaching QA in the first place.

There isn't much I can do about number 3.  This is where I ask for the line to be moved a little with regards to the tool that is being employed.  Here are a few examples of hammering screws and screwing nails.

Static methods, unless invoked through reflection, attract coupling from consumers.  That is to say that if an assembly contains a static method, there is a good chance that something calling that static method has a strong reference to the assembly that exposes it.  This is not a bad thing and there are many places where such a design makes perfect sense.  However, in certain situations, this can cause mocking frameworks to perform more work than necessary to set up the premise for a unit test because they can't mock away the reference the exposed assembly that performs work.  This is because mocking frameworks are ideal for mocking abstract implementations and poor for mocking tightly coupled components.  There is nothing to mock because everything is explicitly stated.  See screw, swing hammer.  Static methods are perfect for unit testing thanks to the magic of reflection.  Inspect the method contract (the logical contract not the physical source code - i.e. what, in English, does it do) and based upon that contract construct a suite of tests to affirm that the method is indeed doing what it promised it would.

Service assemblies, such as configuration loaders or proxies, tend to operate more upon interfaces than implementations.  That is because the value they add is an operation upon some implementation of an interface rather than a concrete process defined up front.  This is the provider model.  We write a set of interfaces describing the kinds of things a provider can do.  We also write a set of services than help those providers achieve some work.  We don't write the actual providers themselves because this is a plugin model.  Well, how do we test a provider that hasn't been written yet?  Wait, this could be hard in unit testing.  We call a method on an interface but have no way to know what the "as yet unwritten" provider will do in that method call and have no way of knowing whether the result is correct.  NTemporalDisplacementUnit 1.0 hasn't been released yet so we can't do it in a state of temporal flux either...panic!  But wait, in thinking about the problem further we realise that we don't care what the provider does.  The contract we are providing is that we will interact with a provider in a predictable and documented fashion.  As long as we interact with the interface in the correct way and at the correct time, our part of the contract is fulfilled.  Woohoo!  That's what a mock framework is for.  We mock up a provider and check that our service correctly interacts with the provider.  Mock frameworks are great for this.  Finally, a nail that we can hit with our hammer.

If you find that such thinking manifests itself in dogmatic emails that state "static methods shouldn't be used because they inhibit testability" or "interfaces are bad because we can't get coverage with them." then it might be time to inspect both the situation and the tools and see that the two are being correctly paired.

The goal of testing is to improve the quality of the end product, not to turn lots of lights a pretty shade of green.  8mph cars with lots of green LEDs and no doors for great dogmatic case study's and really awful consumer responses.

posted @ Wednesday, July 30, 2008 12:56 PM | Feedback (0) | Filed Under [ Architecture ]

Friday, July 25, 2008

Planning for the worst

"The status page we use to report service disruptions in progress is suffering a temporary misconfiguration."

Brilliance!

posted @ Friday, July 25, 2008 1:28 PM | Feedback (0) |

Tuesday, July 15, 2008

Technorati Blog Claim

I claim this blog in the name of Stuart Thompson for my new Technorati Profile.

posted @ Tuesday, July 15, 2008 2:19 PM | Feedback (0) |

LINQ to Coffee

Nice!  A perfect addition to the reference material you keep within reach.

http://www.cafepress.com/linq.225122905

posted @ Tuesday, July 15, 2008 12:55 PM | Feedback (0) |

Monday, July 14, 2008

Debugging Into .NET Source Code

Many have “heard” that you can now step into .NET source code when debugging in Visual Studio 2008.  For those who have not been doing this since the start of the year, you can find excellent instructions for configuring Visual Studio to get the necessary symbols here.

I highly recommend understanding this process and making it a part of your debugging routine.  It often becomes necessary to understand why the .NET framework is behaving in a certain fashion while developing.  By stepping into the source code and using the watch window, I’ve saved myself a lot of hours of head-scratching.  More often than not it’s as simple as understanding why an exception was thrown and the hidden meaning behind the message.  Within minutes I can usually pinpoint how I was incorrectly using one of the libraries, fix the bug, and be on my way.

posted @ Monday, July 14, 2008 1:04 PM | Feedback (0) |

LINQ'd In #1 - Behavior Injection

As part of a continuing set of articles on LINQ, I want to first take a moment to look at how the "natural" syntax of LINQ is turned into executable code.  Once we understand how those expressions and compiled we can investigate ways to extend the code that is being executed.

First of all let’s consider a very simple LINQ expression:

from num in Enumerable.Range(1,9)
where num % 2 == 0
select num

This expression selects the even numbers in the series 1–9.  Let’s first break this down into the actual code that is being executed.  Behind the scenes LINQ is viewing this expression as a series of lambda expressions and extension methods.  Our example is actually being run as:

Enumerable.Range(1,9).Where(n => n % 2 == 0)

Enumerable.Range(1,9) yields an IEnumerable<int>.  By using Reflector we can discover that the signature of the Where method looks like the following:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate)

This is clearly an extension method on IEnumerable<TSource> that takes a Func<TSource, bool> as its only parameter.  While the actual internals of the Where method are actually a little more complex due to the way in which iterators have been abstracted, we could theorize that the behavior is roughly similar to the following:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate)
{
    foreach (TSource t in source)
    {
        if (predicate.Invoke(t) == true)
            yield return t;
    }
}

“For each item in the supplied IEnumerable, invoke the supplied predicate and add the item to the returned collection if that predicate returned true.”

Note: If you haven’t encountered keyword yield before, check out this post about how it works.

Now that we understand how the statement is working internally, lets look at ways in which we can extend it.  To understand the following trick we need to think for a second about how extension methods are implemented, or more importantly about how they are resolved.

When the compiler encounters a statement of the form:

<type>.<method>()         (e.g. IEnumerable<int>.Where(…))

for which there is no explicitly defined method, it searches the current list of scoped namespaces for an extension method that matches the implied signature.  The System.Linq namespace defines the extension method we’ve been examining above.  However, what if we wanted to use our own method instead of the System.Linq version of Where()?

We might want to add in some logging statements when the predicate finds a match.  Let’s do this right now by adding our own extension method for the IList<T> generic.  To do this we need to define a static class that contains a static Where method that has this IList<T> as its first parameter:

public static class ListExtensions
{
    public static IEnumerable<T> Where<T>(
        this IList<T> source, Func<T, bool> predicate)
    {
        foreach (T t in source)
        {
            if (predicate.Invoke(t) == true)
            {
                Console.WriteLine(
                    String.Format("Predicate indicated success for value: {0}", t));
                yield return t;
            }
        }
    }
}

This method is almost identical to the theoretical version of Where we built above.  The only differences are that it extends IList<T> instead of IEnumerable<T> and that it logs when the predicate finds a match prior to yielding the matched item.

Now let’s put together a little snippet that will exercise this extension method.  We can actually use the first sample we used in this post and by simply adding ToList() to the end of Enumerable.Range(1,9) we’ll be calling our extension method for Where() instead of the built-in System.Linq version.  Let’s look at that sample:

from num in Enumerable.Range(1,9).ToList()
where num % 2 == 0
select num

By simply adding the ToList() to the sample above we’ve caused the compiler to call our new Where() method.  This gives a pretty clear idea of how LINQ is working internally and what’s actually going on when we use the new C# 3.0 language keywords.  There is a lot less voodoo involved in the process that one might first believe!

Example Listing
The following is a complete example suitable for pasting into snippet compiler:

using System;
using System.Collections.Generic;
using System.Linq;

public class MyClass
{
    public static void RunSnippet()
    {
        Console.WriteLine("Results using the IEnumerable<T>.Where() method from System.Linq.");
        var enumResults =
            from n in Enumerable.Range(1,9)
            where n % 2 == 0
            select n;
        foreach (int n in enumResults)
            Console.WriteLine(n);
       
        Console.WriteLine("Results using the custom IList<T>.Where() method from this sample.");
        var listResults =
            from n in Enumerable.Range(1,9).ToList()
            where n % 2 == 0
            select n;
        foreach (int n in listResults)
            Console.WriteLine(n);
    }

   
   
    #region Helper methods
   
    public static void Main()
    {
        try
        {
            RunSnippet();
        }
        catch (Exception e)
        {
            string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
            Console.WriteLine(error);
        }
        finally
        {
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }

    private static void WL(object text, params object[] args)
    {
        Console.WriteLine(text.ToString(), args);   
    }
   
    private static void RL()
    {
        Console.ReadLine();   
    }
   
    private static void Break()
    {
        System.Diagnostics.Debugger.Break();
    }

    #endregion
}

public static class ListExtensions
{
    public static IEnumerable<T> Where<T>(this IList<T> source, Func<T, bool> predicate)
    {
        foreach (T t in source)
        {
            if (predicate.Invoke(t) == true)
            {
                Console.WriteLine(String.Format("Predicate indicated success for value: {0}", t));
                yield return t;
            }
        }
    }
}

posted @ Monday, July 14, 2008 11:51 AM | Feedback (0) |

Thursday, July 10, 2008

Bluetooth Retro Handset

Here’s one for all the folks who had a hard time letting go of “the way things used to be”:

ThinkGeek Bluetooth Retro Handset

posted @ Thursday, July 10, 2008 12:45 PM | Feedback (0) |

Deeper Project Visibility - with NDepend

Software projects, by nature, have a propensity for getting out of hand.  No matter how tightly we adhere to our carefully crafted development processes, despite diligent and methodical software designing and refactoring, the elusive software project always seems to manage to get away from us and mask its true nature from our prying eyes.  Something close to a bajillion dollars has probably already been spent in attempts to tame the software project and convince it to open up and reveal its inner secrets and with increasing success.  It has certainly been my experience that the software projects I’ve worked on in the last five years are much more transparent than they were fifteen years ago.  This is in no small part due to the fact that I am no longer a teenager banging out Win32 applications in Borland C++, stumbling my way through APIs until an acceptable solution to the problem in hand somehow occurred.  However, the view that software projects are becoming increasingly transparent is also shared by my peers.  The general consensus is that the tools and development environments have played a significant role in this, a significantly larger role than the maturity or structure of the code being developed.

This is the key observation that I have made in thinking about the problem of software project wrangling.  Despite advancement in the languages, environments, and tool-set, the code itself doesn’t seem to have become significantly more transparent.  Bear in mind also that I am not describing the “API of complete awesomeness” that represents years of careful labor and also accounts for about 0.1% of the code developed each year.  I’m talking about the other 99.9% of “copy/paste/tweak/pray” code that represents the bulk of what you and I will be maintaining, supporting, and extending for a notable portion of your software development career.  Given this (rather lofty, sweeping, and completely personal-opinion-based) assumption, thought moves again to the area in which our wrangling efforts have advanced: the tools.  If we can’t get people to architect more elegant solutions, perhaps we can find less painful ways to pry open Pandora’s box and examine the gifts our coding predecessors have left for us.

7-10-2008_NDepend_Logo

One tool in my arsenal for this task is NDepend.  Tools and development styles will always be very personal.  There are tools that I use for which others find no benefit and similarly there are those tools that have been recommended to me that just don’t seem to do what I need.  However, I can highly recommend that any developer at least evaluate NDepend for their own use as it brings a rather unique perspective to the problem of analyzing even the most elusive of software projects.

What does NDepend do?
Arguably one of the most important questions to ask when evaluating any new piece of software is what it does.  Put simply, NDepend analyzes your project and tells you stuff about it that might otherwise be difficult to discover.  It breaks down a software project into its most basic components and then lets you query and visualize the sum of those components in extremely powerful ways.  NDepend provides a wide variety of features for software analysis but undoubtedly the majority of its value lies in the power of CQL.  The Code Query Language is not unlike traditional T-SQL in both syntax and the type of problem it is trying to solve.  However, where SQL is designed to query data stores, the CQL language is designed to query software project information.  This has several applications from code navigation and searching to coding quality evaluation and a whole host of standards metrics calculations.

In short, NDepend provides an incredible amount of information about how your project is glued together and how every field, method, type, and assembly is structured as well as how each of those elements relates to one another.  When you first run NDepend upon a solution or set of assemblies, the amount of information that is presented can feel a little overwhelming.  However, as you start to present small problems for NDepend to solve it quickly becomes clear why all of this information is very necessary.

Where do I start?
The best way to start working with NDepend is to point it at an existing set of assemblies and run an analysis.  Then we can start to pick through the individual parts of the analysis and start to benefit from the information that is presented.  For this purpose I have down-loaded the source code for an open source project called NArrange.  This provides a nice publicly available solution on which to test NDepend such that the samples in this article can easily be reproduced.

NOTE: I also recommend viewing the video tutorials on the NDepend web-site.  The getting started tutorial covers a lot of the information I present here in much more detail (and very probably with higher accuracy).  The getting started tutorial video is located here.

Step 1 – Download and Install NDepend Trial
You can download a trial version of NDepend here.

Step 2 – Analyzing a Solution
First make sure that you build your solution, either using Visual Studio or via MSBuild or another tool.  NDepend analyses a set of assemblies rather than a project or solution.

From the NDepend start page, select “Analyze: a set of .NET assemblies”.  This will display a file selection dialog which we will use to browse to the NArrange libraries.  I navigated to the NArrange.Tests.ConsoleApplication bin/Debug directory as this contains many of the solution assemblies that we wish to analyze.  Once we have selected a set of assemblies, NDepend will being to run its initial analysis.  This should take about 30 to 60 seconds depending upon system load and performance.

7-10-2008_NDependStartPage   7-10-2008_NDepend_AssemblySelection

Once the analysis has completed, NDepend will display the current project in its main window as well as opening a browser that contains a full analysis report.

There is a tremendous amount of information in this report and it will take a while to become familiar with all of the data that is being presented.  To that end we will look at each of the sections in turn and adopt a step by step approach to understanding why this information is useful.

Analyzing the Analysis
Let’s first look at the project map (or VisualNDepend View).  If you close the browser that contains the NDepend Report you’ll see that the NDepend gui has been updated.  At the top is a section containing this view.

7-10-2008_ProjectMap

This looks a little like a topographical analysis of the moon with yellow writing on it.  In truth this is a lot like a lunar map except instead of showing the peaks and troughs of the moon’s surface it is showing the topography of our project.  The NArrange solution is split into several different projects, each of which compiles into an individual assembly.  The thin yellow lines separating sections of the map represent the boundaries between these assemblies.  Each of the little gray circles that fill in those yellow squares represents a group of code within that assembly.  In essence you are looking at the project as though it were arranged into states and counties.  Each county represents a type whereas each state represents an assembly that contains several of those types.  You can run your mouse over the project map and see that each gray area will turn red as you mouse over it.  Additionally, the name that gray area represents is displayed.  The purpose of this project map is to give you a visualization of the layout of the whole solution.  It also plays into a lot of the deeper analysis functions that NDepend has to offer and becomes a center-point for visualizing the location of code in the project.

7-10-2008_NavigatingTheVisualView

Start by clicking on one of the gray areas.  Note how the class browser window to the left is updated when an area is clicked.  This allows you to navigate your code visually while seeing the familiar class browser tree-view for the selected code element.  Alternatively you can click on a method or type in the class browser and see the visual view update by highlighting the appropriate area of the map.  Selecting an assembly in the class browser will highlight that entire assembly in the visual view pane.  The class browser gives a very zoomed in perspective of your project, whereas the visual view gives a fully zoomed out view of how a particular element relates to the other elements in the full solution.  I find a combination of the two to be a very powerful and expedient way to navigate a solution.

Abstractness vs Instability
Lets open the report that was generated after the initial analysis again.  To do this we can click the 7-10-2008_ViewReportButton button at the top of the Home ribbon.

7-10-2008_ViewReport

The set of links at the top of the report allow you to navigate the report contents.  Click the Assemblies Abstractness vs. Instability link to be taken to a graph that pinpoints this information for each assembly that was analyzed.  This graph contains two major zones of pain and uselessness, leaving a sweet spot in the middle.  Assemblies that are both abstract and unstable live at the top-right of the graph, in the zone of uselessness.  This is to indicate that pairing abstractness with instability serves little purpose.  Assemblies in the bottom-left of the graph are very stable and tightly concrete.  This can lead to significant pain when they are maintained or extended as they are so tightly coupled and interwoven that making even small changes can require significant effort.  The sweet spot in the middle represents the correct balance between abstraction and stability.  This can be a good visual aid when learning new code or revisiting code you haven’t touched for a long time.  The pain points and potential pitfalls are identified quickly.

7-10-2008_AbstractnessVsInstability

In this graph we can see that the NArrange assemblies are sitting firmly in the green zone.  The NArrange.Core assembly is the most abstract of the bunch but is also just stable enough to balance that level of abstraction.  It is expected that most test assemblies will cluster in the bottom right area of the graph, which is not a bad place to be.  Most test assemblies are fairly unstable and employ no abstraction as they are intended only for the purpose of testing a single type or set of known methods.

Additional Resources
This very brief overview was intended to scratch the surface of NDepend and give a feel for what this tool is trying to accomplish.  I’m working on more articles around the excellent CQL language and deeper features of NDepend.  These articles will be the basis of a training for some brown bags as well as the source material for more blog posts on this topic.  Meanwhile, here are some resources that are other great starting points for learning more about this great tool.

Stuart Celarier put together an excellent cheat sheet for NDepend that can be found here.  This is one of those sheets you just want to print out, laminate and either hang on the wall or find a place on your desk, perhaps even as a mouse mat.

The NDepend website contains a great series of videos and articles to help get started.

Other than that, one of the best ways to learn the tool is to simply install it and then start poking around with the analysis and learning by using.  Analyze your current project assemblies and then start navigating using the NDepend interface.  Play with some of the CQL queries (it will make reading future articles on CQL simpler because you’ll be more familiar).  Make sure to install the VisualStudio and Reflector addons as these make full circle integration a part of your life.  Other than that, I look forward to putting together my next NDepend article on using CQL to really understand and learn about how your code is put together and where it can be improved.

posted @ Thursday, July 10, 2008 11:21 AM | Feedback (0) | Filed Under [ Tools ]

Powered by: