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,546
|
Comments: 51,161
Privacy Policy · Terms
filter by tags archive
time to read 1 min | 84 words

Because Binsor is strongly typed, you need to specify the imports for all the types you are using. It can get quite long, at times, because you are usually crossing the entire application, so basically every namespace you can think of is there.

I don't like that, it should be clear what is going on, and the imports should go elsewhere where they don't distract me. So I did it.

You can now write:

import namespaces from defaultImports.boo
#real code here
time to read 2 min | 300 words

A word of advice, if you are not using an IoC, you don't have the problem of defining components, you have the one before that, of dependency management. I am talking here what happens after you embrace IoC, what the next pain points are.

Having the configuration in a single place, being able to define both the shape of the application and its configuration is really nice. It makes a lot of things very easy. Until you want to send allow the user to extend a single facet of the configuration, but not allow them (or not expose them) to the full configuration.

You would want to define your components in a single place, and their configuration in another. To supply all the required configuration, and let the end user override them.

That is usually the place where we setup bridge to a more traditional configuration approaches, which isn't really pleasant. I just added to Binsor to do this across files, so I can use the following syntax to define and override configuration.

Main file:

def DefineComponent():
	component "email_sender", ISender, EmailSender
	
	component "email_sender2", ISender, EmailSender:
		Host = "example123.dot.org", To = ( "Lauren" )

	component "email_sender3", ISender, EmailSender
Extensibility file:
import file from Main.boo

DefineComponent()

extend "email_sender":
	Host = "example.dot.org", To = ( "Kaitlyn", "Matthew", "Lauren" )

extend "email_sender2":
	Host = "example.dot.org", To = ( "Kaitlyn", "Matthew", "Lauren" )

extend "email_sender3":
	@startable = true
	@tag1 = "important", tag2 = "priority"
	lifestyle Pooled, InitialPoolSize = 10, MaxPoolSize = 100
	configuration:
		hosts(list, item: host) = ["rhino", "orca"]

Combine that with the Windsor's resource system, and you get an embedded configuration, externally configurable.

I find it very sleek.

Binsor 2.0

time to read 4 min | 671 words

All credit should go to Craig Neuwirt, for some amazing feats of syntax. He has managed to extend Binsor to include practically all of Windsor's configuration schema. This is important because previously we had to resort to either manual / ugly stuff or go back to XML (see: manual & ugly).

This is important because some of the more interesting things that you can do with Windsor are done using the facilities, and Craig has made sure that Binsor will support the main ones in a natural manner, including out of the box support for the standard configuration model.

Let us start by using the standard configuration model for a moment, the Active Record Integration Facility is expecting to be configured from XML, but we can configure it like this:

facility arintegration, ActiveRecordFacility:
	configuration:
		@isWeb = true, isDebug = true
		assemblies = [ Assembly.Load("My.Assembly") ]
		config(keyvalues, item: add):
			show_sql = true
			command_timeout = 5000
connection.isolation = 'ReadCommitted' cache.use_query_cache = false dialect = 'NHibernate.Dialect.MsSql2005Dialect' connection.provider = 'NHibernate.Connection.DriverConnectionProvider' connection.driver_class = 'NHibernate.Driver.SqlClientDriver' connection.connection_string_name = 'MyDatabase' end end

To compare, here is the equivalent  XML configuration.

<facility id="arintegration" 
	type="Castle.Facilities.ActiveRecordIntegration.ActiveRecordFacility, Castle.Facilities.ActiveRecordIntegration" 
	isWeb="true" 
	createSchema="true">
 <assemblies>
	<item>My.Assembly</item>
 </assemblies>
 <config>
	<add key="hibernate.cache.use_query_cache" value="true" />
	<add key="hibernate.connection.isolation" value="ReadCommitted" />
	<add key="hibernate.show_sql" value="false" />
	<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
	<add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
	<add key="hibernate.connection.connection_string_name" value="MyDatabase" />
	<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
 </config>
</facility>

We don't have any significant reduction in the number of lines. This is mostly because we need to specify a lot of items for the facility to work, but we do have significant reduction in the noise that we have to deal with.

But, frankly, this isn't the best sample, let us take a look at the shortcuts that Binsor now provides, shall we?

Event Wiring

XML configuration:

<component 
	id="SimpleListener" 
      type="Castle.Facilities.EventWiring.Tests.Model.SimpleListener, Castle.Facilities.EventWiring.Tests" />

<component 
	id="SimplePublisher" 
      type="Castle.Facilities.EventWiring.Tests.Model.SimplePublisher, Castle.Facilities.EventWiring.Tests" >
      <subscribers>
      	<subscriber id="SimpleListener" event="Event" handler="OnPublish"/>
	</subscribers>
</component>

And the Binsor configuration to match it:

