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,527
|
Comments: 51,163
Privacy Policy · Terms
filter by tags archive
time to read 3 min | 427 words

Over two years ago, I started working at We!. I wanted to work there mainly because during the interview I was very impressed by the amount of knowledge that the interviewer had. Looking back on the last couple of years, it has been a very good decision. I had the chance to work on interesting projects, work with very smart people, and do some crazy things. Mostly, I got to chance to make a lot of mistakes, learn from then and then make another set of mistakes.

I also had a lot of fun, and the ability to say that I really enjoy what I was doing.

Recently, We! has made a shift in the direction the developer division is headed, and now intends to focus primarily on business solutions. This translate to Share Point and MS CRM solutions. I have no experience in Share Point, so I can't comment on that, but I believe that I expressed my opinions on MS CRM elsewhere quite clearly. The company is focusing on bigger projects, based on those platforms. Those are more profitable, but they are also of the assembly line variety, hook this, bridge that, fill in those gaps, etc.

My interest lies elsewhere. I am interested in building applications in agile fashion, using TDD, DDD and ADD. From a business perspective, We!'s decision is probably extremely reasonable and smart, but it is simply not what I would like to do.

I have been thinking about this for a while now, and I have finally made up my mind about it in the last couple of days. Unless something drastic changes, I intend to leave We! after we finish our current project (around January 2008, I believe).

What does this mean?

I want to take this chance and see how things are going elsewhere in the world, this means that I am leaning toward relocating. I have a good idea about what I want to do next, but nothing that is set in stone. I have already rejected a highly technical position, I am not interested in tech for tech's sake. I believe that I have enough knowledge and experience to handle most technologies. What I would like to do now is working in an agile environment, in an agile team.

I see the following options:

  • Independent consultant / trainer
  • Consultancy
  • Startup
  • Product team

As always, I am interested in your opinions in this matter.

Full disclosure note: I don't have a degree, which I looks like can cause issues when getting a work visa.

time to read 2 min | 298 words

I am using a different meaning to the terms "scaling" and "scalable". I am usually not really worried about performance or scaling out a solution. I am often thinking about how I can take a certain approach and scale it out to the more complex scenarios.

Dragging a table to the form as an example, doesn't scale. It doesn't scale because when you need to handle logic, you need to go into significant complexity just to get it. NHibernate does scale, because so far it handled everything that I threw at her without increasing the complexity of the solution beyond the complexity of the problem.

image

I think that this graph should explain it better.

What we see here are the complexities of solutions vs. the complexity of the problem. The unscalable solution complexity increase more and more as the complexity of the problem grows.

The scalable solution's complexity increase as well, but it increase in direct relationship to the problem at hand. If we need to have a problem twice a complex, then the solution will be about twice as complex.

It can't be less than twice as complex, because you can't escape the complexity, but the other solution is nine times as complex, and the difference between the two only grows when the problem gets more complex.

And that is how I evaluate most of the things that I use. Do they scale? Will I be able to handle more complex scenarios without tool-induced pain?

The solution is allowed to be complex because the problem that we are trying to solve is complex. It must not be complex because the tool that I am using need crutches to handle complex scenarios.

time to read 3 min | 455 words

Jeff Atwood is talking about languages in languages, and suggest that you would avoid using fluent interfaces to hide a language semantics. I completely disagree. Let us talk about the example. The first one deals with regular expressions:

