Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,590
|
Comments: 51,219
Privacy Policy · Terms
filter by tags archive
time to read 2 min | 213 words

First, we have the implementation of the SendPropertyChanged method, can you spot the bug?

protected virtual void SendPropertyChanged(String propertyName)
{
	if ((this.PropertyChanged != null))
	{
		this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
	}
}

Then, you have:

public string CustomerID
{
	get
	{
		return this._CustomerID;
	}
	set
	{
		if ((this._CustomerID != value))
		{
			this.OnCustomerIDChanging(value);
			this.SendPropertyChanging();
			this._CustomerID = value;
			this.SendPropertyChanged("CustomerID");
			this.OnCustomerIDChanged();
		}
	}
}

And this:

public Customer Customer
{
	get
	{
		return this._Customer.Entity;
	}
	set
	{
		Customer previousValue = this._Customer.Entity;
		if (((previousValue != value) 
					|| (this._Customer.HasLoadedOrAssignedValue == false)))
		{
			this.SendPropertyChanging();
			if ((previousValue != null))
			{
				this._Customer.Entity = null;
				previousValue.Orders.Remove(this);
			}
			this._Customer.Entity = value;
			if ((value != null))
			{
				value.Orders.Add(this);
				this._CustomerID = value.CustomerID;
			}
			else
			{
				this._CustomerID = default(string);
			}
			this.SendPropertyChanged("Customer");
		}
	}
}

Both properties show exactly why I despise code generation as an architectural approach.

Instead of taking the appropriate route, and actually solving the problem at hand, they just threw code at it until it looked like it worked.

time to read 3 min | 407 words

Here are a few thoughts about the idea that given a DSL, you can just turn your entire business related stuff to the business users, and be done with it. This kind of thinking is very common, from the dreams of the secretary building applicaitons by dragging boxes to the business analyst modifying the workflows.

I disagree with this quite strongly. Giving a user this type of tool is an irresponsible step at best. The users are not developers, and they will make mistakes. And the first time that the business will lose money over it, it will be your fault.

  • It will be your fault when the server is on 100% CPU because the user has created endless loop.
  • It will be your fault when the server is down because of stack overflow.
  • It will be your fault that Mike from accounting made "just a tiny modification" that suddenly means that you sold a product with for 50% less than you paid for it.
  • It will be you fault that Joe just got a paycheck proudly stating -43.9.
  • It will be your fault that the company baught the entire fish market for the next three years.
  • It will be your fault that no one has any idea what the company's own business processes are.
  • It will be your fault that the database contains incosistent data.
  • It will be your fault that there is not control over it.
  • It will be your fault that there hasn't been an audit log for the last three months.

It will be your fault

Handing a user a tool like that is wonderful, it is a tool that can enable better communication and rapid response betweenthe IT and the business. Having a DSL means that you are talking in the same language, that you are less likely to mess up because of translation problems.

It does not mean that you can just throw it over the wall and walk away. A DSL is code, and like all code, it requires code review, QA, change management (source control), testing, intention revealing semantics, perf testing, auditing, error handling, transaction handling and much more.

Professional developers are having problems with handling that, giving it to unexperienced users is a mistake. It might work for the first few, but this is not a sustainable approach.

Consider the departmental application and their usual bar of quality. Do you truly intend to bring that, knowingly, into your codebase?

time to read 1 min | 124 words

Getting a DSL to work for a single file is fairly easy. Getting it to work in a real application is much harder. There are quite a few scenarios that you need to deal with irrespective of the DSL itself.

Those issues include:

  • Caching - compilation is expensive
  • Batch compilation - see above, also very important
  • Error handling - we can probably do at least some work here to make it easier. At the very least, output something like compilation exception would give us the nice yellow page with the error, compiled output, etc.
  • Automatic refresh - when the file changes, we can invalidate the cache and load from the file again.
  • IoC integration ?

What else do you think is needed?

time to read 1 min | 187 words

This came up with respect to MS MVC. The MS MVC team has decided to make some methods protected, and that makes testing using Rhino Mocks a bit of a pain.

Let us assume that I want test that the call to ProductController.Index() will render the "index.aspx" view. I can do something like:

[Test]
public void ShouldAskToRenderTheIndexAspxView()
{
	MockRepository mocks = new MockRepository();
	ProductController controller = mocks.PartialMock<ProductController>();
	using(mocks.Record())
	{
		controller.RenderView("index.aspx"); // <<-- Compiler error here, RenderView is protected!
	}

	using (mocks.Playback())
	{
		controller.Index();
	}
}

Problem, part of the Rhino Mocks design goal was the use of the compiler and tools as verifiers. I explicitly do not want to have strings in my code, and I put them only where I have no other choice. However, since Rhino Mocks by runtime subclassing, there is no issue with reflection calls...

This means that we can get around this limitation by using the following extension method:

public static void RenderView(this Controller self, string action)
{
	typeof(Controller).GetMethod("RenderView").Invoke(self, new object[] { action} );
}

This is it, it will compile and work now.

time to read 1 min | 161 words

I was just writing this line of code:

DslExecuter<SchedulingDslEngine>.Create(“validateWebSiteIsUp”)

When it occurred to me that this looks a look like an IoC resolve call. Which got me thinking about combining both concepts together, which gave me the shakes.

The idea is that we can expose those dependencies like this:

customers as ICustomerRepository
fraudService as IFraudService
alerts as IAlertService

for customer in customers.FindAll(With.Orders):
	for order in customer.Orders:
		if fraudService.IsFraud(order):
			alerts.ForFaurdOn(order)
			if customer.Important:
				alerts.NotifyCustomerAboutFraud(customer)

Leaving aside the mountain slope code*, consider what is going on here. We are exposing dependencies by specifying the types that we need. We can then get them through the IoC and execute the code in hand.

This means that the DSL has full access to everything in the application, and is subject to the same rules and behavior as all the other components. From my point of view... sweeeeeet.

* First example that popped to mind, yes, I know it is a bad one.

time to read 3 min | 586 words

Let us assume that we have this amazing javascript function:

function test()
{
	var nums = [1,2,3,4,5,6,7];
	for(var i = 0; i<nums.length; i++)
	{
		var alertLink = document.createElement("A");
		alertLink.href = "#";
		alertLink.innerHTML = nums[i];
		
		if( nums[i] % 2 == 0)
		{
			alertLink.onclick = function() { alert('EVEN: '+ nums[i]); };
		}
		else
		{
			alertLink.onclick = function() { alert('ODD: ' + nums[i]); };
		}
		
		document.firstChild.appendChild(alertLink);
		document.firstChild.appendChild(document.createElement("BR"));
		
	}
}

Can you guess what it would generate? Quite a few undefines alerts, as a matter of fact. Why is that? Because the anonymous function is a closure, which capture not the value of i, but the i variable itself.

This means when we click on a link that this method has generated, we use the last known value of i. Since we have exited the loop, i is actually 8.

Now, in C# we have the same problem, and we can solve it by introducing a temporary variable in the loop, so we change the code to look like this:

	
function test()
{
	var nums = [1,2,3,4,5,6,7];
	for(var i = 0; i<nums.length; i++)
	{
		var alertLink = document.createElement("A");
		alertLink.href = "#";
		alertLink.innerHTML = nums[i];
		
		var tmpNum = nums[i];
		
		if( nums[i] % 2 == 0)
		{
			alertLink.onclick = function() { alert('EVEN: '+ tmpNum ); };
		}
		else
		{
			alertLink.onclick = function() { alert('ODD: ' + tmpNum ); };
		}
		
		document.firstChild.appendChild(alertLink);
		document.firstChild.appendChild(document.createElement("BR"));
		
	}
}

Try to run it, and you'll get an.. interesting phenomenon. All the links will show tmpNum as 7. Again, we captured the variable itself, not its value. And in JS, it looks like you are getting the same variable in the loop, not a new one (this is absolutely the wrong way to describe it, but it is a good lie), like you would in C#.

What is even more interesting is that you would get the exact same result here:

	
function test()
{
	var nums = [1,2,3,4,5,6,7];
	for(var i = 0; i<nums.length; i++)
	{
		var alertLink = document.createElement("A");
		alertLink.href = "#";
		alertLink.innerHTML = nums[i];
		
		
		if( nums[i] % 2 == 0)
		{
			var tmpNum = nums[i];
			alertLink.onclick = function() { alert('EVEN: '+ tmpNum ); };
		}
		else
		{
			var tmpNum = nums[i];
			alertLink.onclick = function() { alert('ODD: ' + tmpNum ); };
		}
		
		document.firstChild.appendChild(alertLink);
		document.firstChild.appendChild(document.createElement("BR"));
		
	}
}

Here we have two different lexical scopes, with respectively different variables. Looks like it should work. But the lexical scope of JS is the function, not the nearest set of curly. Both tmpNum refer to the same variable, and as such, are keeping the last value in it.

If the lexical scope is a function, we need to use a function then. Here is a version that works:

	
function test()
{
	var nums = [1,2,3,4,5,6,7];
	for(var i = 0; i<nums.length; i++)
	{
		var alertLink = document.createElement("A");
		alertLink.href = "#";
		alertLink.innerHTML = nums[i];
		
	
		if( nums[i] % 2 == 0)
		{
			var act = function(tmpEVEN)
			{
				alertLink.onclick = function() { alert('EVEN: '+tmpEVEN); };
			};
			act(nums[i]);
		}
		else
		{
			var tmpODD = nums[i];
			alertLink.onclick = function() { alert('ODD: ' + tmpODD); };
		}
		
		document.firstChild.appendChild(alertLink);
		document.firstChild.appendChild(document.createElement("BR"));
		
	}
}

