Hey Microsoft, Our Databases Aren’t Services!

29 commentsWritten on January 17th, 2010 by
Categories: Architecture, Opinions, WCF

Something that frequently bothers me is when people/companies create services that are basically thin layers on top of their database.  The service contracts expose the typical CRUD operations for each table, and add some additional methods for specific queries etc.  These kind of services will sometimes pretend to contain a bit of ‘business logic’ but they are essentially just a remote interface into your database with maybe a bit of extra security on top of it.  They effectively turn your database into a remote service.  Now if you’re anything like me, you’re probably thinking “why on earth would people do that?”

There are probably a few answers to that question, but one reason that can’t really be disputed is that a lot of the tooling that Microsoft offers to developers simply encourage this kind of stuff.  Let’s go over a little example.

I wanted to see what some of Microsoft’s recommended tools would create for me if i wanted to create a Silverlight application which uses a database.  Obviously, a Silverlight application can’t use a database directly so the application will need to communicate with a service.  The service obviously does have access to the database.  RIA Services is a solution that Microsoft seems to be pushing a lot for this specific scenario so i figured i’d give this a shot.

I created a RIA Services Class Library project in my solution and tried to add a ‘Domain Service Class’ (as the RIA Services templates call it) to the project.  If you already have a DataContext or an ObjectContext defined within the same assembly, you can immediately select the database tables that you want to expose.   So i canceled the dialog and quickly added an ADO.NET Entity Data Model to the solution for which i selected my Chinook database.  I tried to create a ‘Domain Service Class’ again and got the following window:

create_service

Well, now that sure is easy isn’t it? I can immediately select all my ‘Entities’ and i can even check whether i want to be able to edit them through the service, and apparently i can also generate associated classes for metadata (which would be useful for validation according to the tooltip).  I checked the Album table, and left the ‘Enable editing’ option unchecked.  This created a service with the following code:

    // Implements application logic using the ChinookEntities context.

    // TODO: Add your application logic to these methods or in additional methods.

    // TODO: Wire up authentication (Windows/ASP.NET Forms) and uncomment the following to disable anonymous access

    // Also consider adding roles to restrict access as appropriate.

    // [RequiresAuthentication]

    [EnableClientAccess()]

    public class AlbumService : LinqToEntitiesDomainService<ChinookEntities>

    {

 

        // TODO: Consider

        // 1. Adding parameters to this method and constraining returned results, and/or

        // 2. Adding query methods taking different parameters.

        public IQueryable<Album> GetAlbum()

        {

            return this.ObjectContext.Album;

        }

    }

 

I don’t know about you, but i love those TODO statements.  After all, you really do might want to consider constraining the resultset that could be returned by the GetAlbum method.   Who knows, perhaps you have certain use cases where you don’t want all of the ‘entities’ in the Album table to be returned by your ‘domain service’.  Hopefully, this service will be used by developers who are smart enough to realize that they should modify this method, instead of using client-side LINQ statements to filter the returned Album ‘entities’ as i’m sure we’ve all seen in too many Microsoft demo’s already.

It gets better if you recreate the service and check the ‘Enable editing’ option.  Now you’re ‘domain service’ will also contain the following methods:

        public void InsertAlbum(Album album)

        {

            this.ObjectContext.AddToAlbum(album);

        }

 

        public void UpdateAlbum(Album currentAlbum)

        {

            if ((currentAlbum.EntityState == EntityState.Detached))

            {

                this.ObjectContext.AttachAsModified(currentAlbum, this.ChangeSet.GetOriginal(currentAlbum));

            }

        }

 

        public void DeleteAlbum(Album album)

        {

            if ((album.EntityState == EntityState.Detached))

            {

                this.ObjectContext.Attach(album);

            }

            this.ObjectContext.DeleteObject(album);

        }

 

