Ayende @ Rahien

Oren Eini aka Ayende Rahien CEO of Hibernating Rhinos LTD, which develops RavenDB, a NoSQL Open Source Document Database.

Get in touch with me:

oren@ravendb.net

+972 52-548-6969

Posts: 7,183 | Comments: 50,205

Privacy Policy Terms
filter by tags archive
time to read 5 min | 894 words

There are some really good comments in this post, which I am going to respond to. Before that, I want to emphasis that I am still playing devil's advocate here.

Joe has two very insightful comments, regarding the just hard code everything and don't provide any admin interface for the parameters:

When you're making software that will be used by more than one customer, you can't hardcode these things in.

And:

Again, why not? Why can't Company A use the same software as Company B and A wants to give 30% discount when amount is over $10K whereas B wants to give 20% when it's over $15K?
Why is that so hard to expose? It's just a matter a validation from the admin UI.

There is obviously no technical reason to do that, right?

image

Well, there is one good reason to avoid this at all costs. It just doesn't work when you have any significant amount of rules. And by that, I am talking anything over two dozens or so.

Let us consider what the implications of such a system would be when talking about a system with any kind of reasonable complexity.

The cost of adding a rule has gone up from a simple "add a class" to creating UI, validating values, saving values, adding to the current UI, loading parameters from persistence storage. This translate to moving from twenty minutes task (including testing) to much more complex endeavor. Consider a rule that should give you discount based on geographical location, you need to provide a way to select that. For that matter, you now need to have multi instance rules, where you need to have the same rule bound to different parameters.

Are you willing to estimate the cost now? It is an order of magnitude or two more complex.

Now, let us say that we have solved the problem in some manner. It is not a hard problem to solve, admittedly. We are still left with operational issues that we have to deal with. How are we going to educate the ops team about all the rules? So far I have chosen a very simple set of rules to show, but real business rules are nothing trivial.

Then, we have UI issues, how are we going to show the ops team the set of rules that they can edit? How are we going to represent hundreds and thousands of rules in a meaningful fashion?

My answer is very simple. Don't even try. Instead of trying so hard to cut developers out of the loop, start from assuming that there will be a developer along the way. Now you need to optimize the hell out of this approach.

Remember, we aren't talking about a system that has a very small set of rules, we are talking about a very large set of them. A competitive advantage is how fast we can go from a business requirement to that behavior running in production.

Take into account that a lot of the changes in the system are not just parameters changes, let us take example of just a few business rules that come up as things that the business wants to do. This is not in design phase. This is when the system is on the air:

  • A customer shopping on his birthday gets a 5% discount
  • A preferred customer that has been with us for over a year gets three [product name] for the price of one for this fall.

Again, pre planning for this might give you a way to deal with those (if you thought about that scenario), but even so, you are going to incur a much higher cost at the system implementation phase. Pushing the changes to code makes the implementation much easier, and the ability to modify the system at a later date is greatly improved, because you already built your system around the concept of dynamically changing environment.

But, as Joe said, this doesn't really work if you have more than one customer. It actually does, in my experience. There are a lot of system out there that have a dedicate person for their care, and giving someone a three hours course in how to do this kind of thing is fairly easy (with the requirement that they can program in C# or VB.Net, which is not inconceivable demand).

If this is still not something that you can do, put a DSL in place. A DSL script is much easier to work with for business oriented stuff, and it incur about the same cost from design and implementation view. However, deployment is ever so much easier, since you are deploying a single script, instead of a dll. You can even provide in app UI to do this, if you really wants.

In short, consider the scenario that I am describing, and oft changing environment with a lot of rules. If you have an opinion on how stupid this is, please provide that opinion within this given context.

time to read 3 min | 599 words

 

 Chris Ortman asks a very good question about my just hard code it post:

image

I really like the simplicity of the approach, but does this impose a requirement that in order to change the discount percentage of the system I must be able to write c# code? I think it would not take very long for someone to ask me for and 'admin' screen to do that.

I run into this all the time with new features that would be trivial to implement if not for the database table to hold the settings, the model to work with the table, and the admin screen to edit it. How do we get from 'enter 5 into this box in the admin screen' to write class that applies the discount percentage you want .

I have a very simple answer for that. You don't provide any sort of admin screen, and you don't provide any way for a business user to go into the system and make a change. To start with, the system administrator has no idea what are the implications of changing such a configuration. Next, we have the standard issues of when we reload the value, validation, etc. All sorts of things that we really don't want to deal with unless we have to. Not to mentions that the idea of letting anyone the option to modify operational parameters without regard to testing and QA makes me very unhappy.

All of those are workable with enough effort, however. What is not workable is the end result of such a system. Here is what you'll end up with:

image

Remember, we expect to have a lot of such rules. So we expect to have a lot of configuration values. And don't get me started on reusing configuration values for different purposes, just because a dev saw something that looked even somewhat similar to what they were doing now.

Given this piece of code, then, how are we going to handle a changing business condition? Let us say that we want to offer this only to preferred members after the first 6 months:

public class DiscountPreferredMembers : OnOrderSubmittal
{
	public override void Execute()
	{
		if ( User.IsPreferred )	
			Order.AddDiscountPrecentage(5);
	}
}

This is trivially simple:

public class DiscountPreferredMembers : OnOrderSubmittal
{
	public override void Execute()
	{
		if ( User.IsPreferred && DateTime.Now > User.PreferredMemberSince.AddMonths(6) )	
			Order.AddDiscountPrecentage(5);
	}
}

Compile this rule (which will usually be in a separate project, along with a bunch of other tightly related rules) and push it to production. If you are doing an out of band release, you might want to do it in a completely separate DLL.

And yes, we are still talking about using the lowest common denominator, without introducing any concept more complex than a class and the if statement. More advance solution would be a DSL, in which the deployment unit would be the individual script, instead of a full DLL.

But even so, I hope that I am demonstrating the concept.

All we have to do is to stop thinking about the code as set in stone and accept that this is one of the richer way we have to express semantics.

FUTURE POSTS

  1. Looking into Zig - 40 minutes from now
  2. RavenDB 5.2: Simplifying atomic cluster wide transactions - about one day from now

There are posts all the way to Aug 06, 2021

RECENT SERIES

  1. RavenDB 5.2 (2):
    12 Jul 2021 - Rolling index deployment
  2. Postmortem (2):
    23 Jul 2021 - Accidentally quadratic indexing output
  3. re (28):
    23 Jun 2021 - The performance regression odyssey
  4. Challenge (58):
    16 Jun 2021 - Detecting livelihood in a distributed cluster
  5. Webinar (4):
    11 Jun 2021 - Machine Learning and Time Series in RavenDB with Live Examples
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats