SQL Server: Clustered Indexes

We’ve already talked about how a level of an index looks a lot like a table.  Clustered indexes take this to the logical conclusion: they use the actual table as the leaf nodes of the index.  This means that we save a whole level of the index, which makes it faster than a non-clustered index.  (That’s providing you need columns not in the index.  Otherwise index covering is typically faster.)  It also means that you’ve actually ordered the table according to the index.

The ordering of the actual table is huge, and the ramifications are large.  The simplest, and probably least interesting, is that you can only have the one clustered index.  However, the ordering also makes it the ideal candidate for range based searches.  If you’re pulling down a large number of columns, it’s your go-to index for unique searches.

Implications of Clustered Indexes for Inserts

The biggest implication of clustered indexes, however, isn’t to do with select performance, it’s to do with inserts.  Remember, we’ve just ordered the actual table.  This means we’ve just specified onto which page any given row will be inserted.  Choose this badly, and you can really kill performance.

Right, I’m not going to go into all of the possible ways that SQL server can arrange a table.  I’m just going to give you one simple piece of advice.  Every table needs a unique clustered index.  Trust me on this.  (There will be experts who have counter-examples, but once you know that much, you won’t need to read this article.)

Now, basically you’re about to look at a trade-off.  If inserts happen randomly in your table, you’ll get page splits.  Page splits are where a page is full and a new row needs adding in the middle.  SQL Server splits the page into two, half-empty pages.  DBAs talk about “fill factor” as a measure of how full your pages are.  The higher the fill factor, the better.  If you have a fairly random key for your clustered index, your fill factor will go down with time.  This isn’t the end of the world, because you can rebuild your indexes and, by implication, your table.  Your DBA will know all about this, and it’s the major reason why he needs to block out time at the weekend to run maintenance scripts.  (The same thing happens to non-clustered indexes as well, but the effects aren’t as severe simply because the index is much smaller.)

It might seem like coming up with a “random” clustered index is a bad idea.  Actually, it’s a very good idea.  As I said, it’s a trade off.  Choosing a predictable index spec gives you a higher fill factor, but at the expense of concurrency.

The Clustered Identity Anti-Pattern

So, let’s say that you do what a lot of people do and place a clustered index on the identity field.  Usually this is declared as the primary key, but SQL server doesn’t really care about unique constraints or primary keys: they’re just unique indexes.  Now you’ve got extremely predictable inserts.  In fact, they always get inserted right at the end.  Now remember that SQL Server typically locks at a page level.  Now imagine twenty people trying to insert at once.

I learned about this the hard way.  My very first commercial application was written for Microsoft SQL Server 4.2 (and Microsoft Access, but that’s another story…).  You loaded a complex object into the UI, did some work and then it saved it into the database.  The performance was cracking.

Well, until we ran a training session and the trainer said “and now could everyone save their orders”.  It took half an hour.  Every time.  I had no idea what on earth was going on.  Nothing I did seemed to help.  The product went live and was usually okay, but every so often it ground to a halt.  Ironically, I was saved by force majeure: the client went bust (not as a consequence of my shoddy software, thankfully).  It was only a year later when I finally decided to educate myself about this RDBMS thingy I was using that it clicked what was going on.

So, trust me, you don’t want the clustered index on the identity field in an OLTP scenario.  Which is unfortunate, because that’s often the obvious place.  Let’s talk about less obvious places to put it.  A person’s name is often a good choice, especially since you probably do range-based searches on it.

There’s a small problem with this: often the name isn’t actually unique.  In fact, sometimes nothing is except for the identity column.  Even then, a clustered index on name followed by id will typically result in a better behaved database structure than an index just on id.

Let’s recap

Non-clustered indexes are added to improve select performance at a small cost to insert performance.  Clustered indexes, on the other hand, should be chosen on the basis of insert performance first.  Improving a couple of selects is nice, but specifying a good insert distribution is much more important.