Man, this sure is easy, isn’t it? I now have a service that offers me full CRUD access to the Album table in my database.  If i wanted to, i could now start implementing a screen in my Silverlight application which allows my users to list the albums, edit them, delete them, create new ones, etc… and i wouldn’t even have to change anything in my ‘service layer’.   The problem is that too many developers actually will do exactly that.   After all, why should they doubt any code that was generated by a tool which comes from Microsoft?  If the tool can generate this, then certainly some people actually want you to use it like this, no?  If not, why would it even generate code like this?

I’m sure this kind of stuff gets a lot of ooh’s and aah’s during the product demo’s at Microsoft events, but other than that, what good does this really bring?  Is this really the way you want people to develop their services?  Do you really want developers to pretty much expose the database as-is to remote clients?  And those TODO statements simply won’t cut it, you know that all too well.  I simply don’t think there’s any good reason to generate code like this because a lot of people will simply take it as is and use it like that directly from their client code.  Oh sure, most of them will hook up the authentication but i’m willing to bet that very few people will actually put real business logic in there.  Why would they?  The message that a lot of people will get from the resulting code is that a service is merely a way to provide CRUD for your database tables.  What’s business logic to these people?  Right, the stuff they’ll implement in their presentation layer because this service doesn’t really encourage people to consider implementing it there.

The only benefit that i can see from using RIA services is that you don’t really have to deal with your service contracts, and your operation contracts or any of that stuff.   No, we won’t be doing any of that.  We simply use a [EnableClientAccess] attribute and we’re done!  I don’t really consider that a benefit, though i can certainly understand why people would not want to deal with the pain of classic WCF services.  RIA Services is simply a solution to the wrong problem.

I haven’t looked at ADO.NET Data Services (which will be renamed to WCF Data Services in .NET 4.0) yet, but i suppose it’ll be more of the same: something that makes it incredibly easy to create services directly on top of your database data.

Seriously though: who on earth actually wants that?