component simple_listener, SimpleListener

component simple_publisher, SimplePublisher:
	wireEvent Publish:
		to @simple_listener.OnPublish

Now that is far clearer, isn't it?

Factory Support

XML configuration:

<component id="mycompfactory" 
      type="Company.Components.MyCompFactory, Company.Components"/>

<component id="mycomp" 
	type="Company.Components.MyComp, Company.Components"
	factoryId="mycompfactory" 
	factoryCreate="Create" />

Binsor configuration:

component mycompfactory, MyCompFactory

component mycomp, MyComp:
	createUsing @mycompfactory.Create

Other new features:

  • Integrating Castle Resources, so now we can use Binsor over several files, which can be located anywhere, including assembly resources, for instance.
  • Easy support for startable and life styles.
  • Extension points for future needs.
time to read 2 min | 391 words

You were just handed a strange DSL implementation, it does stuff, and it may be cool, but you have no idea how it works.

Craig Neuwirt recently did a major overhaul of Windsor ( I am going to post soon with the details of how cool it is now ), but I am now faced with the question, how do you grok such a thing? I thought that it would be useful to put a list of what I am doing to understand how the internals now works.

It goes without saying, but the nitpickers will ask, that a DSL implementation is code like any other, and as such, it can have good & bad implementations. I think that what Craig has done was amazing. It makes for an interesting reading, I actually had to take notes, to make sure that I will not miss any of the cool stuff.

  • Understand the domain.
    This is critical, because if the DSL is chicken scratching to you, you won't be able to get the implementation.
  • Get the tests.
    First things first, make sure that you have tests that ensure that you can understand what the DSL is supposed to do. In addition to that, it allows you to debug a simplified scenario repeatedly, so you can walk through that and figure out what is going on.
  • Take the simplest scenario and run it, then open the resulting DLL in Reflector
    This is important, because you need to be able to see what the differences are between the DSL and the actual executed code are. This allows you to understand in a deep level what the various elements of the language do.
  • Identify a transformation, and follow how it is being built throughout the code
    It will allow you to understand the concepts and patterns used through the code.
  • Follow each transformation throughout its own code path only
    Fairly often you can get side tracked by trying to put the entire program in your head, this is usually not possible, track a single path through the code to completion. After that, you can start tracking other paths, but it is important to have an understanding of the full cycle, and then expand from that.

Hm, not really that different from how I would approach an unfamiliar code base, come to think about it.

Multi file DSLs

time to read 3 min | 417 words

imageWhile a DSL can really cut down the amount of code that you need to write, putting everything in one file is not a good idea. But I like my DSLs to be script  like, without the need for an explicit compilation step. I have thought about it for a while now, and yesterday ago Craig Neuwirt* asked how it can be done using Binsor.

My default language is Boo, obviously, which is a static, compiled language that pretends that it is dynamic and scriptish, giving the best of all worlds. One of the cool things about Boo is that you can reference an assembly by just doing this:

import System.Data.SqlClient from System.Data

This make it very easy to write scripts, because you just declare things and they will be automatically referenced, without needing to pass parameters to the script runner.

Now, I wanted to have some way to handle file inclusion as well. But Boo doesn't support this. This is not something that you can do in a method, or dynamic loading, you have to do this as part of the compilation process.

In a normal language, I would be left with building pre-processors, or doing heuristics to find all the relevant files that I want, or write an XML file that would detail which file I want to include. But Boo is not a normal language, it is a Super Language. It let me do what I want. And I wanted to have file references.

So I did.

I love Boo, I really do. The initial sample I started with was this. This is actually on the examples, what do you know. Then I thought about how I wanted to it, and I figured out that I can do this:

import file from  anotherFile.boo

Boo allows me to modify the compiler object model (AST) at compilation, so I just detect all the imports for the namespace "file", and then I compile and reference that file. I can even do this:

import file from  "~/config/anotherFile.boo"

Where ~ is translated to the AppDomain BaseDirectory.

You can find the code here, about 100 lines of code, out of which around 30 could be YAGNIed away. Wasn't very hard, and make me love Boo all over again, for what it allows me to do.

* Who doesn't blog, and a search for "Craig Neuwirt blog" brings back my blog :-) (hint)

time to read 1 min | 195 words

Today I broke down and added this to my windsor.boo config:

serviceAssemblies = ( Assembly.Load("MyApp"), )
for asm in serviceAssemblies:
  for type in asm.GetTypes():
    continue unless type.NameSpace == "MyApp.Services"
    continue if type.IsInterface or type.IsAbstract or type.GetInterfaces().Length == 0
    Component(type.FullName, type.GetInterfaces()[0], type)