If you can possibly manage it, what you really want to achieve is to have each thread inserting onto its own page.  This is easier said than done (but GUID Comb has potential).  Spread your inserts too randomly, and you end up hitting every page in your database.  Make them synchronize across threads, and you kill concurrency.

And if you’re not rebuilding you indices once a week, performance will eventually drop through the floor due to low fill factors.

SQL Server: Non-clustered Indexes

Okay, first off, there hasn’t been a post in, conservatively forever.  There have been a number of reasons for this: holidays, people visiting during the weekend (when I write this blog) and swine flu are probably the top three.  That and I managed to lose my post on Liskov, so I’m going to have to re-write.  But anyway, I thought that more than one person I know could do with reading a quick guide to SQL Server indexes.

Basics of SQL Server Performance

The first thing you need to know about is pages.  SQL Server puts rows onto pages.  If you access a row, the DB will load the entire page.  Whenever you’re talking about performance, 99% of the time you’re talking about how many pages get accessed.  Pretty much everything else, including processor time, is irrelevant.  Well, unless you decide to do something stupid like a user-defined function or a trigger.  But for straight DB access, pages are what it’s all about.

Non-clustered Indexes

Now, an index is basically a tree.  It’s a tree of pages.  The top level of the index is a page with rows.  Each row points to the page representing the next level of the index.  This works all the way down.  Finally, you get a link to the actual row itself.  This is your basic non-clustered index.

There’s a few things to note:

  • If you’ve got 5 columns in your table, but only two in your index, the index rows will only contain two index columns.
  • The rows in the index will be ordered, typically in ascending order.  (You can do it descending, but it’s rarely useful.)

This can speed up the following operations:

  • Filtering on the basis of columns in the index
  • Ordering using the exact ordering in the index
  • Selecting just the columns of the index.

The second one is highly unlikely to be used, the first is the typical usage, but the last is really rather interesting.  Let’s say that you’ve got two columns in your index, and your query only uses those two columns.  Then, since the index structure is pretty much identical to the structure of the table itself (rows on pages), it can actually query the last level of the non-clustered index and never actually hit the table at all.  If you’ve got some “lite” versions of tables in your database structure, now would be a good time to throw them away and just replace them with indexes.  This is called “index covering” and is a vastly under-used technique.

Insert Performance

Every index you add has to be maintained on every insert and update.  This, obviously, adds to the cost of entering data into the system.  In practice, most systems I encounter could easily handle more non-clustered indexes, since the alternative is dreadful select performance.  However, keep an eye on it and measure it.

Technorati Tags: ,,

Abstract Classes Versus Interfaces

Probably the most C# common interview question in London is “What’s the difference between an abstract class and an interface?”.  Let’s be clear: if you use the word contract in your answer, you’re not getting a job if I’m asking the question.  Contracts are a concept that doesn’t directly correspond to any code construct in C#, abstract classes and interfaces are your fundamental building blocks of well written code.

Here’s the one word answer:  Code.  Abstract classes can have code, interfaces can’t.  C#, like Java, doesn’t allow you to pull code from two sources, so you can only inherit from one abstract class.  Equally, the very presence of code tends to form a template for inheritors, which can be good or bad depending on context.

Fragility

Most people think of abstract classes as producing more fragile solutions than interfaces, simply because more decisions are made up front.  That’s true in the case of a parameter that’s an abstract class, but actually the opposite is true when you choose to inherit from an interface.

Here’s the problem: what happens when add a method to the interface?  As Erich Gamma discusses here, every implementation breaks.  That’s not so bad if every class that implements the interface is actually loaded into Visual Studio: then you can just fix them.  On the other hand, if you’ve not got your entire code-base loaded or, worse, you’re writing a framework, you’ve got broken code on your hands.

If everyone inherits from an abstract, the new method can be added to the abstract class without breaking any inheritors.  Now you know why Microsoft are so fond of abstract classes.

The Third Way

