0

Our project is in its early stages and we are currently using Uncle Bob's Clean Architecture (also known as the Onion Architecture).

An overview of our project is as follows:

  • domain package

    1. Contains our business entities
  • usecases package

    1. Contains operators that use our domain entities to perform use cases
    2. Contains repository interfaces for entities that need to interact with an unspecified database
  • interfaces package

    1. Contains handlers for triggering the correct usecases operators and use cases
    2. Implements our usecases repository interfaces (tailored to LDAP)
    3. Contains a database interface for performing database operations (using LDAP)
  • infrastructure package

    1. Implements our interfaces database interface (using LDAP)

Our business entities are pure data structures whose only business logic is being linked to each other via UUIDs.

While the above approach decouples us from any database technology and lets us test our code independently of our database, any change in LDAP (such as adding/renaming/deleting fields) requires code changes to be made before they can be used.

Because LDAP is basically a map of maps (you can think of it as a HashMap<String, HashMap<String, Object>>), our project manager recently got the idea of taking a "stateless" approach where our application only needs to keep track of what field names client apps are using and the corresponding field names in LDAP.

His proposed solution aims to avoid having to change lots of code in our project and only need to work with a configuration file that keeps track of said name pairs.

e.g. Proposed JSON Configuration File Format (using a Map of Maps)

{
    "entity1Fields": {
        "uiFieldName1": "ldapFieldName1",
        "uiFieldName2": "ldapFieldName2",
        "uiFieldName3": "ldapFieldName3"
    },
    "entity2Fields": {
        "uiFieldName1": "ldapFieldName1",
        "uiFieldName2": "ldapFieldName2"            
    }
}    

Our questions are:

  1. Are there any possible development/testing issues with this approach?

  2. Can a "stateless" approach remove the need for pure data structure domain entities, or will completely relying on the configuration file cause development/testing complexities, especially when working with said entities and their fields?

  3. Can the Clean/Onion Architecture be done with a "stateless" approach?

  4. Is there a better way to implement a "stateless" approach?

  5. Is taking a "stateless" approach (even when just working with pure data structures) generally a bad idea?

Any advice would be greatly appreciated.

  • I've never tried that approach, so it's all but impossible to tell you if that's a good idea or not. But I will give you some sound advice: make sure that you can theoretically rebuild the previous model from the new. This guarantees that you're not losing data in your new approach and prevents irreversible mistakes should you decide later that it wasn't the right approach. – Neil Feb 6 at 7:42
0

Welcome to Ontological Mapping

this will bite hard

First the bad news, the data your clients have in their LDAP may not map nicely with the way your application requires it.

Fair enough some concepts like username are pretty simple and standard, but can your application handle kanji? Not going international, fine can your application tolerate a hyphen, a dot, or a digit in the username? Someone out there will have a system where this is fine.

Okay lets say that you have very permissive concepts that are fine with just about any string. What if the customer serves that data in their LDAP as a composite field? a good example might be email addresses concatenated together with a semi-colon. Hopefully most admins have learnt not to do this, but still there will be cases.

At the other extreme what if several LDAP fields have to be composed to satisfy your applications concept? Email again is a good example, perhaps they don't distribute an email field but expect username + "@" + domain name?

Okay, lets cut this to the bone. You don't support fancy data compositions, the data must be presented as is required by your application. This is about the only time you can get away with a simple 1-to-1 mapping. Unfortunately support is going to be difficult as each LDAP tree is going to have wildly different names. There will need to be a process to translate the trees to allow investigations on something familiar, and conversely to translate fixes back for the customer.

Now obviously you have a single concept, but the fields on that concept might be mapped to paths that are numerous or non-existant. So how are you going to handle missing, and multi-valued fields?

Alternately, still cutting the configurability to the bone, it would be far simpler to declare a single key which serves as the top level property under which your proprietary key set lives. This additionally simplifies support from your perspective as LDAP graph serialisations can be directly compared (beneath that key), also the multi-valued issues vanish were they aren't essential. The downside is that organisation will likely have to duplicate data which brings with it consistency concerns - as admins forget to update both keys.

In Practice

Unfortunately you will not know how much each of these scenarios will be beneficial or havoc inducing until your code hits the wild. If you've already got a few deployments out there great, you've already got some idea of how these concepts are being mapped. Take those current mapping structures and support them without constraining which property they work with.

First Stab

Generalise these mapping methods slowly and with care. While it is tempting to make everything general and push it all out into configuration. Remember that the configuration is code, in a novel programming language, and it is being compiled/interpreted/executed by your application. You will need to develop every diagnostic tool yourself for your new programming language. So keep it simple.

Testing

Keeping the stateless mapping code separated from LDAP objects. At least then you can Mock out the LDAP data structure during your tests for mapping. Also place a separation between the mapping code and the main application, that way you can completely mock out LDAP integration/mapping during testing. Any Integration/End-2-End testing will be somewhat more complex unless you have full control over your own test environments LDAP server, perhaps the ability to aim it at a non-standard port or tie it directly to a non-default server?

Domain

It is always in your best interest to separate your domain objects from peripheral objects - That is the whole point of Onion architecture.

  • First you cannot control the shape of third-party objects
  • If a third-party object is core to your code, it means that updating that library could break most of your domain logic - that is a good recipe for becoming locked into a specific technology or becoming locked into unsupported code.
  • it drastically reduces modularity and testing scope.
  • transitive dependencies - just don't. Down this path lies cyclic dependencies.

Is it Good?

That depends on your other options.

  • It might be the best option - then it is good.
  • If its not your best option don't just do it,
    • mapping ontologies is hard,
    • and supporting a sufficiently complicated language to map them is hard.

Its doable but weigh up the options here.

  • It might be painful, but explicitly supporting mappings in code ensures a developer/ba/test/other conversations occur, that stops all sorts of issues.
  • Perhaps modularising the configurations into plug and play variants, this allows some scope for customisation while still ensuring strong performance, good tooling, and conversations.
  • Is there a way to avoid LDAP entirely for complex data? Could it be instead passed in via a standard config file? Whatever must be accessed via LDAP, can it be minimised? This will make any "stateless" mapping solution easier.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.