2

This is an issue that I have struggled with in a number of systems but this one is a good example. It is to do with when one system consumes WCF services from another system, and each system has their own database, but there are relationships between the two databases.

We have a central database that holds a record of all documents in the company. This database includes Document and Folder tables and it mimicks a windows file structure. NHibernate takes care of data access, a domain layer handles logic (validating filenames/no identical filenames in the same folder etc.) and a service layer sits on that, with services named 'CreateDocument(bytes[])', 'RenameDocument(id, newName) ', 'SearchDocuments(filename, filesize, createdDate)' etc. These services are exposed with WCF.

An HR system consumes these services. The HR database has a separate database that has foreign keys to the Document database: it contains an HRDocument table that has a foreign key DocumentId, and then HR specific such as EmployeeId and ContractId.

Here are the problems amonst others:

1) In order to save a document, I have to call the WCF service to save it to the central db, return the ID and then save to the HRDocument table (along with the HR specific information). Because of the WCF call and all Document specific data access being done within the Document application, this can't be done all within one transaction, resulting in a possible loss of transaction integrity.

2) In order to search on say, employeeId and createdDate, I have to call the search service passing in the createdDate (Document database specific fields) and then search the HRDocument database on the Id's of the returned records to filter the results returned. This feels messy, slow and just wrong.

I could duplicate the NHibernate mapping files to the Document database in the DAL of the HR application. This means I could specify the relationship between HRDocument and Document. This means I could join the tables and search like that but would also mean I would have to duplicate domain logic and violate the DRY principle, and all that entails.

I can't help feeling I'm doing something wrong here and have missed something simple.

Paul T Davies
  • 2,527
  • 2
  • 22
  • 39
  • Do HR related documents always get entered / modified via the HR system or can they come in out-of-band and just get referenced later from the HR system? In other words does the HR system get to see all HR related changes to the document application? – Richard Blewett Jun 17 '11 at 15:31
  • There is currently no requirement for the HR system to be able to be able to reference a document that already exists in the Document system, only to create/view its own documents. But this is certainly something that could be specified at a later date, and so this requirement should be treated as something that may need factoring in in the future. – Paul T Davies Jun 17 '11 at 15:37

2 Answers2

2

I recommend you to apply CQRS and Event Driven Architecture principles here

    • Use Guids as primary keys - then you will be able to generate primary key for document and pass it to WCF
      method call.
    • Use messaging on other side of WCF service to prevent data loss (in case of database failure and
      something like that).
    • Remove constaints between databases - immediate consistent applications don't scale. Use eventual consistency paradigm instead.
  1. Introduce separate data storage for reads purpose that contains denormalized data. Then you will be able to do search very easy. To ensure consistency in your read storage (in case when Document creation failed) you could implement some simple workflow (saga in terms of CQRS)

xelibrion
  • 2,220
  • 1
  • 19
  • 24
  • The eventual consistency paradigm sounds interesting. As for 2, this is theoretically possible, but has consistency problems. If a record is changed in the Document system then the HR system would have to detect this and update - the Document system can't inform the HR system as it should not be aware of it (to avoid cyclic dependencies). Perhaps the HR should be set up as an observer? This is one of those issues where I'm sure I'm not the first to have had this problem, and surely there is a standard solution? – Paul T Davies Jun 19 '11 at 19:30
  • If a record is changed in the Document system - then Document system should publish DocumentChangedEvent. Denormalizer subscribes for this event and updates read storage in this case. If you have to do some logic in HR bounded context, then you'll have saga which subscribed to this event and produces commands to HR bounded context – xelibrion Jun 19 '11 at 19:40
  • Thanks, I've been reading up on this stuff and it sounds like something I should invest some time in, although it will be a big shift to my little synchronous world. :) – Paul T Davies Jun 20 '11 at 08:59
0

You can create a common codebase which will include base implementation of Document along with all the mappings, base Domain Model etc.

A Document Service and an HR System use the same codebase. But in HR System you extend base Document class (or classes) with your HRDocument using inheritance mapping strategy which will suit your needs the best.

public class HRDocument : Document 

And from HR System you don't even have to call Document Service anymore, you just use NH and enjoy ACID and all that. But Document Service is still there and there's no code duplication.

Kostassoid
  • 1,870
  • 2
  • 20
  • 29
  • If anything, HRDocument should contain a Document member, not inherit from it - composition over inheritance and all that. I don't understand how I could reproduce all the mappings and save the Document element from the HR system without duplicating code? Where would the Document specific business logic go? How would, for example, I ensure a filename does not contain invalid characters? – Paul T Davies Jun 19 '11 at 19:20
  • Hm, no matter, you can still use this by making a separate assembly (or assemblies) containing all Document domain model (including validation logic), data access etc and use (read "reference") them from HR System and Document Service. You don't have to implement your Domain Model in one project. The only issue with this scheme is that, in case you want to use a second level cache for your DAL, you'd have to use a distributed cache provider. – Kostassoid Jun 19 '11 at 19:37