If you wrote a class that had more than one responsibility, chances are that your colleagues would be pouncing on it in your next code review, eagerly pointing out what a terrible programmer you are because you’ve broken the single responsibility principle. So if single responsibility is great for classes, why do we so happily accept apps and services that have more than one responsibility?
Yes, I know the obvious retort is that noone’s going to buy an app that only does one thing. What use is a word processor that doesn’t read documents AND save documents AND spell check, and that’s already three responsibilities before you even start wanting to change fonts to make your headings stand out and then change colours because little Angela (aged 9) positively refuses to write anything if she can’t make all the text bright pink first.
So for my question to make sense, we need to be a bit more careful about what we mean by a responsibility. The responsibility of a word processor for example is to let you edit documents – and that word ‘edit’ clearly encompasses orders of magnitude more functionality than you’d put in a C# class. In well architected code, a class would have what you might call a single ‘micro-responsibility’ (convert a paragraph to XML perhaps, or represent a hyperlink). A traditional app on the other hand has a number of ‘macro-responsibilities’ (eg. let the user edit a document).
Let’s look at Microsoft Word in more detail. Sure, it lets you edit documents. But it does more than that: It represents documents internally and also lets you persist them. For example, save them to a file system. In fact, you could argue that there are three distinct layers of responsibility:
In fact, these layers should be familiar to you. They are just a specific example of the traditional 3-tier application.
So now, I can rephrase my original question: Why in the case of Word do these three layers form one single monolithic app? Why aren’t they exposed as separate services?
Before we go on, I should clarify that in this article I’m using the word ‘service’ to simply mean that something exposes a documented public API so it’s callable by other apps. That API might be a COM layer or it might mean it’s a .NET assembly, both of which can be called in-process. So please don’t start thinking Windows services or SOAP or other things that would obviously be silly for Microsoft Word.
You’re probably also dying to remind me that in fact, Word does have some ability to interface other apps: Parts of the Word object model are exposed via a COM API; however if you try to use this COM layer you’ll quickly discover it actually brings up the user interface too: There isn’t really a clean public separation between the UI and the underlying document. Separately from this, Microsoft has also based the Word .docxfile format is based on an open XML standard – this lets you read the files programmatically without using Word at al
l.That’s a great feature but neither this nor Word’s COM API changes the fact that Word is fundamentally monolithic: There’s no separation of responsibilities in the way Microsoft Word is packaged.
Now let’s look at SQL Server. And now you’re going to go ‘Ha!’ Because you’re going to tell me that SQL Server is already componentized. After all, the UI is a separate app, SQL Server Management Studio, and then you have SQL Server itself, which consists of not one but a bunch of backend services that provide – well – the backend. And you know what. I’m going to go ‘Ha!’ right back at you because those backend services are tightly integrated with each other and between them they probably have almost as many responsibilities as Barack Obama does.
For a start, you’ve got all the failover clustering stuff: A whole bunch of technologies like Log Shipping and Always on Availability Groups, all designed take your database and keep it in sync with copies of the database on other machines. Now think: Is there any reason why that data-copying stuff should be only useful for a SQL relational database? Of course there isn’t! If you are running a no-SQL database, you might still want to keep multiple copies in sync. If you want another example chances are your workplace has a big Active Directory installation which at this very minute is being synchronized between various domain controllers. Then there’s all that amazing code that you write, which you then feed into some source control, the very purpose of which is to make sure changes you make to your codebase are synchronized to other people’s machines (admittedly, in this case, on demand, not in real time).
You get the idea? Lots of things in the world need to be synchronized across computers: Wouldn’t it be great if you had an app that could provide that service to any other app (subject, presumably to the client apps exposing some API to indicate what updates have been made to their underlying data store). Synchronization is a great example of a single macro-responsibility and therefore in an ideal world, ought to be available as an independent service, rather than being yet another of the gazillion responsibilities that SQL Server takes on.
Another example: SQL Server also has full text search. Same question: Is there any reason in principle why full text search should be tied exclusively to a relational SQL Server database? No, of course there isn’t. I bet you have thousands of Word documents in your organization that you might want to do a full text search against. That’s another macro-responsibility.
I think I’ve made my point for SQL Server. Let’s target Visual Studio now… That does a lot of things: Let’s you edit code, it compiles code, it manages all the files in a project, publishes websites, and so on. We’re all happy to buy all those things in a single as a package because mostly, we do want to do a lot of those things together. However, each of those things is also a distinct responsibility that you may want to use individually. For example, continuous integration involves building projects, but not editing them. And interestingly, Microsoft do seem to have realized it could be good to expose at least one responsibility separately: The Roslyn Project
is intended to expose the compiler and the information the compiler has about your code programmatically. In effect, it turns the compiler into a separate service. It’s a brilliant idea. But it’s being developed, apparently as a very complex project, essentially as an add-on to Visual Studio’s feature set. I’m gonna bet that if Visual Studio had been designed from the start as a set of independent services, then Roslyn would be almost there by default. And of course if Visual Studio had been designed as a set of independent services, then the UI would have been more pluggable and much of the controversy
over the new VS2012 metro look which I discussed two weeks ago
would have been more easily avoided.
The point I’m making in all these cases is this: If the packaged application was written as a set of independent services (and remember how I’m using the term services), each reflecting one macro-responsibility, and each one exposing a publically documented API so it can be called independently, then customers would benefit from being able to use the software in many more different ways.
Now at this point you’re probably thinking I want the moon on a stick. I plead guilty. Yes, I do realize that re-architecting existing software is a big task. It’s easy for me to suggest that SQL Server services ought not to be tied to the SQL Server database, but of course actually separating them out that would probably take quite a few man-centuries of work, and it’s not going to happen. That’s the problem you always have with code. There’s all this historical legacy which means your code can’t ever be as perfect as you want. But I’m an idealist. And as an idealist, I say, just imagine how great the world would be if apps were usually written with their multiple responsibilities completely separated! It’s not really a new idea either. It’s just taking good service oriented architecture to its logical conclusion.
And while I’m dreaming: If you’re reading this and you work at Microsoft – think of the achievement for your career if you can persuade your bosses to start releasing software this way in the future. It would be a massive step forward in software plug-ability. Indeed, in the history of Microsoft, it could be as significant as Windows 8. With the added bonus of actually being useful.
And if you’re reading this, don’t work for Microsoft, and you’re about to start a brand new greenfield project…
Next week: The Windows 8 Start Screen: Is it So Evil?