I am currently designing the architecture for an multi-channel commerce system which will have multiple different frontend presentations which are tailored to device and channel (user type and location). The challenge I'm facing is how to best ensure we are developing the core commerce platform in a way that reduces duplication in the frontend presentation tiers.
Here is a sampling of the different frontend presentations tiers we will need to support:
- Traditional desktop based website for consumer
- Mobile optimized website for consumer
- Native mobile applications (iOS/Android) for consumer
- Customer Support Center website for customer support representatives
- Instore kiosk based website for consumers shopping in brick-mortar locations
- Other (microsites and other utilizing various technologies such as Angular, PHP, .NET, etc)
Now, I know the best practices around a layered architectures (presentation, business, data tiers) and common design patterns to address frontend challenges within a single app (such as MVC, validators, interceptors). However, none of these principles explain how and where to best encapsulate your presentation specific business logic when faced with supporting multiple frontends.
So, my question is what are some good practices and principles to follow when developing such a system to ensure each frontend application is not duplicating frontend business logic?
I have developed many applications with requirements like this in the past using different approaches...some of which worked fairly well and some which worked not so great. But each time I felt like I was inventing a solution for a common problem and that there must be some best practices and principles to leverage.
A Quick example of the specific challenges I am asking about
All of our frontend applications must support the ability to register a new customer account. The registration form will take in information such as email, password, and customer address information (street, city, zip, etc). When the form is submitted there will be certain trivial and non-trivial validations that need to occur before the account is created in the system and a verification email is sent to the user. For example:
- Email address pattern validation rules
- Ensuring the email address doesn't exist in the system
- Password complexity rules
- Address validation (via third party address validation/standardization system)
For the most part, these validations rules need to be enforced across all frontend systems, though each frontend's registration flow might be slightly different and might only contain a subset of the fields. So, what are some good practices to provide an API to the frontends such that each frontend does not duplicate the various steps required to properly validate and process the registration? For example, if we decide to change the password complexity rules or address validation rules, etc - how, might we best design the system such that we will not have to go out and change all the various frontend applications with this new validation logic.
Just to be clear, I'm not concerned about where to put core business logic which is shared across all frontends (i.e. account creation services, address validation services, account lookup services, etc). Those patterns are commonly discussed in blogs, books, and forums. My questions are specifically related to the business logic which is commonly tightly coupled to the presentation tier. Some questions that always come to my head.
- Should we provide a presentation service layer which supports all frontend operations including form validations and processing via web services? Or should each frontend owns it's presentation logic because "no two frontends are alike"?
- If we do create a presentation service layer, how do we provide services which address the subtle differences of each frontend? Do we provide different services/endpoints for each of these frontends or provide simply have different 'contexts' that each frontend passes when they invoke our services?
- Does this presentation service layer control the error messaging and return the appropriate contextually aware message to each frontend, or should we just pass back error codes and let the frontend own this?
- etc