And that is it for today's JS lesson.

time to read 1 min | 90 words

I mentioned before that MS CRM's decision to build all its external API based on web services (that cannot be accessed outside of ASMX proxies) was a big mistake. It is a mistake because you are handing the developer a really clumsy, stupid, API.

I just spent an hour trying to figure out how to set a value to null. An hour!

It couldn't be as simple as this:

customer.new_employeeintouch = null;

It has to be:

customer.new_employeeintouch = new Lookup();
customer.new_employeeintouch.IsNull = true;
customer.new_employeeintouch.IsNullSpecified = true;
time to read 7 min | 1261 words

Over in the Alt.net mailing list, Glenn said:

If I was really being verbose in the way a business user would expect to define this I would say

               When customer is preferred and the order exceeds 1000 then apply a .05 discount and apply free shipping.

Now do that in a DSL….

Now, I am sucker for this kind of things, and I can probably use the practice. So I decided to go ahead with this. Just to be clear, this is supposedly a natural language processing, only we are going to cheat and get around that.

First, let us analyze the structure of the statement that we need to handle:

When customer is preferred and the order exceeds 1000 then apply a .05 discount and apply free shipping.

I put strike through all the fluff stuff, the things that doesn't really means anything for the language. Keywords are marked in blue, operators in red.

We have the following keywords:

  • When
  • And
  • Then

And the following operators:

  • Is
  • Exceeds
  • Discount
  • Shipping

Everything else is a variable.

This language follows the following syntax:

When [parameter] [operator] [value] (and [parameter] [operator] [value])+ then [parameter] [value] [operator] (and [parameter] [value] [operator] )

Note that the syntax between the when clause and the then clause is different. The operator is the last word there. This is because on the when we would usually do comparisons, while on the then we will perform actions.

Now, to the actual building of the language. We have the following model:

image

Let us take a look at the parser, it is a stupid, single purpose one, but it works. The main parts are to extract a list of ActionExpressions from the language.

public WhenThenClause SplitToWhenThenClause(string text)
{
	if (text.StartsWith("when", StringComparison.InvariantCultureIgnoreCase) == false)
		throw new InvalidOperationException("statement should start with a when");
	int thenIndex = text.IndexOf("then", StringComparison.InvariantCultureIgnoreCase);
	if (thenIndex == -1)
		throw new InvalidOperationException("statement should have a then");
	WhenThenClause clause = new WhenThenClause();
	string whenClause = text.Substring(4, thenIndex - 4).Trim();
	ParseClause(whenClause,
	            delegate(string[] parts)
	            {
	            	ActionExpression item = new ActionExpression();
	            	item.Left = parts[0];
	            	item.Operator = parts[1];
	            	item.Right = parts[2];
	            	clause.When.Add(item);
	            });
	string thenClause = text.Substring(thenIndex + 4);
	ParseClause(thenClause,
	            delegate(string[] parts)
	            {
	            	ActionExpression item = new ActionExpression();
	            	item.Left = parts[0];
	            	item.Right= parts[1];
	            	item.Operator = parts[2];
	            	clause.Then.Add(item);
	            });

	return clause;
}


private static void ParseClause(string clause,
                                Action<string[]> action)
{
	foreach (string subClauses in
		clause.Split(new string[] { "and" }, StringSplitOptions.RemoveEmptyEntries))
	{
		if (subClauses.Trim().Length == 0)
			continue;

		string[] parts = subClauses.Split(new char[] {' ', '\t'}, StringSplitOptions.RemoveEmptyEntries);
		if (parts.Length != 3)
			throw new InvalidOperationException("A clause should have three parts "+
"[object] [operation] [value], found:
" + subClauses); action(parts); } }

Now we need to look at the DslExecuter. This is the one that will take an ActionExpression and actually execute it. We are using reflection to avoid having to do all the work ourselves, so we have this:

public class DslExecuter
{
	private readonly Hashtable parameters = new Hashtable(StringComparer.InvariantCultureIgnoreCase);

	public void AddParameter(string name, object parameter)
	{
		parameters[name] = parameter;
	}

	public object Invoke(ActionExpression expression)
	{
		object obj = parameters[expression.Left];
		if (obj == null)
			throw new InvalidOperationException("Could not find parameter with name: " + expression.Left);
		MethodInfo method = obj.GetType().GetMethod(expression.Operator, BindingFlags.IgnoreCase 
| BindingFlags.Instance | BindingFlags.Public); if (method == null) throw new InvalidOperationException("Could not find method operator " +
expression.Operator + " on " + expression.Left); ParameterInfo[] methodParams = method.GetParameters(); if(methodParams.Length!=1) throw new InvalidOperationException(expression.Operator + " should accept a single parameter"); object converted; Type paramType = methodParams[0].ParameterType; if(paramType.IsEnum) { converted = Enum.Parse(paramType, expression.Right,true); } else { converted = Convert.ChangeType(expression.Right, paramType); } return method.Invoke(obj, new object[] {converted}); } }

Now that we have those two building blocks, it is very easy actually build the DSL itself. Here is the relevant code:

public void Execute()
{
	bool result = true;
	foreach (ActionExpression expression in parsed.When)
	{
		bool clauseResult = (bool) this.executer.Invoke(expression);
		result &= clauseResult;
	}

	if(result)
	{
		foreach (ActionExpression expression in parsed.Then)
		{
			executer.Invoke(expression);
		}
	}
}

We build a domain model to aid us here:

image

Basically this translate directly to the parameters that the DSL needs. This means that all we have left is just the setup of the DSL.

[Test]
public void CanExecuteThenStatement()
{
	ExternalDSLDemo dsl = new ExternalDSLDemo(sentence);
	Customer customer = new Customer();
	customer.CustomerStatus = CustomerStatus.Preferred;
	dsl.AddParameter("customer", customer);
	Order order = new Order();
	order.TotalCost = 5000;
	order.ShippingType = ShippingType.Fast;
	dsl.AddParameter("order", order);
	dsl.AddParameter("apply", new ApplyCommands(order));
	dsl.Execute();

	Assert.AreEqual(4750, order.TotalCost);
	Assert.AreEqual(ShippingType.Free, order.ShippingType);
}

But I am pretty sure that I explained that this external DSL are very hard. This doesn't seem very hard all.

No, this external DSL is not really hard. But try to do support something like:

when (customer is preferred) and (order exceeds 1000 or order is new) then ...

This is when it gets suddenly much more complex... and why I think that External DSL are rarely worth the time to fully develop them. It is much easier to build on top of an existing infrastructure.

You can get the code for this here:

https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-dsl/Rhino.DSL.Tests/ExternalDSL

time to read 3 min | 536 words

Jacob Proffitt calls me up to task for being inconsistent:

In this, Ole Friis is echoing the response I got from the intimidating Oren Eini when I suggested that TypeMock makes arguments that couple DI with unit testing go away.

The main weakness of Type Mock is its power, it allow me to take shortcuts that I don’t want to take, I want to get a system with low coupling and high cohesion.

Consenting AdultsThe implication is that he wouldn’t be developer enough to create a system with low coupling and high cohesion if he used powerful tools like TypeMock. Oren is inconsistent here because he’s otherwise all for developer empowerment as illustrated by his support for Jeffrey Palermo’s excellent post regarding treating developers as professionals.

How can I support the idea of alt.net as "running with scissors", responsible adults that are trusted to know what we are doing, with my comments on Type Mock having "too much power"?

It is a good thing that I never felt the need to be self consistent. It makes things much more... invigorating.

I'll start by saying that I often write bad code. What is bad code? In DevTeach, I showed James Kovacks a 150 lines methods that involved threading, anonymous delegates and exception handling in a ingeniously unmaintainable form. Bad as in you will get the axe and come after me with froth coming out of your mouth if you ever see it.

I have a certain style that works for me. It comes with a set of tools and practices that are built to encourage that style and mindset. Being a lazy bastard, I am careful to make sure that I cannot be too lazy, because otherwise it is usually me who needs to clean up my mess.

I believe that the choice of tool has a profound affect on my ability to work. That comes both at the tooling level (IDE, extensions, R#, etc) and the frameworks sides (IoC, OR/M, DSL, etc). Tools & frameworks should guide me where I want to go, and make it harder to do the wrong thing. This is a decision that I made based on my experience and observations.

After dealing with tools that do not encourage best practices, or tools that forces you to work harder to get there, it is a very important consideration to me. I don't see an inherent disconnect between the two. I believe that the term is that "with great power comes great responsibility". Recognizing that, I intentionally limit my own choices, in order to get things done using the approach that I believe is the best for what I am doing.

Does this mean that this approach is a one size fit all? Absolutely not.

In fact, I can tell you that from each and every project I come out with a profound understanding of how stupid I was when I got into the project, and how many mistakes I made in that project.

But, I do believe that this approach is applicable for a broad set of scenarios. Not all, but a broad set of scenarios.

FUTURE POSTS

  1. RavenDB & Distributed Debugging - about one day from now
  2. RavenDB & Ansible - 5 days from now

There are posts all the way to Jul 21, 2025

RECENT SERIES

  1. RavenDB 7.1 (7):
    11 Jul 2025 - The Gen AI release
  2. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  3. Webinar (7):
    05 Jun 2025 - Think inside the database
  4. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  5. RavenDB News (2):
    02 May 2025 - May 2025
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}