Pablo Picasso
"Computers are useless. They can only give you answers."
My Latest Tweets
Tags

This will be shown to users with no Flash or Javascript.
Calendar
<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

Sign in

Adding an image in WPF is very straight forward. All you need to do is declare an Image element in XAML and specify the path of the image in the Source attribute:

<Image Source="about.png" />

But rather than deploying all your image files with your application, you might want to embed them in the assembly as resources:

Image resource build action. Once you’ve done that, you can start referring to images using either an absolute or relative URI:

<Image Source="pack://application:,,,/
Tbf.Presentation.Common;component/UI/Images/menu/about.png" />

or

<Image Source="Tbf.Presentation.Common;component/UI/Images/menu/about.png" />

Here Tbf.Presentation.Common is the assembly containing the compiled resource and UI/Images/menu is the project folder where the image is located:

Image folder location.

But this is really prone to errors and can quickly become a maintenance headache if you rename or move files around. Instead wouldn’t it be better to have all the pack URIs into one place? The way to do this is to add a new resource dictionary, say ImageResources.xaml, to your project.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:Images="clr-namespace:Tbf.Presentation.Common.UI.Images">

    <!-- Menu -->
  <ImageSource x:Key="about_menu">
	Tbf.Presentation.Common;component/UI/Images/menu/about.png
  </ImageSource> 

</ResourceDictionary>

Then simply merge it into your App.xaml file or any other application-wide resource file…

<Application x:Class="Tbf.Presentation.Shell.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Startup="Application_Startup"
             Activated="Application_Activated"
             Deactivated="Application_Deactivated"
             DispatcherUnhandledException="Application_DispatcherUnhandledException"
             Exit="Application_Exit">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <ResourceDictionary Source="pack://application:,,,/
                       Tbf.Presentation.Common;component/Infrastructure
                       /Resources/ImageResources.xaml" />

            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

… to make images available as dynamic resources across the whole application:

<Image Source="{DynamicResource about_menu}" />

In terms of maintainability however this is still not satisfactory as there is no design or compile time checking to ensure that the key is correct. To improve on this, we can introduce a new ImageLibrary class in the project to help us specify the image resource key in XAML:

namespace Tbf.Presentation.Common.UI.Images
{
    #region Using Directives 

    using System.Windows; 

    #endregion 

    public class ImageLibrary
    {
        public static ComponentResourceKey AboutMenu
        {
            get
            {
                return new ComponentResourceKey(typeof(ImageLibrary), "about_menu");
            }
        } 
    }
} 
 

Next we have to go back to the ImageResources.xaml file and modify it to make use of the new helper class:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:Images="clr-namespace:Tbf.Presentation.Common.UI.Images">

    <!-- Menu -->
    <ImageSource 
x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type Images:ImageLibrary}, ResourceId=about_menu}">
Tbf.Presentation.Common;component/UI/Images/menu/about.png
    </ImageSource> 

</ResourceDictionary> 

Et voilà! We have the support of intellisense for selecting images:Component key and Intellisense.A big improvement then? Yes but not quite perfect yet as now we have to define the key in two places: the ImageResources.xaml file and the ImageLibrary.cs file. To reduce further the amount of work we need to do, we can create a T4 template to automatically generate the ImageLibrary component keys:

1. Add a new item ImageLibrary.tt item in your project.

2. Copy and paste the code below (making the necessary adjustments for the namespace and ImageResources.xaml file path).

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Linq" #> 

namespace Tbf.Presentation.Common.UI.Images
{
    #region Using Directives 

    using System.Windows; 

    #endregion 

    public static class ImageLibrary
    {
<#
foreach (string key in this.GetComponentResourceKeys())
{
    string name = this.GetPropertyname(key);
#> 

        public static ComponentResourceKey <#= name #>
        {
            get
            {
                return new ComponentResourceKey(typeof(ImageLibrary), "<#= key #>");
            }
        }
<#
}
#>
    }
}<#+ 

public List<string> GetComponentResourceKeys()
{
    // Get the image resources file
    string file = @"<PATH>\ImageResources.xaml"; 

    // Read the image resources file
    string content; 

    using(System.IO.StreamReader sr = new System.IO.StreamReader(file))
    {
        content = sr.ReadToEnd();
    } 

    // Extract the keys
    Regex regex = new Regex(
                    "(?<=ResourceId=).*(?=})",
                    RegexOptions.CultureInvariant
                    | RegexOptions.IgnorePatternWhitespace
                    | RegexOptions.Compiled); 

    List<string> results = new List<string>();
    MatchCollection matches = regex.Matches(content); 

    for(int i = 0; i < matches.Count; i++)
    {
        results.Add(matches[i].Value);
    } 

    return results;
} 

public string GetPropertyname(string text)
{
    text = Regex.Replace(text, @"[\W-[\s]]", string.Empty);
    string[] words = text.Split('_', ' '); 

    for (int i = 0; i < words.Length; i++)
    {
        if (words[i].Length > 0)
        {
            string word = words[i];
            char firstLetter = char.ToUpper(word[0]);
            words[i] = firstLetter + word.Substring(1).ToLower();
        }
    } 

    return string.Join(string.Empty, words);
}
#> 

 

3. Run the TextTemplatingFileGenerator tool on the newly created .tt file.

Run TextTemplatingFileGenerator tool.

All done. The image library class is auto-generated and you can now set images in XAML knowing that any errors will be picked up either at design or compile time.

Today my colleague Rob pointed out to me that enabling Code Analysis (aka FxCop) on our solution was slowing down the build time on his machine to a rather unacceptable level. After some very unscientific perf testing, watch in hand, we saw the build time increase by more than 20 seconds with code analysis turned on. Rob therefore asked me whether there was a way we could bypass it – apart from disabling code analysis altogether which is not something we were willing to consider. The only thing I could suggest was to run the solution build out-of-proc using an ‘old’ trick I’ve applied for quite a while to VS2008, courtesy of Scott Hanselman’s Parallel MSBuilds from within the Visual Studio IDE. As we have moved over to VS2010, here is how I adapted it on my machine.

  1. Go to Tools > External Tools…
  2. Click on Add
  3. Fill in the following details:
  • Title: Parallel Build
  • Command: C:\Windows\Microsoft.NET\Framework\v4.0.30128\MSBuild.exe
  • Arguments: /m $(SolutionFileName) /v:m /t:Rebuild /p:Configuration=Debug
  • Initial directory: $(SolutionDir)

The arguments break down is as follows:

/m Switch that allows projects to be built in parallel.
/v:m Specifies the verbosity level for logging - q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].
/t:Rebuild Forces a solution cleanup and then a full rebuild.
/p:Configuration=Debug Sets the solution configuration to build for.

 External Tools

Moments later, Rob came back with an answer to our original problem with Code Analysis. As it happens, all that is required is an extra property at the end of the arguments list as shown below:

/m $(SolutionFileName) /v:m /t:Rebuild
/p:Configuration=Debug /p:RunCodeAnalysis=False

After that all we had to do was to bind the new external command to a keyboard shortcut to give us the flexibility of a faster build and hopefully save us a lot of compile time in the long run.

A lot of Developers who have never seen ReSharper in action often do not appreciate how much more productive they could be if they would start using it. Their arguments for not trying it out usually ranges from “I don't want to rely on a tool to do my coding” to “Why should I use R# when Visual Studio is already doing most of what I want/need” or “I don't like R# telling me what to do”. While these can be easily refuted, I think the main issue is that learning the tool itself can be a bit daunting at first. There are a lot of shortcuts to remember, options to set and functionality to digest. It also means adapting the way you work with the IDE and unlearn some old habits.

So if you are one of these reluctant Developers or just want to become a R# Jedi but don't know where to start, here is my advice: Learn the three shortcuts that rule them all... and the rest will follow!

1. Navigation

Navigation shortcut Navigation options

 

2. Code Generation

 Code generation shortcut Code generation options

3. Refactoring

 Refactoring shortcutRefactoring options

Note that all the options displayed are context sensitive and depend on where the caret is placed. Hence you will get different menu items based on whether your cursor is on a class, a method, etc.

I have been coding with ReSharper since version 3.0 and I simply can't work without it. It is IMO a must-have productivity tool and because of that I have encouraged any .NET Developer I work with to start exploring its capabilities by learning these three shortcuts. So far none of them have gone back to using plain vanilla Visual Studio. Hopefully if you break down the learning curve this way, you will also reap the benefits of what some people have called “the best IDE for Visual Studio”!

…Bonus Shortcuts: Go to type and Go to file.

Search shortcuts

Up until a couple of months ago, I’ve been coding at home either on my company laptop or my own PC. The problem is that neither are decent enough to do any kind of serious Development. I was constantly fighting the machines and grew increasingly frustrated with using sub-standard equipment. So I eventually decided enough is enough and broke the bank to buy myself a brand new Dev machine. To narrow down my search I did set the following criteria which the new system would have to meet: quad core with at least 6GB of RAM capable of running Windows 7 Ultimate 64-bit and video editing applications. But to make my quest even more challenging, my main requirement is that it had to be a laptop! While a desktop usually represents a better option with more bang for your dollar, I am - for some reason - a lot more comfortable developing on a laptop. So after weeks of hunting down that elusive piece of equipment, I finally found the Holy Grail at Overclockers UK.

My Dev Laptop Here is the spec:

  • Processor: Intel Quad Core i7
  • Screen: 17” WSXGA 1920x1200 TFT
  • Memory: 6GB DDR3 1066MHz Triple Channel RAM
  • Primary Hard Drive: 2x Kingston SSDNow V Series 64GB in RAID 0 Configuration
  • Secondary Hard Drive: 500GB 7200RPM
  • Graphics: Nvidia GeForce GTX 280M 1024MB
  • Wireless LAN: 802.11a, 802.11b & 802.11g
  • Ethernet LAN: 10/100
  • Sound Controller: High Definition Audio
  • Speakers: Stereo
  • Expansion: 54mm ExpressCard Slot
  • Camera: 2.0 Megapixel
  • Connections: 4x USB 2.0, 1x HDMI, 1x DVI, 1x RJ-45, Microphone & Headphones
  • Battery: 12-Cell Lithium-Ion
  • Dimensions: 397mm x 298mm x 60mm
  • Weight: Approx. 5.4kg

    Holy Grail…and I haven’t looked back since. I can now happily focus on what I really love doing, that is programming software, without worrying any longer about whether my machine can cope or not. It can!!!

  • Some time ago, while reinstalling StyleCop for ReSharper, I had to restart Visual Studio in order to reload the add-in. I then realised that restarting VS actually requires quite a lot of ‘clicking’ around. First you have to exit the editor, then you need to launch Visual Studio again and finally you have to re-open the solution you were working on just before you closed the IDE. This did not seem very efficient and, a quick macro later, I had a way to restart VS easily with one single click.

    Public Sub RestartVisualStudio()
        Dim solution As String = DTE.Solution.FullName
        DTE.Solution.Close(True)
     
        If String.IsNullOrEmpty(solution) Then
            solution = String.Empty
        Else
            solution = """ """ & solution
        End If
     
        Dim process As System.Diagnostics.Process = New System.Diagnostics.Process()
        Dim arguments As String = "/c start """" /high """ & DTE.FullName & solution & """ /nosplash"
        process.StartInfo = New ProcessStartInfo("cmd.exe", arguments)
        process.StartInfo.UseShellExecute = False
        process.StartInfo.CreateNoWindow = True
        process.Start()
     
        DTE.Quit()
    End Sub

    As restarting VS is not something I do that often, I just added a restart button on my custom toolbar.

    Restart Visual Studio

    Ok. I promise this is my last post on Visual Studio macros… for 2009 :)

    In my previous post I mentioned that I  usually work in full screen mode with all the toolbars removed to maximise the amount of code I can see on the screen. To activate full screen mode I just type Shift + Alt + Enter. Note that you can also squeeze in that little extra space by disabling the scrollbars under Tools > Options > Text Editor.

    Visual Studio scrollbars options

    However after you’ve built your solution, tracked a file within Solution Explorer and inspected a class using the ReSharper File Structure window, you end up with a fairly ‘dirty’ screen.

    Visual Studio dirty full screen

    All that viewing space is now lost! One solution is to set all the windows to ‘Auto Hide’. However since I find this feature rather annoying (in most cases) I tend to pin down all my working windows and therefore I need another way to recover that viewing space. As usual a small macro can do the trick. The macro below simply closes any active tool window that is currently opened.

    Public Sub CloseAllToolWindows()
    	Dim items As EnvDTE.Windows = DTE.Windows
    	Dim item As Window
    
    	For Each item In items
    		If item.Kind.Equals("Tool") And item.Visible Then
    			item.Close()
    		End If
    	Next
    End Sub

     

    Once bound to a keyboard shortcut, Alt + S in my case, I can run it and enjoy my full screen again!

    Full Screen Mode

    As I tend to work mainly in full screen mode within Visual Studio with all toolbars closed, I use shortcuts quite extensively to execute standard IDE and ReSharper commands. Fortunately most commands already have shortcuts associated to them. However there are a few that I need to either map to new shortcuts or rebind to different key combination.

    Below are my custom keyboard mappings:

    Command Shortcut
    Build.BuildSelection Shift + F6
    Edit.LineOpenAbove Shift + Enter
    Edit.ToggleWordWrap Alt + W
    File.CloseAllButThis Ctrl + \
    Macros.MyMacros.TBF.CloseAllToolWindows Alt + S
    Macros.MyMacros.TBF.DecreaseTextEditorFontSize Alt + [
    Macros.MyMacros.TBF.IncreaseTextEditorFontSize Alt + ]
    Macros.MyMacros.TBF.RemoveRegions Ctrl + Shift + #
    ReSharper.CollapseInSolutionExplorerAction Ctrl + `
    ReSharper.Generate Alt + I
    ReSharper.GotoNextErrorInSolution Alt + 0
    ReSharper.MoveDown Ctrl + Left Windows, Ctrl + Down Arrow
    ReSharper.MoveLeft Ctrl + Left Windows, Ctrl + Left Arrow
    ReSharper.MoveRight Ctrl + Left Windows, Ctrl + Right Arrow
    ReSharper.MoveUp Ctrl + Left Windows, Ctrl + Up Arrow
    TestDriven.NET.RunTests F8
    TestDriven.NET.RerunTests Shift + F8

     

    To change your keyboard binding in Visual Studio, follow the steps below:

    1. Go to Tools > Options > Keyboard.
    2. Select the command you would like to bind to (e.g. Macros.Samples.Accessibility.DecreaseTextEditorFondSize).
    3. Select Text Editor or Global where appropriate.
    4. Enter your shortcut key (e.g. Alt + [).
    5. Click on Assign.

     Decrease text font size key binding

    Once you’ve assigned all your keyboard shortcuts simply click OK and you’re done!

    As I was running a macro to increase or decrease the text font size (see previous post), I noticed that the macro balloon kept on flashing in the system tray. The reason for this is that in Visual Studio 2008, a balloon tip is shown every time you run a macro, until you click on it 5 times that is. Thereafter it will be no longer visible. The problem is that your macro might be running too quickly, giving you no time to click on it. For some background on this and why it is behaving like this by design, read Stopping the “Click here balloon” by Craig Skibo.

    macro_balloon  

    While I sort of understand why the VS team did this, I actually don’t care much for this feature. So I thought I’ll disable it altogether. This is easily done by adding a new registry key (HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\DontShowMacrosBalloon) and setting its value to 6. Note that you will still see the spinning cassette icon in the system tray but this is a lot less intrusive.

    Instead of doing this manually I wrote a macro to disable this feature as otherwise I’ll probably forget I ever done this.

    ' Suppresses the macros balloon.
    Public Sub DontShowMacrosBalloon()
    	Dim key As Microsoft.Win32.Registry Key
    	Dim subKey As Microsoft.Win32.Registry Key
    
    	key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\Microsoft\VisualStudio\9.0", True)
    	If (Not key Is Nothing) Then
    		subKey = IIf(key.OpenSubKey("DontShowMacrosBalloon") Is Nothing, key.CreateSubKey("DontShowMacrosBalloon"), key.OpenSubKey("DontShowMacrosBalloon"))
    		key.SetValue("DontShowMacrosBalloon", "00000006", Microsoft.Win32.RegistryValueKind.DWord)
    		subKey.Close()
    		key.Close()
    	End If
    End Sub

    Should you ever want to re-enable it, simply delete the registry key or run the macro below:

    ' Enables the macros balloon simply by deleting the key
    Public Sub ShowMacrosBalloon()
    	Dim key As Microsoft.Win32.RegistryKey
    
    	key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\Microsoft\VisualStudio\9.0", True)
    	If (Not key Is Nothing) Then
    		key.DeleteValue("DontShowMacrosBalloon", False)
    		key.Close()
    	End If
    End Sub

    Warning
    The macros above modify the Registry and therefore the usual precautions apply.

    The other day I grew increasingly frustrated with the amount of code I could or rather couldn’t see on my screen at work, even when working in full screen mode. I therefore wanted to write a Visual Studio macro to zoom in and out of the text editor. However while browsing through the sample macros that come with Visual Studio 2008, I found two macros that are doing just what I wanted: DecreaseTextEditorFontSize and IncreaseTextEditorFontSize. To check whether they are installed on your machine, simply go to Tools > Macros > Macro Explorer or type in ALT + F8 and then drill down to Macros > Accessibility.

    Macro Explorer: Decrease Increase Text Editor Font Size 

    Here is the Visual Basic code (after I changed fontSizeIncrement from 2 to 1):

    ' Set the font size increment and minimum font size
    Private Const fontSizeIncrement As Integer = 1
    Private Const minimumSupportedEditorSize As Integer = 3
    
    ' Increases the font size used within the editor.
    Public Sub IncreaseTextEditorFontSize()
    	Dim textEditorFontsAndColors As Properties
    
    	textEditorFontsAndColors = DTE.Properties(“FontsAndColors”, “TextEditor”)
    	textEditorFontsAndColors.Item(“FontSize”).Value += fontSizeIncrement
    End Sub
    
    ' Decreases the font size used within the editor.
    Public Sub DecreaseTextEditorFontSize()
    	Dim textEditorFontsAndColors As Properties
    	Dim fontSize As [Property]
    
    	textEditorFontsAndColors = DTE.Properties(“FontsAndColors”, “TextEditor”)
    	fontSize = textEditorFontsAndColors.Item(“FontSize”)
    	If fontSize.Value >= minimumSupportedEditorSize Then
    		fontSize.Value -= fontSizeIncrement
    	End If
    End Sub

    If you don’t have the Visual Studio samples, follow the steps below to add these two macros:

    1. Open the Macro IDE (Tools > Macros > Macro IDE or ALT + F11).
    2. In Project Explorer, right-click on My Macros and select Add New Item…
    3. In the Add New Item… dialog, choose Module, give it a name (e.g. MyModule) and click Add.
    4. Simply copy and paste the code above in the newly added module.
    5. Save and close the Macro IDE.

     Add new module

    All I had to do after that was to bind these macros to a keyboard shortcut. I chose ALT + [ to decrease the text font size and ALT + ] to increase it.

     Decrease text font size key binding

    Now, I can easily zoom code in and out in the Visual Studio Text Editor.

    In my previous post, I introduced NDepend and talked about how to get started. Now I’d like to review why I want to use it on my projects.

    First of all, I really like the analysis reports. Not only do they show you instantly the current state of your application and how healthy it is (or not), but it also gives you an objective and systematic way of introspecting your code base. In conjunction with the code query constraints and metrics, they really help you monitor the quality of your .NET components. Even more so if you can run them as part of your build process.

    As Mark Needham pointed out in this blog post, remembering to follow some of the OO design principles is not always an easy task when you’re coding. However by having the tool check for adherence to pre-defined rules/best practices, you can automate the identification step of the refactoring process thereby giving the Dev team more time to focus on the overall design, behaviour and functionality of the system.

    Visual Studio already includes code analysis and FxCop but NDepend goes a lot further and one of its strength is that it let’s you visualize your code in a way that no other tool does. Napoleon said “un bon croquis vaut mieux qu’un long discours” (which more or less is the same as “a picture is worth a thousand words” in English) and so the diagrams produced by NDepend can help you digest complex architectures more easily.

    NDepend Diagrams 

    Now you might also ask what is wrong with just using the built-in Visual Studio 2008 code metrics? Well nothing but NDepend gives you much more than just cyclomatic complexity, depth of inheritance, class coupling and lines of code. There’s more than 80 code metrics out-of-the-box and if one is not applicable or you feel is inadequate for your particular application, you can easily customize the report by amending existing code queries or creating new ones to suit your needs. Also Visual Studio is not as granular and does not let you drill down the dependencies.

    Note that NDepend has some rules defined around naming conventions but I think StyleCop is probably better suited to enforce a specific coding style and ensure consistency. Nonetheless NDepend includes some useful additional constraints such as the ones setting limits on the length of method or field names. Moreover it is relatively easier to add your own custom naming conventions for your particular project with NDepend.

    What initially sparked my interest in NDepend is that it really complements ReSharper as a refactoring tool. In particular there are a few key design concepts that ReSharper’s code analysis simply does not cover, yet can be evaluated using NDepend: cyclomatic complexity, number of method parameters, class cohesion, total coupling and inheritance depth to name just a few. But with both tools in my arsenal I feel better equipped to write cleaner and more SOLID code.

    I probably sound like an NDepend fanboy but I am passionate about using the right tools for delivering quality software. Yet NDepend can still improve in some areas and I have put below a wish list of the things that IMO would help make the tool even better:

    • Better integration with Visual Studio as I don’t like to leave my IDE and flip between the two all the time.
    • Code duplication analysis to reduce code clutter and abide by the DRY principle. Note that some of my colleagues have used Simian in the past to do this but I would personally prefer to do this with a tool I’m already using and familiar with.
    • Full screen mode for graph and dependency matrix windows.
    • Easier navigation between views and better shortcut support. There’s no shortcut for example to close an active window or to cycle through open windows (similar to Ctrl + Tab in visual Studio).
    • Automatic filtering of test projects when adding assemblies from a Visual Studio solution.
    • Being able to delete NDepend projects from the start-up page as at the moment you have to mess around with xml files to do that instead.
    • Quick search textbox in the Class Browser window similar to the one found in Visual Studio so that I can quickly go to a known type rather than drill down the treeview.
    • Cheaper single user licenses as I think the current pricing model is a barrier to entry for most Developers.

    Finally I’d love to see some sort of integration with ReSharper. It would be great to be able to define code queries using NDepend and have ReSharper flag them as solution errors if the constraints are not met. This is probably fiction at the moment but one can dream!

    Overall NDepend is a terrific product to pick up. It should save time over the lifecycle of a project, facilitate communication and increase productivity by aiding refactoring and generally making maintenance tasks easier to perform. Did I mention that it is also a cool way of learning about code metrics and some fundamental OO design principles?

    I haven’t fully grokked NDepend yet but practice makes perfect and I’m really looking forward to use it on my next project. With the upcoming release of Visual Studio 2010, StyleCop + FxCop + ReSharper + NDepend will be a killer combination for developing .NET apps.

    Disclaimer: This evaluation of Visual NDepend is based on a copy of the Professional edition supplied by Patrick Smacchia.

    Caring about quality is not just about producing great code but it is also about producing great software.