//Regular expression
Pattern findGamesPattern = new Pattern(@"<div\s*class=""game""\s*id=:"(?<gameID>\d+)-game""(?<content>.*?)
<!--gameStatus\s*=\s*(?<gameState>\d+)-->
");

// Fluent interface
Pattern findGamesPattern = Pattern.With.Literal(@"<div")
    .WhiteSpace.Repeat.ZeroOrMore
    .Literal(@"class=""game""").WhiteSpace.Repeat.ZeroOrMore.Literal(@"id=""")
    .NamedGroup("gameId", Pattern.With.Digit.Repeat.OneOrMore)
    .Literal(@"-game""")
    .NamedGroup("content", Pattern.With.Anything.Repeat.Lazy.ZeroOrMore)
    .Literal(@"<!--gameStatus")
    .WhiteSpace.Repeat.ZeroOrMore.Literal("=").WhiteSpace.Repeat.ZeroOrMore
    .NamedGroup("gameState", Pattern.With.Digit.Repeat.OneOrMore)
    .Literal("-->");

I can read the fluent interface, but I need to parse the regex pattern. There are tradeoffs there, because as a regex gets more complex, it is getting unreadable. The fluent interface above keep it maintainable even for complex regular expression.

The second example deal with SQL:

// Embdded language
IDataReader rdr = QueryDb("SELECT * FROM Customer WHERE Country = 'USA' ORDER BY CompanyName");

// Fluent interface
IDataReader rdr = new Query("Customer")
	.WHERE(Customer.Columns.Country, "USA")
	.OrderByAsc(Customer.Columns.CompanyName)
	.ExecuteReader();

Here it is much easier to read the SQL statement, right? Except that the statements are not equal to one another. Using "select *" is inefficient, you want to explicitly say what columns you want (even if you want them all).

Nevertheless, the SQL code is much easier to read. It doesn't handle parameters, though, so it will probably encourage SQL injection, but I digress.

So, we have two examples, which mostly go in two different direction, we are inconclusive, right?

No, because one thing that Jeff didn't cover was logic.

I have a regular expression that need to change based on some sort of logic. Imagine validating a document with several options, validating ID per country, validating phone numbers by area, validating email address that belong to a certain company, etc. Even if we have only three choices in each category, this put us in way too many separate regexes to maintain. We need to construct them dynamically.

Now, anyone here thinks that regular expressions that are being constructed using string concat are going to be easy to understand? Easy to write? Maintainable?

What about SQL? Do you think that you can build this search form by simply concating SQL? Do you think it would be maintainable?

I am sorry, but I don't see this approach working when you move beyond the static, one of, stuff. Sure, I write a lot of SQL to look at my data, but it is done in management studio, and it doesn't go into my application. I can't afford the maintainability issues that this will cause.

time to read 2 min | 207 words

While most of the people working and using open source are fun to work with, there are some people who are... not.

A discussion on the nature of OSS development had turned into an exchange of stories about the "I'm using your stuff, you owe me big time." characters that appears every so often among the otherwise great communities.

Some of those encounters range from the one who thinks that I work for them: "I run into this issue with your stuff, I need you to fix it by Wednesday."

The blackmail attempts are almost amusing: "If you don't add this feature (three months development and human sacrifice may be involved) the I am never using your stuff again, and neither will my company."

To those that have Seen the Light and feel the need to spread it: "Why are you wasting your time on such a expletive expletive expletive stuff, are you so stupid you don't realize that Yxz is so much better then your expletive expletive expletive."

 I remove the expletives because they were fairly unimaginative.

The weirdest so far was a guy that  tried to convert me to Islam on the basis of exchanging three emails.

So, what is your best horror story?

Helplessness

time to read 1 min | 135 words

image Not my code.

I am not even calling this by any way shape or mean.

No way in, no way to debug, check or fix.

In Reflector, the ViewId setter is 80 lines long and contains enough logic to start evolving on its own.

I have spent the entire day fighting the CRM, trying to get it, not to work right, because I consider this beyond hope, but just to the barely functioning level that seems to be the normal state of affair there.

This is just the latest in a long series of error that had made this day an utterly frustrating, annoying, aggrevating mess.

I am going home.

 

 

 

 

 

 

.

Mocking Boo

time to read 24 min | 4735 words

Okay, I built it to relax a bit, because I am extremely annoyed at the moment. I apologize in advance for the code quality, it is POC only, but still, I wouldn't generally release it like this.

What is this? Do you see the highlighted bit at the bottom? This is Boo code that invokes a Macro on compile. It will generate an adapter and an interface, so you don't have to do it manually. The implementation code is below:

image

class AdapterMacro(AbstractAstMacro):

      def Expand(macro as MacroStatement):

            if macro.Arguments.Count != 1 or not macro.Arguments[0] isa ReferenceExpression:

                  raise "adapter must be called with a single argument"

            entity = NameResolutionService.Resolve(macro.Arguments[0].ToString())

            raise "adapter only accept types" unless entity.EntityType == EntityType.Type

            BuildType(macro, entity)

           

      def GetModule(node as Node) as Boo.Lang.Compiler.Ast.Module:

            return node if node isa Boo.Lang.Compiler.Ast.Module

            return GetModule(node.ParentNode)

     

      def BuildType(macro as MacroStatement, type as IType):

            adapter = ClassDefinition(Name: "${type.Name}Adapter")

            adapter.Members.Extend(

                  Field(Name: "theTarget", Type: SimpleTypeReference(type.FullName) )

            )

           

            ctor = Constructor()

            ctor.Parameters.Add(ParameterDeclaration("target", SimpleTypeReference(type.FullName) ) )

            ctor.Body.Add(

                  BinaryExpression(BinaryOperatorType.Assign,

                        ReferenceExpression("theTarget"),

                        ReferenceExpression(Name: "target")

                  )

            )

            adapter.Members.Add(ctor)

            adapterInterface = InterfaceDefinition(Name: "I${type.Name}")

            GetModule(macro).Members.Add(adapter)

            GetModule(macro).Members.Add(adapterInterface)

            adapter.BaseTypes.Add( SimpleTypeReference(adapterInterface.FullName) )

            for member in type.GetMembers():

                  AddMethod(adapter, adapterInterface,  member) if member isa IMethod

           

            BooPrinterVisitor(System.Console.Out).Visit(adapterInterface)

            BooPrinterVisitor(System.Console.Out).Visit(adapter)

           

      def AddMethod(adapter as ClassDefinition,

            adapterInterface as InterfaceDefinition,

            method as IMethod):

           

            return unless method.IsPublic

           

            interfaceMethod = Method(Name: method.Name)

            forwarder = Method(Name: method.Name)

           

            if method.ReturnType.IsByRef or method.ReturnType.IsArray:

                  return

           

            args = []

            for param in method.GetParameters():

                 

                  if param.IsByRef or param.Type.IsArray:

                        return

 

                  forwarder.Parameters.Extend(

                        ParameterDeclaration(

                              Name: param.Name,

                              Type: SimpleTypeReference(param.Type.FullName)

                              )

                        )

                  interfaceMethod.Parameters.Extend(

                        ParameterDeclaration(

                              Name: param.Name,

                              Type: SimpleTypeReference(param.Type.FullName)

                              )

                        )

                  args.Add( ReferenceExpression(param.Name) )

                 

            adapterInterface.Members.Add(interfaceMethod)

            adapter.Members.Add(forwarder)

           

            mie = MethodInvocationExpression(

                  Target: AstUtil.CreateReferenceExpression("theTarget.${method.Name}")

                  )

            mie.Arguments.Extend(args)

            forwarder.ReturnType = SimpleTypeReference(method.ReturnType.FullName)

            interfaceMethod.ReturnType = SimpleTypeReference(method.ReturnType.FullName)

            if method.ReturnType == typeof(void):

                  forwarder.Body.Add(mie)

            else:

                  forwarder.Body.Add(ReturnStatement(mie))

Dynamic Methods

time to read 2 min | 352 words

I don't hear it talked about, but the CLR has a very efficient way to generate code at runtime. Probably this is because this code generation stuff is something that is accessible through IL generation only, and that is not for the faint of heart. Nevertheless, there are some very useful uses for this. NHibernate is utilizing this approach to avoid the costs of reflection, for instance.

Let us take a look about a simple scenario, we want to translate any delegate type with two parameters to a call to an instance method on our class:

public class Program
{
	private static void Main(string[] args)
	{
		new Program().Execute();
	}

	private void Execute()
	{
		//instance that has events that we want to subscribe the adapter to 
		DataGridView dataGridView1 = new DataGridView();
		EventInfo ei = dataGridView1.GetType().GetEvent("RowPrePaint");

		ParameterInfo[]pia = ei.EventHandlerType.GetMethod("Invoke").GetParameters();

		MethodInfo methodInfo = this.GetType().GetMethod("Handler", 
			new Type[]{typeof (object), typeof (object)});

		DynamicMethod mtd = new DynamicMethod(
			"Adapter",
			typeof(void),
			new Type[]
				{
					typeof (Program), // this 
					pia[0].ParameterType,// sender
					pia[1].ParameterType // e
				}, this.GetType(), true);

		ILGenerator gtr = mtd.GetILGenerator();
		gtr.Emit(OpCodes.Ldarg_0); // this
		gtr.Emit(OpCodes.Ldarg_1); // sender
		gtr.Emit(OpCodes.Ldarg_2); // e
		gtr.Emit(OpCodes.Call, methodInfo);
		gtr.Emit(OpCodes.Ret);

		// generate a delegate bound to this object instance
		Delegate dynamicDelegate = mtd.CreateDelegate(typeof(DataGridViewRowPrePaintEventHandler), this);
		//register the adapter
		ei.AddEventHandler(dataGridView1, dynamicDelegate);


		dataGridView1.GetType().GetMethod("OnRowPrePaint", BindingFlags.NonPublic | BindingFlags.Instance)
			.Invoke(dataGridView1, new object[] { null });
	}

	// method that handles the call
	public void Handler(object x, object y)
	{
		Console.WriteLine("{0}: {1}, {2}", this.GetHashCode(), x, y);
	}
}

Take into account that you are probably going to want to cache the method anyway, but this is a cool, if long winded way of achieving this. Personally, in this scenario I would probably simply write a reflection based wrapper, the complexity doesn't really have justification in such a case, but this is just an example, of course.

SQL Gotchas

time to read 2 min | 203 words

I think you can imagine the amount of paint involved in having a query behave in an unexpected manner. I have run into both of those recently. This one had me doubting my sanity (imagine this on a table with several hundred thousands records, with a fairly complex query around it:

select 1

where 1 not in (2,3,null)

And then there is this interesting little query:

select 1 where 'e' = 'e   '

I refused to believe the result until I saw it myself.

time to read 2 min | 210 words

image This is a screen cast that was spawned as a result of the discussion in the ALT.Net about the ideal IDE. Glenn Block mentioned that something that would be cool is:

Ability to instantly search for a specific artifact (kind of like Google / windows live search). As I type it in, I see the filtered results.

I like challenges, and I happened to know some components that can make this very easy, so I set out to build the foundations of a code search engine that can match the above requirements. Now, refining it to the point where it is usable should take about a day or two, I think, but all the basics are there.

  • Length: 28:07:00
  • Download size: 40Mb
  • Code starts at: 1 minute mark

This is basically glue code, so be aware of it. It meant to show you how, not to actually show production level code to handle all the required scenarios.

You can download the screen cast here. As usual, the sound quality is probably suspect, and I recorded it at 2AM, so I am not sounding my best there.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. RavenDB Cloud (2):
    26 Nov 2024 - Auto scaling
  2. Challenge (75):
    01 Jul 2024 - Efficient snapshotable state
  3. Recording (14):
    19 Jun 2024 - Building a Database Engine in C# & .NET
  4. re (33):
    28 May 2024 - Secure Drop protocol
  5. Meta Blog (2):
    23 Jan 2024 - I'm a JS Developer now
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}