The thing with abstraction is, you can to some extent have your cake and eat it too.  Just because you create an IGraph interface doesn’t mean you can’t also create a PureBaseGraph abstract class with no implementation of any of the methods.  You’ve got the ultimate flexibility of the interface, but you can choose convenience and stability of an abstract class.  Microsoft don’t favour this approach, because they know that when they change an interface they’ll be deluged with complaints from developers who don’t want to ever change their code.  NHibernate and Castle Windsor, on the other hand, do, as Oren outlines here.  Using EmptyInterceptor avoids being exposed to changes in the interface, but you can run with scissors if you really want.

So, do I get the job?

SOLID Principles: Types of Abstraction

When I first try to demonstrate the power of abstraction to developers, often they get confused.  Partly this is because they’re unused to thinking in these terms, but partly it’s because there’s so many different types.  Ultimately, it’s a case of tools for the job: you pull out a hammer when you’ve got a nail, a screwdriver when you’ve got a screw.  The problem is:  they can all be combined together in useful ways.  There’s no such thing as a hammer than you twist, but abstract classes and interfaces can be used together in the one solution.

Parameterization

Everyone understands parameterization.  If you’ve got a routine that writes to a file, the routine is more general if it takes the destination filename as a parameter than if it hard-codes it in.  What not everyone does is take it far enough: we’ve already talked out parameterizing dependencies (aka dependency injection), but even for primitive types, there’s more parameterization that can be done.  A classic case of this is the class that reads a string from a config file.  Just passing the string in as a parameter is more general and more flexible.

Inheritance and Abstract Classes

Abstract classes allow for generality with the re-use of code.  Unless you make absolutely every method virtual (which, typically, you should) they’re not as general as interfaces.  The single inheritance restriction somewhat limits their usefulness as well.

Interfaces

Operationally, interfaces are almost exactly like abstract classes with no code and every method declared virtual.  However, one class can implement multiple interfaces, which we’ll see later helps us support the Interface Segregation Principle.

Dynamic Types

Dynamic types aren’t in C# yet, but will be soon.  Here, you can call any method, but it’s resolved (or fails to resolve) at runtime.  That’s equivalent to having your own custom interface you don’t need to declare.  It might well be worth using code contracts to actually check that your dynamic object behaves the way you think it does.

Any old VB programmer knows this concept already: it’s late binding.  He’s probably also quite wary of it.  The average python or ruby programmer knows it already and is a lot more comfortable with it.  Us C# programmers are going to have a lot to learn from them over the next few years.

Generics

Generics are the most powerful tool in the C# armoury, and due to become more powerful with C#4.  Here, you’ve got the benefits of abstraction, but you can specialize later.  So, your original base class can require a TWebRequest, which is declared to be a type that inherits from WebRequest, but you can inherit from this and then restrict TWebRequest to be an HttpWebRequest.

Generics in C# were created to support Nullable<T> and Collection<T>, but they’re much, much, more powerful than that.  Any parameter can be made generic, even if it’s an interface already.

The major problem with generics right now is the type system is cussed.  For instance, IEnumerable<int> can’t be case to IEnumerable<object>, despite the fact that this would cause no problems.  On the other hand, List<int> will never be castable to List<object>, because that would imply that you could add a float to a List<int>.

If there’s a lesson to be learned here, it’s that you still need to think about abstraction when actually instantiating a generic.  A list of an interface type is still more general than a list of abstract type.  A list of abstract type is still more general than a list of a concrete type.

Delegates

In my experience, people are quite uncomfortable with delegate abstraction.  Coming from a maths background, the idea of parameterizing one function with another is second nature.  A functional programmer won’t show many problems with the concept either.

However, there’s actually a very easy way to think of it.  Imagine you had an interface that had exactly one method and passed in the interface instead.  It behaves exactly the same.

There’s one other problem with delegates as dependencies: Castle Windsor doesn’t really inject them naturally.

Technorati Tags: ,

SOLID Principles: D is for Dependency Inversion