I was staring at the task of adding two lines to a config file that is less than a 100 lines (including imports & spacing), but that would have been an extra step that I needed to take, and I had intended to create three or five services in the next hour or so. At that point, I couldn't live with having to go into that extra step of adding a line per service.

It is not the line itself that is bothering me, it is the need to remember adding it. Stuff should just happen the way I want it to. I really like that Binsor give me the ability to just go and change the convention of the configuration at will, and that would do for now.

time to read 3 min | 494 words

Hammett has a post that made me think. He is talking about configuring Spring for Java and has this to comment:

I can’t understand this uncontrolled passion that java programmers carry for xml.

I can certainly agree with him about that, but I got to the same point a long time ago with Windsor. I had an application which was rife with components. I am talking about many dozens of generic (as in MyComponent<T>) components, all of which required registration in the config file, which got to be fairly annoying very fast.

I solved that by creating Binsor, a Boo DSL for configuring an IoC container. Initially, it was very similar to the Batch Registration Facility, but I pushed it much further, until today I do all my Windsor configuration using Windsor.boo, and its existence is a core part of my application architecture. Why? Because I can do things like this:

controllersAssemblies = (Assembly.Load("MyApp.Web"), Assembly.Load("Castle.MonoRail.ViewComponents") )
for asm in controllersAssemblies:
	for type in asm.GetTypes():
		continue if type.Name == "ScheduledTasksController"
		if typeof(Controller).IsAssignableFrom(type):
			IoC.Container.AddComponent(type.FullName, type)
		if not typeof(ViewComponent).IsAssignableFrom(type):
			IoC.Container.AddComponent(type.Name, type)

The immediate result of this type of behavior is that I don't have any weight of the IoC, I just develop as I would normally would, and it catches up with everything that it needs to handle.

I recently had the chance to maintain a MonoRail application that used XML for configuring Windsor, and by the third time that I added a controller, I was pretty annoyed. Each and every time, I had an additional step to perform before I could run the code. Compared to the approach that I was using, it was hardly zero friction.

Of course, my approach is not flawless in any mean, there is a bug in the configuration above, can you spot it?

The point of this post, which I have been trying to get to for a while, while random electrical pulses moved my fingers in interesting ways, is that I have began not only to use this to a great extent (all projects in the last year or so are based on this idea), but I have started to actually design with this in mind.

The end result right now is that I am relying a lot more on commands patterns and attributes for selections. This means that I often do things like:

[SelectionCriteria(Selection.FirstOption, Selection.SecondOption)]
public void SomeSpecficCommand : Command<ObjectActingUpon>
{
	public override void Execute()
	{
	}
}

You can see a more real world sample here, but the idea is to declaratively express the intent, have the configuration figure out what I want, and make it happen. The nice thing, most of the time, It Just Works. And the nice thing about utilizing Binsor is that I can adapt the convention very easily. So I can have many nice conventions, each for a particular situation.

time to read 9 min | 1739 words

So, it looks like the vote goes decidefully for MonoRail, so that is what I am going to build it with. I have setup a project here:
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/SampleApplications/Hibernating.Forums

I have decided to take advantage of this series and show some other cool stuff that I have used, from the Repository<T> & NHQG to Binsor and MonoRail Windsor Integration.

The application is basically just UI and configuration right now. I did some very rough strcuturing of the UI in a way that should help me work on it.

The most interesting part is probably the windsor configuration:

import System.Reflection

import Castle.MonoRail.Framework

import Castle.MonoRail.WindsorExtension

 

Facility( "rails", RailsFacility )

 

webAsm = Assembly.Load("HibernatingForums.Web")

activeRecordAssemblies = ( Assembly.Load("HibernatingForums.Model"), )

 

for type in webAsm.GetTypes():

      if typeof(Controller).IsAssignableFrom(type):

            Component(type.Name, type)

      elif typeof(ViewComponent).IsAssignableFrom(type):

            Component(type.Name, type)

 

 

Component("active_record_repository", IRepository, ARRepository)

Component("active_record_unit_of_work",

      IUnitOfWorkFactory,

      ActiveRecordUnitOfWorkFactory,

      assemblies: activeRecordAssemblies )

I will probably start recording tomorrow (unlikely) or on Friday.

time to read 12 min | 2250 words

Tomer Gabel commented on my post about debuggable configuration:

This may be debuggable, but it sure as hell doesn't look like configuration to me. Configuration should be declarative and should not contain complex logic (what you show above definitely falls under that category in my book). This sort of script is, as far as I'm concerned, tantamount to collating all your configurable properties into one external, dynamically-compiled class -- in other words, hardcoded.

Let me just point out what I tried to do when I started using this approach:

death.by.xml.png

Looks familiar, anyone? I have shown this image to a fair amount of people, I got a lot of guilty looks :-) and general acknowledgement that this is a very bad place to be.

