Monday, September 28, 2009

MassTransit at Skills Matter

image

This Thursday, 1st October, I’m going to be giving a talk about MassTransit, a lean, open source, service bus for building loosely-coupled, message-based applications. The first half of the talk will be some general thoughts about message based architectures and why we should be considering them. The second half will be an overview of MassTransit. There will be plenty of code, but be warned, I’ve been getting crazy with Powerpoint animations to try and explain some of the concepts.

The talk is hosted by Gojko Adzic and SkillsMatter at the SkillsMatter offices which are located at the junction of St James's Walk and Sekforde Street, just northeast of Clerkenwell Green.

It’s free, but please register on the SkillsMatter site if you wish to attend.

See you there!

Friday, September 18, 2009

Why is ‘Buy’ not always better than ‘Build’

Building software is hard. I’ve been involved in building business systems for 13 years and it’s probably fair to say that I’ve been involved in more failures than successes, and I’m pretty sure that’s not merely the function of my effectiveness (or lack of it) as a software developer. Any business embarking on the development of a core system is taking on significant risk, because the core competencies of building software are probably not the core competencies of the business. After all the business of building software is a huge problem domain in its own right with a large and complex body of expertise.

Recognising this, many businesses when faced with a Buy vs Build decision will do almost anything to avoid Build; purchasing Commercial Off-The-Shelf (COTS) systems is always the preferred decision.

If your business need is a common one, then purchasing a COTS system is almost always the right choice. You would be insane to consider building a bespoke word processor for example.

But often it’s the case that your requirements are somewhat common, but with unique elements that only your business would need.

Given the understandable preference for Buy over Build, the temptation is to take a COTS system, or systems, and either fit your business around it, or have it customised in some way. So long as the features of the COTS software and your requirements overlap it’s worth buying it right?

clip_image002

Sure you will have some unsatisfied requirements and there will be some features of the COTS system that you don’t use, but you are still getting benefit. The unsatisfied requirements can be fulfilled by customising or extending the COTS package and the unused features can just be ignored.

You may have a requirement for customer relationship management for example; why not just buy MSCRM from Microsoft? The things your customers care about might be somewhat unique, but the Microsoft reseller will assure that MSCRM can be customised to meet your requirements. You might also have case-management style requirements alongside your customer relationship ones, why not buy a case management tool as well and simply integrate it with MSCRM?

But now, as soon as you decide to go down the COTS + customisation route, you are effectively doing software development. Except that now you have suckered your way into doing it rather than approaching it with your eyes open. You will find that extending and customising COTS systems is often a horrible variant of ugly hackery that’s almost impossible to do with good software craftsmanship. You will still have to hire developers, but instead of allowing them to build well architected solutions, you will be forcing them to do a dirty and thankless job. You can guess the calibre of developer that will be attracted to such a position.

The reason why it’s hackery is that it’s almost impossible to extend or customise software without rewriting at least a part of it; and of course, you won’t be able to rewrite your closed-source COTS system. To answer this, most COTS vendors pay some lip service to customisability and extensibility, but the hooks they provide are always somewhat clunky and limited. Anyone who has tried to build a system on top of Sharepoint, or customise MSCRM will know the pain involved. It’s the same for pretty much any enterprise software system.

Each additional requirement over and above the out-of-the-box features will cost significantly more than the equivalent additional requirement of a custom system.

You have a graph somewhat like this:

clip_image003

So long as your set of customisations is limited, it’s still worth going down the COTS route, but my experience is that the point where the two lines cross is further to the left than is often appreciated. The chart doesn’t of course factor in the original cost of the COTS system and that can be substantial for many ‘enterprise’ software packages.

A further consideration that’s often ignored is that business requirements often change over time. How are you going to ensure that your COTS system, even if it perfectly matches your requirements now, can continue to match them into the future?

So if you have to do software development, and you will have to unless you can find a COTS system that fully satisfies your requirements, why not do it properly: hire and nurture a great software team; put professional software development practices in place; properly analyse your business; work out exactly what you need from your supporting applications, and then build a system that exactly fits your needs.