When we looked at the Open / Closed principle, we saw that certain practices produced fragile code.

  • Static Methods
  • Non-virtual methods
  • Creating objects
  • Too-specific variable declarations
  • Hard-coded values
  • Using the wrong object (the Law of Demeter)

Of these, the first three are all things you can’t override.  If you can’t override things, they’re inflexible and, inevitably, will cause problems.  In the cases we’ve seen, the Law of Demeter problem could be solved just by using the right object in the first place.  Equally, a non-virtual method is easy to fix, you just make it virtual.  You might be thinking “but that line of reasoning would make every method virtual” and you’d be right.  Private methods are pretty much the only case in which you don’t need this: because you can’t change a private method anyway.

Making Dependencies Explicit

Just for a second, let’s go back to the example of the code that printed some lines to the console.  For the code to run, it needed two things: the lines themselves, and the console object.  If we’d had some formatting rules, we could have obtained them from some instance variables.  If we were writing to a file, we’d have need the StreamWriter object we created.  These are all examples of direct dependencies:

  • Static methods (and by extension, singletons)
  • Objects we create
  • Method Parameters
  • Instance variables

Now, to go all Animal Farm on you for a second, two of these are good and two of these are bad.  Static methods and objects we create can’t be changed, so they’re bad.  Method parameters are easy to change: just change what you pass into the function.  Instance variables are typically set either by the constructor, a property set or another method call.  In each case, it comes down to a parameter you can change, so it’s good.  Obviously, static methods and object creation has to happen somewhere, but there’s ways around that.  You can wrap static methods with an object.  You can then pass the wrapping object as a parameter.  You can do the same thing with object creation.  Then, of course, you’re using an abstract factory.  You’ll have noticed that the discussion of SOLID principles is heading towards the same territory as the discussion of GoF design patterns.  This is no accident, but I’ll cover that in more detail later on.

By doing this, we see something really interesting.  All of a sudden, everything we depend on in an object is being passed in to the object.  If we return to my naive interpretation of OOD, it’s completely the other way around.  There, if a an object/actor needed another actor, he just got it, created it, whatever you like.  Now, my object is always being told what to do.  The actor is finally actually reading his lines.

It gets even better: hard coded values are dependencies as well.  Again, the same solution presents itself: pass it in.  Most people get the value of this when they start building tests for it, but it’s not about testing, it’s about flexibility.  You can filter and buffer function calls by introducing decorators, you can change your real time data feed to a batch CSV import without altering any code.

Using Abstractions

We’ve already touched on how making variable declarations too specific can cause problems.  In general terms, you want to declare variables with the most general type you can.  In the file reading example, the correct parameter declaration for the input was IEnumerable<string>, rather than string array or “ILineProvider”.  Abstraction is at the heart of the SOLID principles.  If you declare something as IEnumerable<string>, more people can use your code easily than string array or “ILineProvider”.  Another way of thinking about it is that you’ve made as few decisions as you can and still get work done.  This directly analogous to the Agile principle of the Last Responsible Moment.

There are challenges associated with abstract code.  The first is to get your own head round it.  If you’re a mathematician, this is a lot easier: you’ve got years of training in it.  The second is team acceptance.  Because abstract code is harder to immediately grasp, it’s often derided as “unreadable”.  In fact, well written abstract code can actually be significantly more readable than concrete code.  If you think about sorting, would you rather have to implement a sorting algorithm every time you needed to sort something, or use a well-defined abstract algorithm and simply tell it how you wanted the comparison to be done?  If you think about LINQ’s OrderBy method, there’s actually two layers of abstraction:

  • It takes the fields you specify and turns them into a Comparison delegate.
  • It applies a sort algorithm to the list using the Comparison delegate.

Depend on Abstractions, not Concretions