Now, to Tomer's comment:

This is a dynamically compiled class, but I wouldn't call it hard coded. It has all the features of a configuration file, i.e: restart the app and it will get the chances, I even has an app when I can do this type of changes on the fly. Declarative is an issue because you start to get out of control very fast with it in even mildly complex scenarios.

When I need to change a property or a feature, I can do so by opening this in notepad, make a change, and continue, there is nothing else that is needed to happen. I routinely does such things on production (tuning parameters, etc). I believe that this approach is far more common in dynamic langauges. Configuring MediaWiki, for instnace, is done by editing a php file.

This simplify things to a large degree, no need to extract values form XML, build the object graph, transform it, etc. I can just build the final result directly. The code I have shown is also doing some glue to connect some parts of the application. I mentioned that I am not sure if it is the responsability of the configuration to do so, but that is another matter.

Where does XML configuration fails?

Repeated configuration, I need to define 10 things of the same kind, with slight variations. For instance, defining a customer, where each customer has a different connection string:

customersDatabases = {

      "Northwind"       : "Data Source=...",

      "AdventureWorks"  : "Data Source=..."

      }

     

for entry in customersDatabases:

      Application.RegisterClientDatabase(entry.Key, entry.Value, ClientOptions.UseSharedConfiguration)

Now, imagine trying to do that in XML. Specifying debug/release configuration is also much easier:

if Environment.MachineName ~= /prod/: #production

      Application.LogLevel = LogLevel.Error

      Application.CrashReport = ( EmailReport("admin@site.com"), SmsReport("132432142") )

      Application.ShowErrorToUser = false

     

if Environment.MachineName ~= /test/: # test / staging

      Application.LogLevel = LogLevel.Info

      Application.CrashReport = ( BugTrackReport("trac.build.com"), )

      Application.ShowErrorToUser = false

     

if Environment.MachineName ~= /lap/: # dev machine

      Application.LogLevel = LogLevel.Debug

      Application.CrashReport = ( ErrorMessageReport("trac.build.com"), )

      Application.ShowErrorToUser = false

Trying to do the same in XML bring you right back to trying to debug XML. Since I don't know anyone except developer / IT admin that is going to touch a configuration file anyway, the claim that it is not readable to non-dev is not an issue. It is worth mentioning, though, that it is fairly easy to build a GUI over this.

time to read 8 min | 1525 words

Okay, this is a lie, but it is nearly true. Take a look at this Binsor script:

def OnNewTransaction(transaction as ITransaction,  transactionMode as TransactionMode,  isolationMode as IsolationMode):

    transaction.Enlist( TransactionScopeResourceAdapter(transactionMode) )

 

Component(transaction_manager, ITransactionManager, DefaultTransactionManager)

IoC.Container.AddFacility("automatic_transaction_management_facility", TransactionFacility())

 

IoC.Container.Kernel.ComponentCreated += do(model as ComponentModel, instance as object):

    cast(ITransactionManager, instance).TransactionCreated += OnNewTransaction if instance isa ITransactionManager

 

activeRecordAssemblies = ( Assembly.Load("Exesto.Model"), )

 

Component(active_record_repository, IRepository, ARRepository)

Component(active_record_unit_of_work, IUnitOfWorkFactory, ActiveRecordUnitOfWorkFactory, assemblies: activeRecordAssemblies )

 

Component(just_service, JustService)

In 10 lines of code, it setup a Active Record, setup unit of work, setup automatic transaction support, bind it to my Active Record Unit Of Work Adapter (note the OnNewTransaction and registerring to the ComponentCreated event) and setup a service that uses declarative transactions.

It also slice, dice and debug ;-)

On the one hand, it opens up a whole new world of options in the configuration. On the other hand, should this stuff be in the configuration in the first place? The ability to do things on ComponentCreated, for instnace, or to register to a specific event from a service and do stuff from the configuration is very powerful. The problem is that I am very afraid of trying to maintain anything but the simplest stuff there, since it is probably the most volatile part of the application.

 

 

FUTURE POSTS

  1. Partial writes, IO_Uring and safety - about one day from now
  2. Configuration values & Escape hatches - 5 days from now
  3. What happens when a sparse file allocation fails? - 7 days from now
  4. NTFS has an emergency stash of disk space - 9 days from now
  5. Challenge: Giving file system developer ulcer - 12 days from now

And 4 more posts are pending...

There are posts all the way to Feb 17, 2025

RECENT SERIES

  1. Challenge (77):
    20 Jan 2025 - What does this code do?
  2. Answer (13):
    22 Jan 2025 - What does this code do?
  3. Production post-mortem (2):
    17 Jan 2025 - Inspecting ourselves to death
  4. Performance discovery (2):
    10 Jan 2025 - IOPS vs. IOPS
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}