LoB/ERP: You’re Doing it Wrong
Introduction: What is LOB/ERP?
As the pendulum swings toward Service-Oriented Architectures such as IoT and MicroServices, everybody needs to look at what they’re doing to keep up with the changes of the world. What is LoB Software? It means Line of Business, meaning anything it takes to get business done; From the User Interface to the Order Processing. It is frequently interchangeable with ERP. ERP is typically the internal portion of the business, such as HR, Inventory, Accounting, etc.
What ISN'T LoB/ERP Software? If you're building an Operating System, or an Audio/Graphics engine (For Movies or Video Games), or some other Low Level development, that is NOT LoB/ERP Software.
The code that ties it together, the User Interface, the Payment Processing, the Authentication, the Website or "Application", the whole "Backend", are all LoB or ERP.
LoB/ERP Should be Service-Oriented
There are three sides to programming. The Domain side should be Service-Oriented. But before we get into what Service-Oriented means, let’s define the three sides of the programming coin:
A: The “Domain”, also known as the “Server-Side” or the “Back-End.” This is where most of the heavy lifting and proprietary logic lives for software. You might think of terms such as Object-Oriented, Java, .NET, or PHP.
B: The “UI”, also known as the “Front-End” or the “Application.” This is the portion that is viewed or installed on a user’s machine which manages how they interact with the software. You might think of terms such as HTML, Angular, or WPF.
C: The “Persistence”, also known as the “Database” or the “Data-Layer.” This is the location and process by which information is (semi) permanently saved and retrieved. You might think of terms such as SQL, Oracle, ORM, or Entity Framework.
What’s the Point?
What’s the point of Service-Oriented Architectures? The main point is Server-Side Statelessness. That is, the complete removal of “state.” State being a snapshot of the position data is in at any moment. State should only exist in two places, the main place being Persistence. Keeping the state of data is literally the job of Persistence. The second place is the Front-End. A User-Interface is required to keep track of the current activity, view, and position that a user is interacting with information.
So why should the Domain be stateless? Because Scalability. Let’s talk about Scaling each of the three sides of the Programming Coin.
Scalability
First, UI Scalability. The UI Doesn’t scale. UI’s are viewed or installed Per-User. There are a few examples of multiple installations or multiple instances running at once, but those instances are not dependent on one another. If I have two instances of a Media Player open on my PC, the state of one does not depend on the state of the other. You can’t control the hardware on user’s machines.
Second, Persistence Scalability. Persistence doesn’t scale well. You can always throw more hardware (vertical scaling) at any machine you control. But horizontally, scaling is a nightmare. If you consider Horizontal Scaling to mean you partition different parts of data to live on different servers, that is not scaling. That is distributing the load. If you consider it to mean having multiple copies of the data on different servers, that is most likely Backups or Disaster-Recovery. Similarly, you have Clustering systems which is a combination of distributing load and duplicating data, such as Hadoop, which spend a huge amount of resources keeping data in sync, but for a noticeable speed payback. That is close to scaling.
Scaling really happens on Service Entry Points (Where Domains are Consumed). So, for example, if I run a Payment Service (such as PayPal), I probably have an Endpoint that developers can consume to interact with my Payment Domain. That Endpoint sends and receives a LOT of traffic. Too much to handle, actually. To fix that, each call to the endpoint is forwarded to a different machine. If there are only 100 calls per day, they are all forwarded to the same machine. If there are 100 calls per second, they are probably distributed to different machines so the hardware can handle it. That is true Horizontal Scaling. And Vertical Scaling means each machine might have more or less hardware power.
Horizontal Stateful Issues
The issue with Horizontal Scaling with Service Entry Points is that the code running on each machine doesn’t know the state of the code running on the sister machines. So if a UI sends a request which is distributed to Server 734, then Server 734 knows exactly what is going on. But if the UI then asks for additional information, and that request goes to Server 63… Server 63 has no clue what “Additional” means, since it doesn’t even know that Server 734 even exists, let alone previously processed a request.
Enter Stateless Domains. While the purpose of the Service Entry Points might be to distribute calls and route data to/from the Domain, they are nothing more than gateways. The only reason they might understand State is because they should be RESTful. REST stands for Representational State Transfer. That means the UI, who knows the state, Represents its state during the call. So instead of saying “Give me more info about that user we just talked about.” with the URL http://www.site.com/User/MoreInfo. The UI would instead call a RESTful endpoint that says, “Give me Page 2 of the info for User 89” with the URL http://www.site.com/User/89/2 because the RESTful endpoint asks for /ObjectType/ObjectID/InfoPageNumber.
Given those stateful variables, the Service Entry Points can pass along information to the Domain, who doesn’t care about state, and who can orchestrate the information as necessary. So, now that we have a Domain who is given Parameters, instead of controlling state, that Domain doesn’t care if multiple copies of it are running all over the world. It knows that if it receives a request, it can process that request independent of the rest of the world.
The Benefits of Statelessness
The first benefit of Stateless development was mentioned above. It allows you to Scale your services Horizontally, such that you can handle varying levels of consumption or traffic.
The second benefit of Stateless development is the Functional Programming Paradigm. That doesn’t mean you have to learn Haskell, F#, or the Map, Reduce, Filter mechanics. But it means you can program with Pure functions who require Parameters instead of State.
With Stateless, Pure, Functional-Programming, Unit-Testing (And Therefore TDD) becomes automagical. If you have ever written Unit Tests (especially in OO, ew), you know how much fun it can be to Mock out all of your dependencies, and all of their calls, and create fake returns from them as they intermingle through your tests. Well forget all of that. Forget Mocking altogether! When you Unit Test Pure Functions, you no longer need to mock*, you only need to test pure functionality.
When you go down the path of Stateless development, Pure Functions aren't only easier to Unit Test, they're easier to Refactor. That means they're easier to Read, which means they're easier to Maintain, and the dominos keep falling over with benefits. In the end, you can ask your developers to add a feature and not worry that some disperate system or report will explode.
What You’re Doing Wrong
Because many developers follow the Write-Bad-Code Principle, the Fragile-Code principle, and the Tight-Coupling principle, your first assumption is to go to the pros! Find a Recruitment Company or Software Company who says they know the best of the best. Then tell them you want the developer who REALLY Knows the BEST Practices for Object-Oriented Programming. Not some kid who barely knows OO.
Your problem there is; Object-Oriented Development is for Object-Oriented Architectures. These are Monolithic, stateful solutions, who have no business in our world of business. Object-Oriented is the act of combining State and Process, as defined by one of the greatest OO advocates, Martin Fowler. Many schools teach that Object-Oriented Development means using the three keys of OO; Inheritance, Polymorphism, and Encapsulation. But those pillars existed far before OO, and are not exclusive to OO. Long-Story Short, OO is a Stateful development Paradigm.
So why are you using Stateful Object-Oriented Development to attempt to build a Stateless Service-Oriented Architecture?
OO is Stateful, why are you OOing!?
Some Architects have unknowingly begun the transition from OO to Service-Oriented. They swear they aren't doing OO Statefully, but they still follow all of the stateful rules of OO. And because OO's rules are based on statefulness, even the Anti-Patterns are created to be Anti-Stateless. So these Architects are only half way there. They are essentially shooting themselves in the face by forcing OO rules into a stateless system.
Service-Oriented Architectures for IoT and MicroServices are best developed with a Stateless Paradigm. Service-Oriented Programming is a type of SOLID development making heavy use of the benefits of Functional Programming. But not all applications are IoT and MicroServices.
There are three types of applications, which closely align to the three sides of the Programming coin.
A. The System. This is where programming talks to the machine, typically assisted by the Operating System. This could mean reading and writing to/from Memory, as in a Database, or sending data to a GPU, as in Graphics processing. This is basic wrapper functionality for things such as SQL interaction and Web/Desktop UI’s. There is no business logic, and this is typically the easiest of development. This is design-heavy and might use some OO principles, though it doesn’t have to.
B. The Middle-Man. This is the vast majority of programming. This is the Domain we have been speaking of, and should certainly all be Service-Oriented. The Middle-Man Validates, Moves, and Transforms data between a consumer and Persistence**. This is where 100% of business logic and many proprietary algorithms come into play. This should all be Stateless.
C. The Machine IO. This is the real nitty gritty stuff. While Side A above (The System) might use some wrapper functions to perform basic machine operations, the real IO processing related to the user’s keyboard/mouse, and the user’s monitors gets very low level. This type of programming is the C (or similar) directly on the chips of the hardware for the BIOS, Card-Readers, and heavy GPU Processing. This is the code used to BUILD the Database Servers and Clients, as well as the OS itself. These must be the fastest and most efficient of algorithms, and is the most difficult and math-heavy of development. This is typically Procedural/Functional***.
Conclusion
In this world, OO is pretty much useless. If you are doing basic interaction with the OS or Machine, you are simply using Wrapper code or Markup. If you are doing very low level development, you are using a low level language. But the vast majority of development is done in the Domain, which should be Stateless.
* With Functional Programming, some parameters might be Delegate Functions. If that scenario exists, though it should be infrequent, you will need to mock a delegate function.
** “Persistence”, from the view of a Middle-Man or “Domain” could also mean another Middle-Man. Because Services can consume Services. But when consuming other Services, they are treated as just another type of persistence outside of the control of the current domain.
*** Some say Windows NT was made using “OO Design.” Though it was built using C, which does not include native support for OO Design. What C DOES support is the ability to create discriminated unions and follow patterns which had originally set the groundwork for the current definition of OO. C, using “OO Design”, was a very SOLID pure way of development, and not what we currently define as “OO” today.