I’ve split dependency inversion into two parts: the injection of dependencies and the abstraction of dependencies.  Although both are of use separately, it’s when we bring it together that it really starts to pay off.  Using dependency injection without abstraction gives you some flexibility (e.g. the ability to read from a different file) but often not as much as you’d get from adding abstraction (e.g. the ability to read from a URL as well).  Abstraction without dependency injection is, in many ways, worse, because you often get the illusion of flexibility without the benefits.  You’re still performing wiring by soldering the lamp into the power socket.  The fact that the power socket could power a toaster isn’t much use: the lamp can’t be pulled out without damage.

Understanding the power of abstraction and how to use it is key to all serious development.  There are many things that don’t benefit: administration scripting (when you’ve got no re-use cases), project planning, end-user testing, work prioritisation… but if you want to be a better coder, you’ve got to learn abstraction.

Coding Without Resharper

Davy Brion asked if his readers could go back to not using Resharper.  Sadly, I don’t have to imagine this.  I deal with this on a regular basis.

You see, although my firm has enough Resharper licences to go around, many developers just plain don’t like it.  The objection is simple: it slows up the dev environment.  This isn’t an idle objection either: the slowdown is real.  I think we’ll probably have to wait for VS2010’s new extension model to see a proper fix for this.

However, personally I think the performance cost is incredibly worth it, because it saves my cycles even if it doesn’t save the processor’s cycles.  Little things that I use all the time:

  • Generate a field from a constructor parameter.  (Alt-Enter Enter)
  • Generate a property from a field.  (Alt-Enter Enter)
  • Automatically add a new interface method to an implementation.  (Alt-Enter Enter)
  • Find Usages (Shift-F12)
  • Find current file in solution explorer (Alt-Shift-L)
  • Implement Interface (Alt-Enter Enter)
  • Generate Method Stub (Alt-Enter Enter)
  • Add parameter to function when you changed a call to it.  (You guessed it: Alt-Enter Enter)

That’s without mentioning the “Automatically Add Namespace” feature.  (Alt-Enter Enter or just click on the tool-tip.)  This single feature probably saves a good five to ten minutes when dealing with an unfamiliar code base.  Just try grabbing most of the code samples from blogs and getting them to compile without this feature.

Before Resharper, one of my big secrets as a developer was that I could remember a lot of the mechanical edits I needed to make to effect a change.  Now, I spend more of my time thinking about what my code actually does, rather than how to wire it up correctly.

So, what’s it like without Resharper?  In a word, mechanical.  Code just gets stuck together slower.  You find yourself constantly writing bottom up code to help out intellisense.  Until you can’t remember what namespace a type is in.  At which point you spend your time guessing and googling something that would take would have taken under a second to correct with R#.

Now, if only they could fix that really annoying hang when you first delete a file…

Technorati Tags:

Thinking Again About the Decorator Pattern

Speaking to a colleague about the Decorator pattern, I think I was unduly harsh on decorators the last time I wrote on the subject.  I’ll start off by re-iterating my opinion that writing pass-through methods is for the most part a horrible waste of time and a code smell to boot.  However, there are some cases where proxy/decorator functionality is useful where there are relatively few methods you need to proxy.  Ironically, one of these is my very first post.  It employs the decorator pattern to give you a class that executes Retlang Commands, but allows you to halt processing at a time of your choosing.  This kind of buffering is generally useful, you can do things like process a message based on the following message this way (and if you know enough about Bloomberg feeds, you’ll know why this isn’t an academic example).

Some other examples of where the decorator pattern can come in handy:

  • Currency Conversion: here the converted amount can be a decorator on the underlying value.
  • A read-through cache: here the read-through functionality is added as a decorator on the underlying value.
  • Parameter interception: mostly useful for testing, you log the parameters and then call through to an underlying implementation.  (I actually used to have a Rhino Mocks capture constraint that was a decorator around a proper constraint.)

A good rule of thumb for using the decorator pattern:

  • You have an underlying behaviour that you wish to leverage.  In the case of the haltable executor, I wanted to allow any underlying executor.
  • You want to change one particular aspect of the underlying behaviour.  Again, in the case of the haltable executor, I wanted to allow for halting.
  • There are very few methods that need delegating.

Decorator vs Composite

