Archive for May, 2009
A WPF - IronRuby Scripting Console User Control
One of the clear value added possibilities with IronRuby and IronPython (or any DLR language) has to offer is making applications scriptable. This opens the possibility for enabling scripting of your application, it’s types and potentially objects running in memory in your application at runtime. I recently went looking for an IronRuby console / shell window control written natively in WPF and turned up nothing. I did however come across some examples implemented for Windows Forms and the one that got my attention was Orion Edwards Embedded IronRuby Interactive Console.
Whilst Orion’s project provided the basis of what I was after, I was under no illusion that I would find exactly what I was after and would therefore have to build out the rest of the functionality I required.
The Basic Requirements List
- Reusable WPF User Control
- The Console should allow users to write script against in memory objects of the host application.
- Should persist (to a log) the state of variables in the IronRuby runtime scopes.
- Extensible Application Design and easily maintained and Testable.
So rather than re-invent the wheel I started out with Orion’s code and worked it into a WPF User Control that followed the MVP pattern. This version supports printing of all scope variable state to the console window, clearing of the console window text and all the out of the box access to the IronRuby runtime from the console itself. The IronRuby Console User control also allows the consumer application to pass through in memory variables from your managed CLR hosting application.
Finally I need to also make mention that some of the classes used to stream the STD/IO came directly from Ben Halls wonderful IronEditor. And before I forget, the code can found here on my blogs subversion repository.
3 commentsHigh functioning autistics don’t work in vacuums
I had the pleasure of recently listening to one of the most entertaining podcasts I have heard in a while where Scott Bellware was the guest in question. Scott is a captivating speaker and always prompts you to challenge your own beliefs and ideas as a developer. The podcast was intended to be centred around a discussion on BDD however Scott points out that he practices “Context Specification” and that it differs somewhat to BDD.
Something that has stayed with me in the weeks passed since listening the to discussion, is Scott’s description of developers as ‘high functioning autistics’. The context in which Scott makes the observation is one where he expresses a desire for developers to speak more fluently in the language of the business and desist in articulating implementation details or information of no business value. I’m sure that most people will find that idea logical and reasonable (as I do) however I feel that it’s worth throwing some attention onto the business and how it communicates in the reverse direction.
Any relationships success relies on the mutual respect and determination of all parties to participate in functioning cohesively to achieve a common goal. Yes developers should aim to achieve communicating more effectively with the business but it should be said that business people must take an equal position of responsibility for the success of communication between the parties. I’m pretty sure that most developers have worked in environments with little structure or discipline, where ad-hoc is the methodology of the day and expectations are generally unreasonable. I am sorry to say that I have seen developers purposefully communicate in an abstract way with business people, in an attempt to shield themselves from the kind of environment I just described.
I find it curious that we even speak of ‘developers’ and the ‘business’ as separate entities almost as though they exist in different dimensions; surely we developers work for the very same business as do those in HR, Sales or Warehousing? By definition we must also be considered part of the business. Seriously though, I understand the distinction when we speak about ‘software’ and the ‘business’ in terms that express a notion of separation, but I guess I am starting to think that it’s a consequence of the inadequacy of language that helps in promoting exactly some of the problems that Scott wants to see eradicated.
I think it’s worth making the observation that whilst developers should take responsibility for themselves in communicating more effectively across the organisation they serve, it’s incumbent on all parties to create environments designed for successful communication that travels in all directions. There have been plenty of occasions where I have seen ‘business people’ behave in a fashion that demonstrated a lack of respect and understanding of those sitting on the IT side of the fence. Respect is a two way street.
2 commentsEntity Framework, Fluent Interfaces & Domain Specific Languages
I have been giving some thought lately to how we might go about writing a small internal DSL for reporting on and or editing data in database. Immediately I thought about how LINQ (a DSL in its own right) might play it’s part in this and since we are talking Data, then the Entity Framework came immediately into consideration. Why should we have a DSL for accessing Data? It’s a commonly held opinion that SQL is a DSL for that very purpose, albeit a very general purpose DSL and LINQ is certainly a DSL.
Let’s consider the workers of the Northwind Trading company as an example of some possible beneficiaries to such a Data Centric DSL modelled around a specific business. Of course workers at Northwind have MS Access and SQL Server GUI tools (often called Graphical DSL’s), to help design their queries.
A snippet
So what would our Northwind language look like? Given that we set up from the start to consider an internal DSL, I have chosen to use C# to implement this “little language” (very little) and we will use a fluent interface to accommodate our design. A query might be expressed like this:
public void Do() { var custs = NorthwindLang .Customers .WithOrdersShippedFrom(“Germany”) .That() .Are() .OlderInYearsBy(5); }
The Language
public static class NorthwindLang { public static Customer[] Customers; private static NorthwindEntities ctx = null; public static Customer[] WithOrdersShippedFrom(this Customer[] customers, string country) { ctx = new NorthwindEntities(); var customers_and_orders = (ObjectQuery<Customer>) from c in ctx.Customers.Include(“Orders”) where c.Orders.Any(o => o.ShipCountry == country) select c; Console.WriteLine(customers_and_orders.ToTraceString()); customers = customers_and_orders.ToArray(); customers.ToList() .ForEach(c => c.Orders.ToList() .ForEach(o => { if (o.ShipCountry != country) { ctx.Detach(o); }})); return customers; } public static Customer[] That(this Customer[] customers) { return customers; } public static Customer[] Are(this Customer[] customers) { return customers; } public static Customer[] OlderInYearsBy(this Customer[] customers, int years) { var years_ago = DateTime.Now.AddYears(-years); var newOrds = new EntityCollection<Order>(); var coolFunc = new Func<IEnumerable<Order>, EntityCollection<Order>>(o => { newOrds = new EntityCollection<Order>(); o.ToList(). ForEach(ord => { ctx.Detach(ord); newOrds.Add(ord); }); return newOrds; }); var filtered_customers = from c in customers let neworders = (from o in c.Orders where (o.ShippedDate.HasValue) && (o.ShippedDate.Value < years_ago) select o) select new Customer() { CustomerID = c.CustomerID, CompanyName = c.CompanyName, Orders = coolFunc(neworders) }; customers = filtered_customers .Distinct() .ToArray(); return customers; } }
Problematic
Something worth noting about the OlderInYearsBy() method is the projection taking place with the Orders property assignment for each new Customer entity projected in the queries select clause. You can see that we are “projecting” the orders that match the criteria into the customers Orders collection, however as they have already been fetched from the Database and are attached to an ObjectContext, we need to detach them so they can be referenced by a new Customer Entity that is being returned in the array of Customers produced by the function. Also, you may have observed that we are working with extensions to Customer arrays and not EntityCollection<T> where T is of type Customer, further to that, the code presented is filtering data selected from method calls higher up the call chain of the fluent interface and their is nothing stopping a user from composing a query that does not work with the assumptions present in the fluent interfaces design, and consequently the behaviour may not be as expected. Another issue with this approach is grammar and creating sentences that make little sense and don’t adhere to the DSL’s intended use or rules.
public void Do3() { var custs = NorthwindLang .That() .OlderInYearsBy(15) .WithOrdersShippedFrom(“Italy”) .Are() .That() .OlderInYearsBy(15); }
Where to from here?
I want to follow up with a post on how to achieve similar outcomes using a functional approach and building compound queries using lambda expression that have been joined together with the logical & and | operators. A perfect candidate for this requirement is (dare I say it) the specification pattern. What I hope to achieve with this more functional approach is to be able to compose sentences of intent that build our query so that it can be submitted as one single SQL query. The issue of grammar still remains a problem and I have considered previously that a graphical designer that sits in front of a fluent interface might offer a solution and offer some options with respect to constraining the use of the fluent interface. Consider a UI design surface built with the VSX DSL tools that sits on top of our NorthwindLang fluent interface. Anyway we shall see where this journey takes us!
One final thing
I don’t recommend using an ORM for reporting purposes. The scenario under which this idea was proposed (rather envisioned) was one where the database in question is a constantly renewed small set of data that is exported from an enterprise Document Management System and it’s purpose is to provide an offline view of partitioned data relevant to a consultants work for a given client. This precludes the requirements from having to deal with issues such as concurrency, given that each instance of this database is usually single user in the most literal sense.
2 comments







