0

We are in the design phase of setting up an internal enterprise API layer for our company. We are hoping to realize an API that can serve our internal apps as well as our external clients. Our environment is MS heavy, IIS, ASP.NET MVC apps, etc.

We have an existing service layer that was not designed well, so we are trying to do it right this time.

This question indicated a project breakdown for larger ServiceStack projects that is no longer present in the main documentation. Primarily the inclusion of a separate "Logic" project. We are trying to align this with a lot of what Martin Fowler outlines in Patterns of Enterprise Application Architecture.

Here is what we are considering:

    ○ Service.Host (single)
        § Dumb Host
        § Assigned multiple Service Interfaces on startup (subsystems)

    ○ Service.Interfaces (many projects)
        § Subsystems of Business (e.g. Ordering, Customers, etc)
        § Data Access Layer with Repository pattern
        § Service Layer endpoints
            □ Application endpoints (returns data/dtos for views/screens)
            □ Vendor Endpoints (Feeds, hierarchies, etc; authentication/authorization)

    ○ Service.Models (single)
        § DTOs for all systems (namespaced appropriately?)
        § Shared and distributed to vendors/client apps
        § No dependencies

    ○ Service.Logic
        § Rich Domain Layer
            □ Objects that model our business
            □ Rules/algorithms for business logic

    ○ Service.Tests

Fowler and other suggest that DTOs and Business Logic should be independent of each other, with Assembly/Factory classes that convert between.

First question: Where do the assemblers live? In the Service Interfaces project? In their own project? Are they necessary for every conversion?

Secondly: Does the client need to convert back to Domain Objects, or does the client just use DTOs to populate screens and send data back to the service? We only want clients dependent on the Service Models class, right?

Thirdly: How do we design the DTOs? Previously, they were pocos that represent one resource (trying to be restful, OrderDTO, CustomerDTO, etc). In practice the data required is complex. We initially thought the clients request whatever they need individually and piece it back together. Fowler indicates that we want to minimize requests to the service, and have dtos that are almost aggregates of the business objects, to try and send it all down at once. So if I have an order and a want the customer tied to it, should I send down a CustomerOrderDTO with everything populated? Or do I send down an order object, and force the client to make another request for the order?

Fourth: Where is it appropriate to use actual C# interfaces? Do we have one for every repository to make them switchable and testable? One for every service interface?

Fifth: Is there no choice but to map at every layer? i.e. SQL to Data layer using ORM. Data Layer to Domain Layer using AutoMapper or ServiceStack mapper. Domain layer to DTO. DTO to ViewModel. ViewModel to Javascript model (e.g. Knockout) It seems like a lot of repetition and boilerplate. Is there a better way?

I'm trying not to make this subjective - but there are very little guidelines for some of the details here - our assumption is there are best practices or intentions that we are missing in the ServiceStack framework to account for these things. Thanks in advance for answering any of these questions.

Community
  • 1
  • 1
IronicMuffin
  • 4,182
  • 12
  • 47
  • 90

1 Answers1

4

This contains too many broad questions to be able to answer in any depth, Questions should not have multiple disjointed questions covering different topics, you should split this up into multiple focused questions so it's clear what the question is and the answer that it's expecting.

I'd first recommend going through the Designing APIs section in ServiceStack's documentation which walks through designing APIs with ServiceStack.

Pay special attention to Software complexity, goals of Services and important role of DTOs as it covers a lot of what you should the thinking about when creating Services. E.g. If you use a code-first POCO Micro ORM like OrmLite you can re-use the Data Models in your DTOs, ViewModels, Caching Providers, etc. But when you need to you can use ServiceStack's built-in AutoMapping to easily map between models <-> DTOs. Either way try to avoid having multiple artificial layers and different models in each layer which is a large source of unnecessary friction.

It also highlights that you should be looking to reduce any unnecessary layers/patterns/etc when possible as each time you add a layer you're adding artificial friction so make sure every Layer you add serves a purpose and you can see the value they each add. E.g. I'd recommend against having multiple fine-grained repositories, I'll generally have a repository to cover an entire sub-system of related functionality and would highly recommend against mechanically creating fine-grained repositories based on some arbitrary rule that's not related to your domain, e.g. per Table.

You only need C# interfaces if you have multiple implementations or want to write tests mocking them.

ServiceStack encourages coarse-grained Message-based Services so instead of client-specific fine-grained RPC Services, try to design generic, reusable, batchful Services that minimize forcing clients to perform multiple, dependent I/O Services and send data clients need in a single Service response when it's cohesive to that request.

ServiceStack's Physical Project Structure is already implemented in most of ServiceStackVS VS.NET Templates so I'd recommend starting a new project using the most appropriate ServiceStackVS template. E.g. {Project}.ServiceInterface holds the Service Implementation whereas {Project}.ServiceModel holds the DTO's in a impl-free Project so the types can be reused.

By just maintaining DTOs in a separate ServiceModel project, it eliminates the friction for clients which can reuse the Typed DTOs with any ServiceStack C#/.NET Client to enable an end-to-end Typed API without effort.

Instead of sharing your ServiceModel project, clients can also use ServiceStack's Add ServiceStack Reference feature to import all Types for a remote Service which it can use with the C# Clients to enable a Typed API. To see how and why this works live checkout Add ServiceStack Reference on Gistlyn which lets you call any remote ServiceStack Service from a browser.

Community
  • 1
  • 1
mythz
  • 141,670
  • 29
  • 246
  • 390
  • 2
    thank you for the thorough response. I understand I'm asking a lot of different things here. I think the most important thing we are trying to wrap our heads around is where do we implement our business logic. You removed the "Logic" project from the example I linked to, and the nuget templates do not have that. Our business (Supermarket) I would say is rather complex, and we want to manage the business logic appropriately. – IronicMuffin Aug 17 '16 at 19:31
  • 4
    @IronicMuffin It doesn't include it since most small/medium projects don't need it. The only project that would be split is the **ServiceInterface** project to [modularize your Services implementation across multiple projects](https://github.com/ServiceStack/ServiceStack/wiki/Modularizing-services). If you're going to create multiple projects my recommendation is to scope each project so it's cohesive, modularized + isolated so devs working on functionality in one project don't need to know about impl in other projects i.e. reducing complexity/cognitive overhead being goal of modularization – mythz Aug 17 '16 at 19:37
  • Follow up to that, since you're replying - if we split out the ServiceInterface, we would still dump all relevant DTOs into the single ServiceModel project? – IronicMuffin Aug 17 '16 at 19:44
  • 2
    @IronicMuffin Yes, you should only maintain a single **ServiceModel** project per Service Boundary which just contains the DTO Types (not behavior or impl). The only time you'd have multiple **ServiceModel** projects is if you had multiple Micro Services in which case each Micro Service would have their own **ServiceModel** project. – mythz Aug 17 '16 at 19:47
  • 1
    Thank you - I will try and distill the key pain points above into more appropriate questions for SO. – IronicMuffin Aug 17 '16 at 19:48