The problem with decorator is that you’re constantly in danger of making a Law of Demeter violation.  You’ve got to ask yourself “do I really need the underlying object, or is it just convenient?”  Let’s take the example of the Rhino Mocks capture constraint.  In practice, I didn’t really have any underlying behaviour I wished to leverage.  I just wanted to deal with the fact that you can only have one constraint per parameter.  Problem is, we’ve already got a pattern for dealing with that situation: composite.  A proxy or decorator needs exactly one target. 

Now imagine you can a constraint that evaluated both constraints (it’s not hard, it actually exists:  Rhino.Mocks.Constraints.And).  Now you can have the capture constraint just always return true.  Your constraint now becomes “the underlying constraint” and “the capture constraint”.

Decorator vs Chain of Responsibility

Some have argued that Chain of Responsibility, one of my personal favourite patterns, should be replaced wholesale with Decorator.  I seriously disagree with this.  First, let me point out that the version I used in the previous post on the subject isn’t actually the classic gang of four pattern.  The original is a linked list, hence the “Chain” terminology.  The interface I gave has rules that don’t need to know about other rules.  This gives you a bit more flexibility in constructing different rule chains.  Providing the rules don’t need to share information (which will usually cause problems of their own) linked-list behaviour or using a decorator is just a Law of Demeter violation.

Does Anyone Out There Understand The Microsoft Public License?

Seriously, I’ve raised the subject of this before, but it’s getting to be a bit of a joke.  Take a look at this recent discussion on the castle list.  Whereas the Free Software Foundation will tell anyone who cares to listen (and frankly, many who’d rather not) the minutiae of compliance with the various versions of the GPL, Microsoft can’t or won’t answer a straight question about what they regard as being compliant with a license they themselves drafted.  Rather laughably, they then point amateur open source projects at lawyers.  Lawyers who are going to tell them “well, it depends, there’s no case law on the subject”.

Believe me, I would love to see a good answer to this question, but as it is it’s hard to recommend the use of this licence to anyone.  I think people who do choose to use it are going to be receiving a lot of requests for dual licensing.

Technorati Tags:

SOLID Principles: O is for Open / Closed

Any tour of SOLID should start with the Open/Closed principle.  The Open/Closed principle is actually different from the others.  All of the others are development practices.  OCP is a philosophical goal.  Here’s the classic statement:

Objects should be open for extension but closed for modification.

A great phrase, but meaningless unless you’ve had it explained to you.  Now, the SOLID principles are all about improving project velocity.  What the Open/Closed Principle actually says is: you don’t want to be editing code to change its behaviour.  You should be changing a class to fix a bug, not to make it do something else.  Now, when this was originally formulated, TDD was in its infancy and changing code was regarded as being inherently fragile.  We’ve mitigated that with TDD, but actually it turns out that the same principles enable testing: you shouldn’t have a separate code path for testing.

Let’s take a look at some examples of code that fail the Open / Closed test.

public void PrintLines(string[] lines) {
    foreach (string line in lines) {
        Console.WriteLine(line);
    }
}

Okay, let’s think about how we’ve violated the open closed principle.  First off, we’ve got a great big ugly static method.  I’ve talked a fair bit about these already.  Let’s talk about possible scenarios that could come up:

  • What happened if you wanted to write to a file?  You’d have to change the code.
  • What happened if you wanted to disable writing to anywhere?  Because the function isn’t virtual, you’d have to change the code.
  • What happened if the lines were streaming from a database?  Passing them in as an array isn’t ideal so you’d have to change the code.

Let’s look at another example:

public void PrintLines(string[] lines) {
    using (var writer = new StreamWriter(@"c:x.txt")) {
        foreach (string line in lines) {
            writer.WriteLine(line);
        }
    }
}

Now, obviously many of the objections to the last code are valid again, but this one’s got some more to worry about:

  • You can’t change the filename.
  • Even assuming you only ever wanted to write to a file, you can’t choose to buffer the file.

Finally, consider this code:

public void PrintLines(ILineProvider lineProvider) {
    using (var writer = new StreamWriter(@"c:x.txt")) {
        foreach (string line in lineProvider.Lines) {
            writer.WriteLine(line);
        }
    }
}

This has an interface in it, so it must be better, right?  Sadly, it isn’t.  This code is actually less flexible than the previous example.  Now you’ve got to implement ILineProvider just to use it, not just any old array of strings.  This is what is known as the Law of Demeter.  The Law of Demeter isn’t explicitly mentioned in the SOLID principles, but it should be.  Maybe it could be SOLIDD…

Danger Points

Just these two examples have given us some talking points that highlight points at which you’re likely to violate the Open/Closed principle:

  • Static Methods
  • Non-virtual methods
  • Creating objects
  • Too-specific variable declarations
  • Hard-coded values
  • Using the wrong object (the Law of Demeter)

If there’s a summary to all of this, it is this: be careful what you depend upon.  Next, I’ll talk about how we actually go about achieving this.

Technorati Tags: ,

Everything I Learned About Object Oriented Design Was Wrong

For all the kerfuffle about maintainability recently, it’s worth noting that actually the principal participants agree much more about best practices than they disagree.  The SOLID principles underpin pretty much every major open source .NET project I’ve examined.  (There’s a selector bias here, but I’m not going to worry about it.)  They are, in my opinion, much more important than the design patterns I’ve been talking about.  Sadly, they’re not half as well known as the Gang of Four book.  They should be, because they can be summarized as follows:  you need to change the way you develop.

Now, people are always saying this, and they’re usually wrong.  AOP, Workflow, there’s any number of new development ideas that have fallen by the wayside.  In practice, this one won’t, mostly because actually the ideas are quite old.  They’re just not widely understood.

When I was at University, I had to deliver a project in Turbo Pascal.  I think the Maths Department must have been allergic to curly braces.  Like a good little geek, I opened the user guide and started reading.  Now, most technical documentation is completely unreadable, but this was different.  It was, in fact, one of the single best bits of technical documentation I’ve ever read.  It introduced a whole new concept to Turbo Pascal: object-oriented development.  C++ had been around for a while, but the concepts were entirely new to me; programming for me was pretty much defined by Kernighan and Ritchie, as it was to most of the people I knew.

This new OOP concept was a revelation: it was, finally, a logical way of organizing your code built right into the language.  All you had to do was identify your objects, which behaved like actors in a play.  The actors would play their parts, and the program would come about as a combination of the actors.

Unfortunately, this was dead wrong.

Objects aren’t actors, a single business concept doesn’t necessarily correspond to one object.  This will lead you directly to the creation of god objects.  It turns out that the development of code isn’t principally about modelling.  It’s about flexibility, dependencies and coupling, and only then about modelling.  Ironically, this approach leads to better models in the long term, simply since the model will track changes in requirements faster.

What is “good” code?

I think I’ve probably seen more fruitless arguments about this than any other subject.  Everyone thinks their code is good, and sometimes they’re right.  Good code definitely isn’t the same thing as useful code, which is an error a lot of developers make.  Good code isn’t about aesthetics or huge architectures either.  Here’s the only definition of good code worth having:  good code is code you can easily change.  There are many formerly popular technologies (CORBA particularly springs to mind) that failed that one test.  The SOLID principles are guidelines designed to make your code easy to change.

So, I’ve decided to write a York Notes guide to SOLID.  My principal sources are Uncle Bob’s own website, and the excellent Hanselminutes podcasts on the subject.  One of the things you’ll probably notice as you go through is that your code tends to get longer:

  • There’s more interfaces
  • There’s more small classes
  • There’s more constructor parameters
  • There’s more instance variables

I really, really advise getting ReSharper, it turns doing this from what feels like an extremely bureaucratic endeavour to a case of pressing “Alt-Enter, Enter” a lot.  One day I hope I’ll be able to see this stuff baked into the language.

Technorati Tags: