Great timing - I had spent quite a few days with meditating on this question lately, and I am working on a framework to support my approach, so forgive me venting this here.
First, a bit of eastern-like statement: If the question is right, the answer feels natural - when the answer is foggy, perhaps we should ask a better question. I offer the following "better question": why we create business logic? Can we classify logic layers?
1: Execute the planned actions (control equipment, modify data, etc.), this is "Process";
2: Protect the system from malfunction or corrupt data, ensure a coherent state, this is "Consistency";
3: Help the user do her/his tasks in a comfortable environment, provide all information to make the right decisions quickly, this is "Ergonomy".
To me, this classification makes the answer quite obvious.
Process is in the core, it uses all the sensitive resources (databases, hardware, etc.) directly following the actual commands with the given data. The data must be clean and error-free at this point, only system errors can occur in forms of technical problem reports (system availability, low level DB exceptions) that requires the attention of the support team immediately, and should give an "internal error under investigation, come back later" message to the end user.
In a heterogeneous environment, this is the backend, server, the center. In my framework, this is a fully configurable network of hardcore Java components.
Ergonomy is the other end. It is absolutely essential part of the system, but the support team does not care about its messages: it translates the notifications and actions of the other layers and reflect to changes (notification lists, field states and value sets, calculated value updates).
If at all possible, it should run on the client only, and use minimum amount of the valuable server resources. In my framework, this is written in JavaScript, so it can run in a browser or in a modern JRE for fat clients.
Consistency is in between. First, it MUST run on the server in the same synchronized transaction with the Process, to reliably protect the sensitive elements. It might use heavy-weight components and sensitive data that should never go down the line to the client. At the same time, some parts might run on the client side to save server resources and provide smooth client experience. Consequentially: this is also JavaScript, can partly go down and run at the client side to increase performance, but must completely run inside the Process transaction.
Of course, this is my ideal approach and is under construction, but so far looks good. My 2 cents.
B. D. "Beck" Beykpour
Lorand, I'm thinking of automation software that I've work on. I think you're model does fit here as well. I've often thought that consistency and safety had to be implemented at two levels. First, it should enforced at lower levels to ensure that nothing goes wrong. However, it often has to be reflected in the UI as well, whether disabling certain conflicting commands or informing the user about a possible conflict in their requests.
Beck, I have to admit that there's a catch here: this approach is less than 2% of that framework, and without the rest 98% it is merely a fairy tale...
With a simpler approach however, you can still make this work. You have to create "abstract smart widgets", a separate data layer, and a logic layer in between. In this environment
- the widgets are responsible for handling their own events and transfer them to data change commands and events for buttons
- they also "listen" to data changes, and that mean both their 1: actual value, 2: the value set for lists, combos or tables and trees and 3: decoration like tooltip, visibility, activeness, style
- logic can sit behind data and listen and react to the data change. Ergonomy works with the decoration, Consistency with the valuesets, availability and status report - Process is what you don't see at all
- and you need "light bounds" between them: access controls and data by string identifiers and should support following paths. ObjectiveC does a good job with it, in Java it's a pain.
Well, even this simpler approach takes a lot of time, for me about 1.5 years to run a public national administration system, ten years ago (but afaik it still runs and gives work for a hundred developers, I felt forced to leave after creating it) :-)
In practice smaller scale apps do not worth such amount of effort, but still good to keep this segmentation in mind. So again: sorry for venting.