Search code examples
c#design-patternsdomain-driven-designoffice-interop

How to design a domain model related to confidential documents management?


I am working on a desktop application that deals (among others) with applying read / write permissions to confidential documents (MS Word).

For a document, multiple permissions can be defined. For example:

  • user X can read the document D1 between start_date and end_date
  • user Y can read and edit the document D1 any time

Also, the set of permissions for a document should be retrievable in order to be presented on the user interface.

Furthermore, the document can be signed (with a certificate) by the current user of the application (the author of the documents).

Recently (after having some behaviour-less domain objects and some business / application services), I have come up with the following:

interface IConfidentialDocument {
    void AddPermission(Permissions permission);
    BunchOfPermissions Permissions { get; } // all defined permissions
    void Sign(User currentUser);
    ... other operations (like ShareToUsers, SendViaEmail)
    string Path { get; }
}

class Permission {
    User User { get; private set; }
    PermissionType Type { get; private set; } // Read, Write, Full etc.
    ... other members (for time bounds etc.)
}

The problem is that the IConfidentialDocument has to be implemented using the Word Interop library. I could not figure a nice way to wrap the Word Interop functionality and hide its corrupt design under a simpler model, as the one presented above.

I was thinking of implementing IConfidentialDocument as a WordDocument that delegates the work to a Microsoft.Office.Interop.Word.Document. The latter would be passed in the constructor of the WordDocument. This one would be created by a ConfidentialDocumentFactory.Create(string path). The concrete factory would depend on Microsoft.Office.Interop.Word.Application and so on...

  • Is there a DDD-friendly way to deal with such a domain?
  • (How) should I define an anti-corruption layer over / against Word Interop?
  • Should I make the domain anaemic and define services like DocumentsSigningService, PermissionsApplyingService instead? - actually, this is what I currently have - it works, but...
  • Should I use double dispatch perhaps?
    • document.SignVia(signingService)
    • document.ApplyPermissionsVia(permissionsService, bunchOfPermissions)

The business is actually slightly more complex. It also involves sending documents to their permitted users (via email) etc. What I've done until now is relying on a set of business services and application services to perform most of the logic - the ConfidentialDocument thus being quite behaviour-less. But, as I have said, I am searching for a better design.

Any idea is welcome :)

Thank you!

Some references (not enough reputation to add the links):

  • How not to inject services in entities (thinkbeforecoding)
  • A better domain events pattern (lostechies)

Solution

  • The question is too much general, and I don't understand why WordDocument : IConfidentialDocument is bad. It can be allocated in the separate module and considered to be an adapter.

    Ok, I'll try to express my thoughts.

    With respect to DDD you should make your own model clear as possible.

    MS Word uses its own model containing notions such as User, Permission and Document. So it is necessary to make model translations between your entities and ones presented by MS. There are some points of interest that should be considered.

    Model translation

    • What relations exist between your model and MS Word model? For example, if someone modifies permissions of MS Word directly (bypassing your app), can your app always properly react to this changes? And vice-versa. So, at first I would determine relations between models and infer some restrictions.

    • Does your app supports any other document types/vendors (OpenOffice)? You can analyze details depending on concrete document vendors and separate it from your own model.

    Document model

    • Should you always load "real document" in memory when creating your app document object? I consider, no. Hence, proxy fits good.

    • Are there some basic document fields or states which are common for all documents regardless to physical document type? If yes, than basic abstract class "PhysicalDocumentState" as a field of document object will fit that good.

    I propose something like this:

    Model

    I use words like "Service", "State", "Facade" for referencing to corresponding patterns.

    Probably, you need not to implement WordDocument, WordPermission, but:

    • it can be usefull as it makes WordFacadeService simpler
    • it makes full isolation of WordState from MSOfficeInterop and focus first on domain operations
    • when creating Document type, WordState is initialized by WordFacadeService, and hence it can realize different document initialization logic (e.g. lazy loading)

    The only problem now is in determintaion of simple and transparent interface of WordFacadeService and in separating of restriction control responsibilities between WordState and WordFacadeService.

    Finally, I have no idea why you should use Anemic Domain Model in described case.

    I will be glad if it helped.