I have no doubt that there are some people out there that are using RIA Services in a responsible manner and are sticking by responsible architectural guidelines.  I also have no doubt that those people are ignoring most of the tooling that is offered by Microsoft around it.  So really, why not get rid of this kind of tooling, and spend the effort that normally goes into those tools (or anything else which encourages bad practices for that matter) on providing actual guidance to the developers of your platform?  The last thing we need are more developers who think that this is ‘ok’, or projects that have been delivered based on this kind of ‘architecture’, or customers that are turned off by .NET projects because “they all have maintenance problems”. 

  • Jeffrey Palermo

    Microsoft has a history of creating tools which are easy to use. I agree with you about the architecture principles, and I advocate dodging the out-of-the box architecture in favor of better maintainability. The Microsoft platform is widely adopted because it is easy to get started. It is actually a good business decision. Once customers become more educated they will eschew the default coupling conventions and put better design in their apps. Before that, at least they are able to get some software. When the alternative is no software, the microsoft tooling is welcome assistence.

  • Koen

    Gill Cleeren talked about the WCF data services at the SQL Server day. It’s basically the same, only REST based, but you can access it through LINQ on the client side, so no big difference. There’s a bunch of things it can’t do (WHERE id IN (1,2) => two queries) and a lot of things it won’t do as good (can’t optimize your queries).

    One of the pro’s he mentioned is that you now don’t need to write methods like FindAllSortedByName or FindFilteredByName on the server-side (implemented with LINQ to entity framework). Sadly the man didn’t notice that he had now the exact same methods on the client side (implemented with LINQ to WCF data services) while his full database was now exposed as a service…

  • http://http//blog.yoot.be Steve Degosserie

    Nice post Davy, I have the same fears as you do concerning the latest evolutions of tools like RIA Services (http://blog.yoot.be/index.php/2010/01/08/2010-predictions-galore). But as Jeffrey mention it, there’s no wrong in willing to simplify & automate simple application scenarios for which you don’t always wanna have to go through a full-blown architecture.
    And well … it’s always possible to misuse a tool, I’m sure many developers have trouble with e.g. NHibernate ;-)
    So, I would say that as consultants / software developers, it is our duty to have alternatives in the tools we are using and to know precisely what are the benefits & drawbacks of each, but most importantly, to be very transparent about it with our customers.
    Indeed, in the end it is most often a business decision to decide whether to develop an application that will be long-lived and therefore most probably requires a good architecture, or a short-lived one for which the maintenance aspect is less important and the use of tools that accelerate the development process is acceptable.

  • http://davybrion.com Davy Brion

    @Jeffrey and Steve

    it’s too bad they’re never up-front about it though… you’ll often hear them tout these things as the best thing since sliced bread and how it’ll reduce your development time dramatically. If they want to be treated fairly about it, they in turn should be fair about the many downsides that come with using these things.

    @Koen

    well, i can’t say that i’m suprised about that :)

  • Fizz

    This cookie cutter code leads to laziness, the worst example I have seen is from a senior developer and was something like this client side.
    this.ObjectContext.AddToParent(parent);
    foreach(Child child in parent.Children)
    {
    this.ObjectContext.AddToChild(child);
    }
    When asked about
    1. The lack of transaction integrity
    2. Performance issues with multiple round trips
    The reply was “Its easier if you ignore that”

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #519

  • Jack

    Can you give an example of what the exposed business objects may look like for the Chinook database? In my experience they are often extremely similar. Lets say you want a Silverlight personal music database. How radical a departure from the db entities would you need? Where would most of the BO logic be ‘spent’? Thanks, Jack

  • http://davybrion.com Davy Brion

    @Jack

    i generally wouldn’t expose business objects at all… if it’s purely a silverlight client which enables you to manage your personal music database, then yeah, the objects you send over the wire (i’d go for DTO’s) would indeed be pretty much identical to those of the album/track/artist/playlist tables and there would hardly be any business logic to speak of.

    however, once you create something for the invoicing part of the chinook db, the situation changes… i wouldn’t really be happy with my silverlight client knowing about how the invoices are stored in the database or what kind of business rules or general logic applies to the actual creation/handling of invoices. The silverlight client needs to be able to show data (using DTO’s), and send commands to the server (like ‘add X number of this product to that order’) and the business logic behind the service layer should try to handle it, or fail if some business rule is broken.

    generally speaking, your presentation layer (whether it’s silverlight, wpf, winforms, asp.net or whatever) needs to be as dumb as possible. The more it ‘knows’, the more trouble you’ll end up with sooner or later.

  • Wayne Bloss

    Microsoft generates the code as a starting point for you.

    I didn’t see an example of the kind of code that you think would be better.

  • http://davybrion.com Davy Brion

    @Wayne

    personally, i don’t want any generated code at all… i want something that allows me to deal with cross-cutting concerns in as few places as possible, something that doesn’t advocate sending your business enitities to clients, something that doesn’t encourage you to expose your database (or parts of it) and something that does not automatically lead to a maintenance nightmare once you need more than straightforward CRUD functionality.

  • James Hicks

    I could see using RIA Services or WCF data services for exposing a persistent view model (think CQRS where the client is a silverlight app). Many developers follow Microsoft’s guidance without question because that is what they have been taught for years. Its unfortunate Microsoft does not have an understanding of maintainable architecture.

  • Rc

    What would be the best way/pattern to go about exposing data from a db. Should all business objects be modeled out? Say, for example, an outside vendor exposed it’s database and internally we wanted to consume that data in ETL. Since internally, we’re not allowed to create a dblink to the outside db, and we only have home grown etl tools, would it be advisable to expose the data metrics that we wanted as a service and use it as a data service layer?

    I’ve been going back and forth on the best way to do this. Either model out the business objects then put another interface layer on top of that, or just create classes/types for the metrics we want and call get methods with the sql on those to return the data we want.

  • http://davybrion.com Davy Brion

    @Rc

    if the data service layer would only be used to import the data into your system, then i guess there’s no problem with that. anything else that consumes that data through another service that you do have control over, i’d hide the actual db schema from them and provide the data in a form that is the most optimal for the specific client(s)

  • http://csharpmagazine.blogspot.com/ Nima

    I’ve not worked with RIA but what I can see from your blog is that these services aren’t domain services at all. These are more like Repositories to me and maybe one can use them to have some data access services in place so other real domain services can use them :)

  • http://erichauser.net Eric Hauser

    Davy,

    I initially had the same opinion about a WCF Data Services. However, I eventually realized that what it really does is provide a standard REST interface to any IQueryable. It just so happens that out of the box most of the examples are using the Entity Framework as the IQueryable implementation. It is similar to how people think that LINQ is just a tool for ORM.

    Data Services also has reflection based provider that you could use to expose your domain model (not your database) as services. I am currently writing a custom provider (using the 1.5 update) that allows us to load metadata on the fly and generate different web services depending on customer customizations. There are certainly limitations to the model.

  • Bruce

    A lot of developers may use WCF RIA Services unwisely. On the other hand I think that a lot of developers will use WCF RIA Services wisely.

    The good thing about WCF RIA Services is that it provides a place (your domain services classes) for you to add business logic that is separate from your presentation layer, and it provides a great deal of flexibility for you to structure your business interface and logic however you want.

    Therefore I see no reason why you can’t define a sound architecture using WCF RIA Services, and implement it productively.

  • http://jack-fx.com Jack

    database is a better place to place some configuration of services, and it is easy to access and maintain. Of course, you must install them before.

  • Ben

    You’ve entirely missed the point of at least one major feature of RIA Services — using LINQ against IQueryable on the client side is not the same as classic (i.e. bad) client-side filtering. Instead, the client-composed query expression is sent back to the server, and only the filtered results are returned. For example, if I write (on the client):

    var albums = domainContext.GetAlbum().Select(a => a.Name == "Back in Black" && a.ReleaseYear == 1980);
    var loadOperation = domainContext.Load(albums);

    The albums returned (asynchronously) in the operation are only those that match the criteria specified in LINQ. So, RTFM.

    While I’m at it, griping about how a technology might allow lesser developers to shoot themselves in the foot is the height of arrogance. What exactly is your concern–that a bunch of newbs are going to write a huge system using poor methodology and with no oversight, and that somehow, somewhere, a long-suffering senior developer–or worse, society–will be forced to deal with the consequences? Please. There’s good software, and there’s bad software. If you find yourself working on a lot of the latter, maybe it’s time to ask whose fault that really is.

  • Ben

    And to fizz: your senior developer would not have been making one roundtrip per change unless he was calling ObjectContext.SubmitChanges after every addition — and given that’s an asynchronous method, I seriously doubt that was the case.

    If I can’t be sure that you made the whole scenario up, I’m at least certain that you’re blind to the simple fact that changes are batched in the context until that method is called.

    Study up, junior.

  • http://davybrion.com Davy Brion

    @Ben

    “There’s good software, and there’s bad software. If you find yourself working on a lot of the latter, maybe it’s time to ask whose fault that really is.”

    i’m pretty lucky in that i hardly ever have to deal with bad software so by following your logic, i could conclude that i must be doing something right in my decisions and choices

    and you are indeed right: there is good and bad software, but that doesn’t mean we shouldn’t try to do better. We’d all end up as frustrated as you appear to be.

  • Ben

    You’re fooling yourself if you think readers of this blog won’t see your response for the cop-out it is.

    I notice you haven’t corrected the misrepresentations in your post.

  • http://davybrion.com Davy Brion

    @Ben

    Indeed i haven’t, because i haven’t verified your statement yet. I really don’t have a problem with me being wrong about that, but the other problems that i believe are inherent with using RIA Services are still there… if you really wanna make this discussion interesting, perhaps you want to talk about those? Or is a service layer all about querying for you?

    As for my previous statement being a cop-out, that’s the kind of response you get with the attitude that you display. You talk about arrogance in my point of view, but your second comment was just filled with it. You can’t really expect anyone to talk to you seriously if that is how you present yourself…

  • kilfour

    @Ben :
    ‘the height of arrogance’ : Well, that would be me…
    But atleast I’m polite…
    The fact that something happens client side, server side, or even in a parallel universe does not interest me. It’s a performance (/implementation) issue which I as a dev should not be aware of, until it turns out to be a problem.

    The fact that some ‘Prime Directives’ (read up on your PARC history) are violated when it comes down to encapsulation worries me far more.

    “There’s good software, and there’s bad software. If you find yourself working on a lot of the latter, maybe it’s time to ask whose fault that really is.”

    It’s probably partly your fault, if you consider this kind of development good practice.
    It just falls to pieces ‘in the wild’ and then there’s other people that have to clean up the mess.

  • Ben

    @Kilfour: More of the same. How does RIA Services violate your ideals any more than, let’s say, C# itself? To say that a technology makes it too easy to do something wrong is like saying “food makes it too easy to become fat”. Nobody forces you to use RIA Services in a way that breaks your precious directives.

    By the way, please explain exactly how something done so poorly in the first place would become so widely used that other people would have to “clean up the mess”, as you put it. Are you tired of cleaning up other people’s messy code, or is this some general humanitarian concern? You must have hated the 20th century, when we actually used pointers and all that really dangerous stuff. (I suppose that should have been kept top-secret, too.)

    @Davy: A database-backed service layer is not all about querying, but it is very much about querying, and RIA Services makes that part of it–the part that otherwise requires much tedious boilerplate code–a cinch. Nowhere does it state this is the only way to do things.

    Don’t get all stuffy about my poor attitude: your post, rich with snit and cynicism, practically invites it. I came here looking for useful information about RIA Services, and if I hadn’t known any better before I read your post, afterwards I’d have thought it was a turd. I mean, really: what modern services layer technology set would facilitate something so odious as client-side filtering? Guess what, buddy: every one of those Microsoft demos you laughed at was demonstrating exactly the opposite of what you assumed.

    So, yes: in my mind, it is exceptionally arrogant for anyone to spend fifteen minutes poking through some Visual Studio wizards, immediately form a wrong opinion, and rush to WordPress to crow about it to the world. If that’s not deserving of mild censure, I’m not sure what is.

  • http://davybrion.com Davy Brion

    @Ben

    seriously, go waste someone else’s time… i already said i have no problem with being wrong about the filtering, the other stuff however, still holds and you continue to ignore it while you keep focusing on one sentence. it certainly makes your last paragraph all the more ironic.

  • Drammy

    Hi,

    I am all fairly new to this and am actually glad that Ben posted his comments – its always good to hear two viewpoints when trying to learn.

    @Davy. That being said your post is interesting and I’d like to learn more about your way of providing access to the database. Do you have any links/resources you could post here to help me learn?

  • http://davybrion.com Davy Brion
  • Haipeng Jiang

    Hope it’s ok to post my Q twich ;) help!

    Could anyone please advise me on this design of a data integration solution:

    We’re doing a data integration project between a MS Sql Server database and a Microsoft CRM system (through its web services).

    We’re trying to build a “service” layer on top of the database. The design of our current solution is to use web services for CRUD, with xml being the format of data.

    Views are created to consolidate related tables into one entity, and we query these views, using the “SELECT * FROM someview ” + “For XML” to generated xml that will be returned from our web services.

    For update we’re trying to use the same approach – using SQL XML to map updates views, we have “instead of” triggers defined on top of these views, and in these “instead of” triggers we update the underlying tables.

    The views/triggers are generated by tools so don’t be too concerned with coding efficiency here…

    what do you think if we use WCF data Provider to publish a enterprise data model (essentially DTOs) ? p.s., we don’t have a BL layer for now, it’s all in the stored procedures!!!

    What’s your opinion on this / any better design? much appreciated!

  • Pingback: Learning Silverlight #3 – Getting Started « Danny-T.co.uk home of Dan Thomas, Moov2 Ltd