An alternative might be to build a close relationship with a bespoke software house, but be aware that their incentives will not be fully aligned with yours and in any case, if your system is substantial, they will probably simply go to the open market and hire the same team of developers that you could have hired yourself.

So consider carefully the costs of a COTS system that doesn’t fully meet your requirements and don’t ignore the benefits that bespoke software built and supported by an in-house team can bring.

Wednesday, September 09, 2009

Slides and Code for last night’s VBug London NHibernate talk

Thanks to everyone who came to last night’s talk on NHibernate, and especially Sam Morrison of VBug for inviting me along and for Anteo Group for hosting the event.

You can download the code and slides from the talk here:
http://static.mikehadlow.com/Mike.NHibernateDemo.zip

The NHibernate homepage is here:
https://www.hibernate.org/343.html

Fluent NHibernate is here:
http://fluentnhibernate.org/

NHibernate Profiler is here:
http://nhprof.com/

NHibernate in Action by Pierre Henri KuatĂ©, Tobin Harris, Christian Bauer, and Gavin King is essential reading and can be purchased from the publisher, Manning’s, website:
http://www.manning.com/kuate/

image

Tuesday, September 01, 2009

Mocking Delegates

I never realised you could do this; use Rhino Mocks to mock a delegate:

using System;
using Rhino.Mocks;
using NUnit.Framework;

namespace Mike.MockingLambdas
{
    [TestFixture]
    public class Can_a_lambda_be_mocked
    {
        [Test]
        public void Lets_try()
        {
            const string text = "some text";

            var mockAction = MockRepository.GenerateMock<Action<string>>();
            var runsAnAction = new RunsAnAction(mockAction);
            runsAnAction.RunIt(text);

            mockAction.AssertWasCalled(x => x(text));
        }
    }

    public class RunsAnAction
    {
        private readonly Action<string> action;

        public RunsAnAction(Action<string> action)
        {
            this.action = action;
        }

        public void RunIt(string text)
        {
            action(text);
        }
    }
}

Wednesday, August 19, 2009

The first rule of exception handling: do not do exception handling.

Back when I was a VB developer, we used to wrap every single function with an exception handler. We would catch it and write it to a log. More sophisticated versions even featured a stack trace. Yes, really, we were that advanced :) The reason we did that was simple, VB didn’t have structured exception handling and if your application threw an unhandled error it simply crashed. There was no default way of knowing where the exception had taken place.

.NET has structured exception handling, but the VB mindset of wrapping every piece of code in a try-catch block, where the catch catches System.Exception, is still common, I see it again and again in enterprise development teams. Usually it includes some logging framework and looks something like this:

try
{
    // do something
}
catch (Exception exception)
{
    Logger.LogException("Something bad just happened", exception);    
}

Catching System.Exception is the worst possible exception handling strategy. What happens when the application continues executing? It’s probably now in an inconsistent state that will cause extremely hard to debug problems in some unrelated place, or even worse, inconsistent corrupt data that will live on in the database for years to come.

If you re-throw from the catch block the exception will get caught again in the calling method and you get a ton of log messages that don’t really help you at all.

It is much better to simply allow any exceptions to bubble up to the top of the stack and leave a clear message and stack trace in a log and, if possible, some indication that there’s been a problem on a UI.

In fact there are only three places where you should handle exceptions; at the process boundary, when you are sure you can improve the experience of the person debugging your application, and when your software can recover gracefully from an expected exception.

You should always catch exceptions at the process boundary and log them. If the process has a UI, you should also inform the user that there has been an unexpected problem and end the current business process. If you allow the customer to struggle on you will most likely end up with either corrupt data, or a further, much harder to debug, problem further down the line.

Improving the debugging experience is another good reason for exception handling. If you know something is likely to go wrong; a configuration error for example, it’s worth catching a typed error (never System.Exception) and adding some context. You could explain clearly that a configuration section is missing or incorrect and give explicit instructions on how to fix it. Be very careful though, it is very easy to end up sending someone on a wild goose chase if you inadvertently catch an exception you were not expecting.

