I have my own very strong opinion on where to put business logic, but it isn’t any of the above. It’s this: It depends. Depends on your organization, your application, and even, sometimes, the particular business rule. Yes, it can be hard to maintain business rules scattered throughout various application tiers, but it’s worth it, because each tier has its own strengths and weaknesses.
Business Logic in the Database
Take the EIS tier, AKA the database. The DB developers are right–this is the absolute most secure and robust layer at which to put your business logic. If true disaster would result if a rule were broken even once–even by a developer with a SQL prompt who had spent a bit too much time at the aforementioned bar the night before–this is really your only option. And it’s the only option that’s really and truly 100% guaranteed to be enforced in every single application that changes data, with no additional work on the developer’s end.
There’s another very good reason to put some business rules in the database: They use a *lot* of data. I’m not talking about a rule requiring a SQL query that returns 100 rows, even if it’s from a million-row table. I’m talking about a rule that, say, will perform updates on each of a million (or even 100,000) rows. You do not want to instantiate one million entity beans (or, for you ADF-ers out there, one million entity object instances) and make changes through them. You want to have the database handle that; crunching huge amounts of data is what the database is for.
On the other hand, if none of these factors is critical to you, putting business logic in the database has some real disadvantages. First, there’s the issue of interactivity and JDBC hits. It’s not that a single JDBC hit is that expensive, but they do tend to add up, especially when you need one every single time you want to give feedback on user input, which in a rich UI situation is really quite often. Of course, if you have the sort of traditional form where an attempt is made to post data to the DB every time the user submits, this isn’t nearly as much of an issue.
Secondly, if a user violates a validation rule that’s being enforced by a DB trigger, what the application sees is a SQLException. And the message in a SQLException is not fit for public consumption. For one thing, it generally refers to database objects and columns. This is not information that will be useful to your customers, and it is the sort of information that might be useful to individuals of technical skill and questionable character. For another, even if a specific attribute caused the problem, a SQLException is unlikely to contain the sort of information that you could use to create, say, a FacesMessage bound to a particular control–so no nice link in the message box, and no nice red X beside the particular value that the user needs to fix.
There are ways to get around that–in fact, I’ll talk about them in next week’s entry–but they’re annoying; they require a fair bit of parsing and plumbing. Business logic placed in the middle tier allows you to more easily create exceptions that integrate well with JSF messages. In fact, if you’re using validation rules in ADF BC or the ADF Model, the framework will manage this process by itself.
Business Logic in the Middle Tier
Which brings us to the middle tier, or, as Jave EE developers call it, “the application.” That’s really relevant: If you or most of your team consists of ace Java developers, who might know basic SQL but aren’t database experts, your productivity, and the quality of your applications, is going to plummet if you try to pack most of your business logic into the DB. Conversely, if you’re on a team of database wizards with one good Java developer, things will be a lot easier for you if you set that one developer doing error message integration and have everybody else writing triggers. That’s an important consideration, but it isn’t the only one.
As said above, working with large reams of data in the middle tier isn’t a very good idea. And no code you deploy on your application server is going to keep a single mistake at a SQL prompt from corrupting your data. Moreover, reuse of business logic between applications isn’t automatic if the logic is enforced by the application, rather than the database. You’ll have to make sure you structure business logic in such a way that it’s easy to reuse between applications, and then you have to make sure each application does reuse it.
That means keeping your code properly factored, moving reusable code up in the class hierarchy or out into object members. For people using ADF BC in particular, this means:
- Making liberal use of the “Business Components Base Classes” page of JDeveloper’s Project Settings dialog, and the “Class Extends” button on the Java page of most business component editors, so that you can factor common code into custom framework classes.
- Maintaining a single project of frequently used entity object definitions and associations, and importing those entity object definitions and associations into other projects, rather than recreating them. To be honest, this is kind of an annoying process now; the Business Components Library functionality in 11g will help matters here immensely.
- Creating, sharing, and using validation domains where appropriate.
- Creating, sharing, and using custom validation rules where appropriate.
All of these options are mentioned, but sort of pushed to the side or into “Advanced Topics” in the ADF documentation and developer’s guide, and to tell the truth, I’ve given them pretty short shrift in my earlier books (I’m hoping that Oracle JDeveloper Fusion Development – A Handbook for 4GL Developers will fix this problem). Don’t let that treatment fool you; these are topics that, at the very least, a lead developer on any sizable project that use(s) ADF BC for business rules enforcement should be familiar with.