Recovering gracefully from an expected exception is, of course, another good reason for catching an exception. However, you should also remember that exceptions are quite expensive in terms of performance, and it’s always better to check first rather than relying on an exception to report a condition. Avoid using exceptions as conditionals.

So remember: the first rule of exception handling: do not do exception handling. Or, “when in doubt, leave it out” :)

Friday, July 24, 2009

How MassTransit Publish and Subscribe works

clip_image002

This is a follow-on from my last post, A First Look at MassTransit. Here’s my take on how publish and subscribe works. It’s based on a very brief scan of the MT code, so there could well be misunderstandings and missing details.

The core component of MassTransit is the ServiceBus, it’s the primary API that services use to subscribe to and publish messages. The ServiceBus has an inbound and outbound pipeline. When publish is called, a message gets sent down the pipeline until a component that cares that message type dispatches it to an endpoint. Similarly, when a message is received it is passed down the input pipeline giving each component a chance to process it.

Understanding how the input and output pipelines are populated is the key to understanding how MassTransit works. It’s instructive to get a printout of your pipelines by inspecting them with the PipelineViewer. I’ve created a little class to help with this:

 

using System.IO;
using MassTransit.Pipeline;
using MassTransit.Pipeline.Inspectors;

namespace MassTransit.Play.Helpers
{
    public class PipelineWriter : IPipelineWriter
    {
        private readonly TextWriter writer;
        private readonly IServiceBus bus;

        public PipelineWriter(IServiceBus bus, TextWriter writer)
        {
            this.bus = bus;
            this.writer = writer;
        }

        public void Write()
        {
            writer.WriteLine("InboundPipeline:\r\n");
            WritePipeline(bus.InboundPipeline);
            writer.WriteLine("OutboundPipeline:\r\n");
            WritePipeline(bus.OutboundPipeline);
        }

        private void WritePipeline(IPipelineSink<object> pipeline)
        {
            var inspector = new PipelineViewer();
            pipeline.Inspect(inspector);
            writer.WriteLine(inspector.Text);
        }
    }
}

Let’s look at the sequence of events when RuntimeServices.exe, a subscriber service and a publishing service start up.

When RuntimeServices starts up the SubscriptionService creates a list of ‘SubscriptionClients’. Initially this is empty.

clip_image003

When our subscriber comes on line, it sends an AddSubscriptionClient message to the subscription service. The subscription service then adds our subscriber to its list of subscription clients.

clip_image004

Next our publisher comes on line. It also sends an AddSubscriptionClient message to the subscription service. It too gets added to the subscription clients list.

clip_image005

When the subscriber subscribes to a particular message type, ServiceBus sends an AddSubscription message to SubscriptionService which in turn scans its list of subscription clients and sends the AddSubscription message to each one.

SubscriptionService also adds the subscription to its list of subscriptions so that when any other services come on line it can update them with the list.

The publisher receives the AddSubscription message that was broadcast to all the subscription clients and adds the subscriber endpoint to its outbound pipeline. Note that the Subscriber also receives it’s own AddSubscription message back and adds itself to its outbound pipeline (not shown in the diagram).

clip_image006

The subscriber also adds a component to its inbound pipeline to listen for messages of the subscribed type. I haven’t show this in the diagram either.

When the publisher publishes a message, it sends the message down its outbound pipeline until it is intercepted by the subscriber’s endpoint and dispatched to the subscriber’s queue. The subscription service is not involved at this point.

clip_image007

I hope this is useful if you’re trying to get to grips with MassTransit. Thanks to Dru for clarifying some points for me.

Wednesday, July 22, 2009

A First Look at MassTransit

Get the code for this post here:

http://static.mikehadlow.com/MassTransit.Play.zip

I’ve recently been trying out MassTransit as a possible replacement for our current JBOWS architecture. MassTransit is a “lean service bus implementation for building loosely coupled applications using the .NET framework.” It’s a simple service bus based around the idea of asynchronous publish and subscribe. It’s written by Dru Sellers and Chris Patterson, both good guys who have been very quick to respond on both twitter and the MassTransit google group.

To start with I wanted to try out the simplest thing possible, a single publisher and a single subscriber. I wanted to be able to publish a message and have the subscriber pick it up.

The first thing to do is get the latest source from the MassTransit google code repository and build it.

The core Mass Transit infrastructure is provided by a service called MassTransit.RuntimeServices.exe this is a windows service built on Top Shelf (be careful what you click on at work when Googling for this J). I plan to blog about Top Shelf in the future, but in short it’s a very nice fluent API for building windows services. One of the nicest things about it is that you can run the service as a console app during development but easily install it as a windows service in production.

Before running RuntimeServices you have to provide it with a SQL database. I wanted to use my local SQL Server instance so I opened up the MassTransit.RuntimeServices.exe.config file, commented out the SQL CE NHibernate configuration and uncommented the SQL Server stuff. I also changed the connection string to point to a test database I’d created. I then ran the SetupSQLServer.sql script (under the PreBuiltServices\MassTransit.RuntimeServices folder) into my database to create the required tables.

So let’s start up RuntimeServices by double clicking the MassTransit.RuntimeServices.exe in the bin directory.

clip_image002

A whole load of debug messages are spat out. Also we can see that some new private MSMQs have been automatically created:

clip_image004

We can also launch MassTransit.SystemView.exe (also in the bin folder) which gives us a nice GUI view of our services:

clip_image006

I think it shows a list of subscriber queues on the left. If you expand the nodes you can see the types that are subscribed to. I guess the reason that the mt_subscriptions and mt_health_control queues are not shown is that they don’t have any subscriptions associated with them.

Now let’s create the simplest possible subscriber and publisher. First I’ll create a message structure. I want my message class to be shared by my publisher and subscriber, so I’ll create it in its own assembly and then reference that assembly in the publisher and subscriber projects. My message is very simple, just a regular POCO:

namespace MassTransit.Play.Messages
{
    public class NewCustomerMessage
    {
        public string Name { get; set; }
    }
}

Now for the publisher. MassTransit uses the Castle Windsor IoC container by default and log4net so we need to add the following references:

clip_image008

The MassTransit API is configured as a Windsor facility. I’m a big fan of Windsor, so this all makes sense to me. Here’s the Windsor config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <facilities>
    <facility id="masstransit">
      <bus id="main" endpoint="msmq://localhost/mt_mike_publisher">
        <subscriptionService endpoint="msmq://localhost/mt_subscriptions" />
        <managementService heartbeatInterval="3" />
      </bus>
      <transports>
        <transport>MassTransit.Transports.Msmq.MsmqEndpoint, MassTransit.Transports.Msmq</transport>
      </transports>
    </facility>
  </facilities>
</configuration>

As you can see we reference the ‘masstransit’ facility and configure it with two main nodes, bus and transports. Transports is pretty straightforward, we simply specify the MsmqEndpoint. The bus node specifies an id and an endpoint. As far as I understand it, if your service only publishes, then the queue is never used. But MassTransit throws, if you don’t specify it. I’m probably missing something here, any clarification will be warmly received J

Continuing with the configuration; under bus are two child nodes, subscriptionService and management service. The subscriptionService endpoint specifies the location of the subscription queue which RuntimeServices uses to keep track of subscriptions, this should be the location of the queue created when RuntimeServices starts up for the first time, on my machine it was mt_subscriptions. I’m unsure what the managementService specifies exactly, but I think it’s the subsystem that allows RuntimeServices to monitor the health of the service. I’m assuming that the heartbeatInterval is the number of seconds between each notification.

Next, let’s code our publisher. I’m going to create a simple console application, I would host a service with Top Shelf in production, but right now I want to do the simplest thing possible, so I’m going to keep any other infrastructure out of the equation for the time being. Here’s the publisher code:

using System;
using MassTransit.Play.Messages;
using MassTransit.Transports.Msmq;
using MassTransit.WindsorIntegration;

namespace MassTransit.Play.Publisher
{
    public class Program
    {
        static void Main()
        {
            Console.WriteLine("Starting Publisher");

            MsmqEndpointConfigurator.Defaults(config =>
            {
                config.CreateMissingQueues = true;
            });

            var container = new DefaultMassTransitContainer("windsor.xml");
            var bus = container.Resolve<IServiceBus>();

            string name;
            while((name = GetName()) != "q")
            {
                var message = new NewCustomerMessage {Name = name};
                bus.Publish(message);
                
                Console.WriteLine("Published NewCustomerMessage with name {0}", message.Name);
            }

            Console.WriteLine("Stopping Publisher");
            container.Release(bus);
            container.Dispose();
        }

        private static string GetName()
        {
            Console.WriteLine("Enter a name to publish (q to quit)");
            return Console.ReadLine();
        }
    }
}

The first statement instructs the MassTransit MsmqEndpointConfigurator to create any missing queues so that we don’t have to manually create the mt_mike_publisher queue. The pattern used here is very common in the MassTransit code, where a static method takes an Action<TConfig> of some configuration class.

The next line creates the DefaultMassTransitContainer. This is a WindsorContainer with the MassTransitFacility registered and all the components needed for MassTransit to run. For us the most important service is the IServiceBus which encapsulates most of the client API. The next line gets the bus from the container.

We then set up a loop getting input from the user, creating a NewCustomerMessage and calling bus.Publish(message). It really is as simple as that.

Let’s look at the subscriber next. The references and Windsor.xml config are almost identical to the publisher, the only thing that’s different is that the bus endpoint should point to a different msmq; mt_mike_subscriber in my case.

In order to subscribe to a message type we first have to create a consumer. The consumer ‘consumes’ the message when it arrives at the bus.

using System;
using MassTransit.Internal;
using MassTransit.Play.Messages;

namespace MassTransit.Play.Subscriber.Consumers
{
    public class NewCustomerMessageConsumer : Consumes<NewCustomerMessage>.All, IBusService
    {
        private IServiceBus bus;
        private UnsubscribeAction unsubscribeAction;

        public void Consume(NewCustomerMessage message)
        {
            Console.WriteLine(string.Format("Received a NewCustomerMessage with Name : '{0}'", message.Name));
        }

        public void Dispose()
        {
            bus.Dispose();
        }

        public void Start(IServiceBus bus)
        {
            this.bus = bus;
            unsubscribeAction = bus.Subscribe(this);
        }

        public void Stop()
        {
            unsubscribeAction();
        }
    }
}

You create a consumer by implementing the Consumes<TMessage>.All interface and, as Ayende says, it’s a very clever, fluent way of specifying both what needs to be consumed and how it should be consumed. The ‘All’ interface has a single method that needs to be implemented, Consume, and we simply write to the console that the message has arrived. Our consumer also implements IBusService, that gives us places to start and stop the service bus and do the actual subscription.

Here’s the Main method of the subscription console application:

using System;
using Castle.MicroKernel.Registration;
using MassTransit.Play.Subscriber.Consumers;
using MassTransit.Transports.Msmq;
using MassTransit.WindsorIntegration;

namespace MassTransit.Play.Subscriber
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine("Starting Subscriber, hit return to quit");

            MsmqEndpointConfigurator.Defaults(config =>
                {
                    config.CreateMissingQueues = true;
                });

            var container = new DefaultMassTransitContainer("windsor.xml")
                .Register(
                    Component.For<NewCustomerMessageConsumer>().LifeStyle.Transient
                );

            var bus = container.Resolve<IServiceBus>();
            var consumer = container.Resolve<NewCustomerMessageConsumer>();
            consumer.Start(bus);

            Console.ReadLine();
            Console.WriteLine("Stopping Subscriber");
            consumer.Stop();
            container.Dispose();
        }
    }
}

Once again we specify that we want MassTransit to create our queues automatically and create a DefaultMassTransitContainer. The only addition we have to make for our subscriber is to register our consumer so that the bus can resolve it from the container.

Next we simply grab the bus and our consumer from the container and call start on the consumer passing it the bus. A nice little bit of double dispatch :)

Now we can start up our Publisher and Subscriber and send messages between them.

clip_image010

clip_image012

Wow it works! I got a lot of childish pleasure from starting up multiple instances of my publisher and subscriber on multiple machines and watching the messages go back and forth. But then I’m a simple soul.

Looking at the MSMQ snap-in, we can see that the MSMQ queues have been automatically created for mt_mike_publisher and mt_mike_subscriber.

clip_image014

MassTransit System View also shows that the NewCustomerMessage is subscribed to on mt_mike_subscriber. It also shows the current status of our services. You can see that I have been turning them on and off through the morning.

clip_image016

Overall I’m impressed with MassTransit. Like most new open source projects the documentation is non-existent, but I was able to get started by looking at the Starbucks sample and reading Rhys C’s excellent blog posts. Kudos to Chris Patterson (AKA PhatBoyG) and Dru Sellers for putting such a cool project together.

Tuesday, June 30, 2009

IronPython in Action

image Writing a book about IronPython presents a dilemma, do you write a book introducing Python to .NET developers, or do you write a book introducing .NET to Python developers? Striking the right balance between the two is always going to be difficult, but Michael Foord and Christian Muirhead have made a very compelling attempt. Of course I can’t speak for the Python hacker coming to the world of .NET for the first time, but for a .NET guy like me, the book is an excellent introduction to Python and how IronPython works with the rest of the .NET ecosystem.

It’s a very well written and crafted book, with an easy to read conversational style. I find many programming books quite hard work, but this one was a pleasure.

The compromise for me was a rather too high level introduction to Python itself, I would have preferred a deeper introduction to the details of Python and its standard libraries. But then I guess I could always go and buy a Python book, or check out the prodigious online resources for a more in-depth view. I’m not particularly interested in Winforms programming, so I didn’t really get much out of those parts of the book, but I guess the detail is understandable when you know that the authors day job is programming a large winforms system, Resolver One. Chapter 8 on metaprogramming and protocols was very interesting for a dynamic newbe like me, and chapter 15, on embedding the IronPython engine, also sparked off quite a few ideas.

I disagree with Craig Murphy’s comment on the back cover, “… and if you are new to programming, it’s for you too.” Michael and Christian go too deep too fast for a complete beginner. You would really need to have some background in either .NET or Python to get the most out of this book.

So am I excited about IronPython? A bit. I think I need to actually try some serious programming with it. For me its two obvious applications are as an embedded scripting language and for those tasks that don’t justify a fully compiled .NET application, such as automated deployments. I’m sure that you could be very successful building large applications with it, as indeed the authors have, but I don’t feel immediately compelled to drop C#.

I’m certainly not as excited about IronPython and the DLR as I am about functional languages such as F#. Functional programming really is a new paradigm. If you told me we would all be writing our applications with dynamic languages in ten years time, I’d be sceptical. But with functional languages, I’d be inclined to agree. Maybe we will see the emergence of a more polyglot programming ecosystem? In that world there’s certainly a place for IronPython.

Thursday, June 11, 2009

TFS Build: _PublishedWebsites for exe and dll projects

We’re using TFS on my current project. Yes, yes, I know.

It’s generally good practice to collect all the code under your team’s control in a single uber-solution as described in this Patterns and Practices PDF, Team Development with TFS Guide. If you then configure the TFS build server to build this solution, it’s default behaviour is to place the build output into a single folder, ‘Release’.

Any web application projects in your solution will also be output to a folder called _PublishedWebsites\<name of project>. This is very nice because it means that you can simply robocopy deploy the web application.

Unfortunately there’s no similar default behaviour for other project types such as WinForms, console or library. It would be very nice if we could have a _PublishedApplications\<name of project> sub folder with the output of any selected project(s). Fortunately it’s not that hard to do.

The way _PublishedWebsites works is pretty simple. If you look at the project file of your web application you’ll notice an import near the bottom:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />

On my machine the MSBuildExtensionsPath property evaluates to C:\Program Files\MSBuild, if we open the Microsoft.WebApplication.targets file we can see that it’s a pretty simple MSBuild file that recognises when the build is not a desktop build, i.e. it’s a TFS build, and copies the output to:

$(OutDir)_PublishedWebsites\$(MSBuildProjectName)

I simply copied the Micrsoft.WebApplication.targets file, put it under source control with a relative path from my project files and changed _PublishedWebsites to _PublishedApplications and renamed the file CI.exe.targets. For each project that I want to output to _PublishedApplications, I simply added this import at the bottom of the project file:

<Import Project="<your relative path>\CI.exe.targets" />

You can edit CI.exe.targets (or whatever you want to call it) to do your bidding. In my case, the only change so far is to add a couple of lines to copy the App.config file:

<Copy SourceFiles="$(OutDir)$(TargetFileName).config" DestinationFolder="$(WebProjectOutputDir)\bin" SkipUnchangedFiles="true" />

There’s a lot of stuff in Microsoft.WebApplication.targets that’s only relevant to web applications and can be stripped out for other project types, but I’ll leave that as an exercise for the reader.

There was also a discussion on StackOverflow, with some nice alternative suggestions of how you might want to do this. It’s worth checking out.

Friday, May 29, 2009

What I look for in a Code Review

I recently put this bullet point list together for the team I’m currently working with.

Naming Conventions

General Principles

  • The core imperative is to organise complexity.
  • Clarity and readability is central. “Intention Revealing”
  • Do not prematurely optimise for performance.
  • Do not repeat yourself. Never copy-and-paste code.
  • Decouple.
  • Always try to leave the code you work on in a better state than before you started (the ‘boy scout’ principle)

Keep the source clean

  • Always delete unused code. Including variables and using statements
  • Don’t comment out code, delete it. We have source control to manage change.

Naming things

  • The name should accurately describe what the thing does.
  • Do not use shortenings, only use well understood abbreviations.
  • If the name looks awkward, the code is probably awkward.

Namespaces

  • Namespaces should match the project name + path inside the project. This is what VS will give you by default.
  • Classes that together provide similar functions should be grouped in a single namespace.
  • Avoid namespace dependency cycles.

Variables

  • Use constants where possible. Avoid magic strings.
  • Use readonly where possible
  • Avoid many temporary variables.
  • Never use a single variable for two different puposes.
  • Keep scope as narrow as possible. (declaration close to use)

Methods

  • The name should accurately describe what the method does.
  • It should only do one thing.
  • It should be small (more than 10 lines of code is questionable).
  • The number of parameters should be small.
  • Public methods should validate all parameters.
  • Assert expectations and throw an appropriate error if invalid.
  • Avoid deep nesting of loops and conditionals. (Cyclomatic complexity).

Classes

  • The name should accurately describe what the class does.
  • Classes typically represent data or services, be clear which your class is.
  • Design your object oriented schema deliberately.
  • A class should be small.
  • A class should have one responsibility only.
  • A class should have a clear contract.
  • A class should be decoupled from its dependencies.
  • Favour composition over inheritance.
  • Avoid static classes and methods.
  • Make the class immutable if possible.

Interfaces

  • Rely on interfaces rather than concrete classes wherever possible.
  • An interface is a contract for interaction.
  • An interface should have a single purpose (ISP)

Tests

  • All code should have unit tests if possible.
  • Test code should have the same quality as production code.
  • Write code test-first wherever possible.

Error Handling

  • Only wrap code with a try..catch statement if you are expecting it to throw a specific exception.
  • Unexpected errors should only be handled at process boundaries.
  • Never ‘bury’ exceptions.