October 2003 - Posts
The roundtable on Service Oriented Analysis was interesting, because it showed the culture clash between 'Pure Object' guys and 'Service Oriented ' guys.
Martin Fowler was the OO guy and someone from the Indigo team whose name I cannot remember was the SOA guy.
Fowler was quite ironic about SOA. He said he did not know what does SOA mean, and that the meaning changes every 5 minutes. In his mind, SOA was about application integration. If you have a property layered application, then SOA is just adding another layer to adapt the inner interface to the Service Oriented one. Inside the application domain, you will keep using thightly coupled OO classes.
The Indigo guy view was that you can use SOA even inside applications (i.e., inside different teams), and it was a much more pervasive thing. The audience seemed to like Fowler's point of view, as there were applauses after some of his comments.
At least there is agreement that you should not expose your inner object model in the service layer, something that was not at all clear in the times of DCOM and CORBA.
I'm closer to the SOA guys than to the OO guys.
Some information about ObjectSpaces that was given in Luca Bolognese's presentation:
- It is designed to be a thin layer on top of ADO.NET. It's just as ADO.NET but with objects. There isn't an object server and they don't provide caching, so it's not a Entity Beans clone.
- They are targeting a 30/40% performance decrease compared to the DataSet/ADO.NET approach. They are currently 2 times slower.
- One of the usual issues with O/R mappers is that they have to decide how to load an object graph. Using the example from their demo, if you have:
Continent
string Name
ArrayList Countries
Country
string name
Continent continent
if you retrieve one Continent, you could want to load all its countries or not. In ObjectSpaces you can specify a 'span' when you query for Continent that says that you want to retrieve the Country, or leave the span empty to specify that you just want the Continent but no the Country.
The other way to deal with this is to use 'Lady Loading' (which Luca said they'll call 'Delayed Load' because marketing did not like 'Lazy' ;), which means that countries are loaded the first time you access the Continent.Countries property. To do that you need to use a special class for the collection. You cannot use ArrayList, as they need to have a hook to execute the data loading code when you access the property. The same happens if you want to lazy load a field (i.e., the 'continent' field in 'Country')
- They are using reflection to load the fields from the database. It seems in Whidbey there is a feature called 'Lightweight Reflection' that is really fast.
- The first version will support SQL Server 7 -> Yukon. They will provide a way to add support for other Managed Providers in the future.
UPDATE:
Andrew Conrad made some clarifications on the performance issue.
I was really busy during PDC and I did not find time to blog or even to keep up with email (BTW, the DeKlarit booth stuff arrived on Monday afternoon so it was ready for the Exhibit Hall reception).
I'm still in L.A., and while I'm installing Longhorn in my notebook I'll try to put in order my thoughts about this week.
If I have to pick the most important thing, it is, without any doubt, Avalon.
Avalon is really a very big bet. Windows Forms applications and 'smart clients' are really in trouble today. Most of the people is developing web applications, and Avalon is the only chance Microsoft has to keep the smart client alive. And in the long term, the smart client's fate is Windows' fate.
I really like Avalon and XAML. It feels like the right way to build client applications.
Most of the revolutions in the client were really driven by customers demands. Customers wanted to use Windows apps instead of text apps, and we developers had to build them. Users wanted web apps, and we had to build them. Users will want Avalon apps, so we'll have to give them that.
The guy with half the booth is stuck in San Diego, and he will be arriving to L.A. around 2 PM, so it seems the Exhibit Hall will open and our booth will still be unfinished.
This means it will have a very minimalistic design, reflecting that the important thing is the product and not the booth ;)
http://www.bml.psy.ruhr-uni-bochum.de/Demos/BMLwalker.html
I'll be looking at my elbows the next time I walk ;)
Click the 'Lines' button to see it more clearly.
One of the main complains about ADO.NET it's that you cannot write code that is database independent.
There are a number of libraries to accomplish it, and the latest DAAB version also supports it.
I think the designers of ADO.NET acknowledged something that we don't want to: each database engine is different, we will write different SQL code, and we will need different APIs.
The most visible difference is parameter markers. SQL Server native ones are prefixed with '@'. In OleDB we used '?' which required the SQL driver to parse the sentence and change them to '@'. In .NET all the Data Providers use their native parameter markers, so you have ':' for Oracle, '@' for SQLServer/Access, etc.
This implies that is very difficult to write a parameterized SQL sentence that can be database independent. 'SELECT * FROM CUSTOMER WHERE CustomerId = @CustomerId' won't work in Microsoft's Oracle Data Provider even if we are using the generic IDb APIs.
Even if ADO.NET provided a generic API and even if it supported the same parameter markers in each Data Provider, we all know the SQL sentences are different in each database engine. Doing a SELECT * FROM CUSTOMER always works, but when you need to deal with autonumbering, database-specific types (think uniqueidentifier in SQL Server), outer joins, then it's not possible to use the same SQL sentences.
Suppose you _can_ write generic SQL, because you have simple SQL statements that are supported in all the databases you need, or the places where you need different statements are not many.
Then you code:
IDataReader reader = myAbstractCommand.ExecuteReader(“SELECT CustomerID FROM CUSTOMER);
while (reader.Read()) short customerId = reader.GetInt16(0);
And then you run Anakrino, open the OracleDataReader class, and find:
public virtual short GetInt16(int i) {
throw ADP.NotSupported();
}
...
Writing database independent code is a dream. Let's wake up.
I've been playing with Ruby the latest couple of weeks (and I'm not the only one ;).
We are starting a new project and I'm trying to evangelize the rest of the team to use code generation throughout the build process.
While reading Code Generation in Action, I became intrigued about Ruby, as it was used for the sample code. I've been hearing about Ruby from a long time but I was never intrigued enough to learn more about it, and I never had a need for it in my day to day job.
I knew the Pragmatic Programmers had a book on Ruby so I went to their site, and found an online copy of their Ruby book. The intro is enough to get a grasp of it. For a quick intro, go straight to . There is also a full Ruby setup for Windows with all the important libraries and a text editor from where you can run Ruby scripts.
The Code Generation in Action book the ERB template engine is used for the samples, and it's not included in the Windows distribution mentioned above. You can find it in http://raa.ruby-lang.org/list.rhtml?name=erb
I liked Ruby a lot, but I'm still not sure if I should push it inside our team or not.
Below are the CodeSmith/C# template and the ERB/Ruby template to acomplish the same task:
--- CodeSmith / C#
<%@ Property Name="XmlFileName" Type="System.String"%>
<%@ Assembly Name="System.Xml"%>
<%@ Import Namespace="System.Xml" %>
<%
XmlDocument doc = new XmlDocument();
doc.Load(XmlFileName);
string objectName = doc.SelectSingleNode("/UIObject/Name").InnerText;
%>
public class <%= objectName %>
{
<% foreach (XmlNode node in doc.SelectNodes("/UIObject/Members/Member"))
{
string memberType = node.SelectSingleNode("Type").InnerText;
string memberName = node.SelectSingleNode("Name").InnerText;
%>
private <%= memberType %> m_<%= memberName %> <%= (node.Attributes["Initialize"] != null && node.Attributes["Initialize"].Value == "yes")?("= new " + memberType + "()"):""%>;
<% } %>
<% if (doc.SelectSingleNode("/UIObject/DefaultConstructor") != null)
{ %>
public <%= objectName %>()
{
}
<% } %>
}
--- ERB / Ruby
<%
require "rexml/document"
doc = REXML::Document.new File.new(xml_file_name)
object_name = doc.elements["/UIObject/Name"].text
%>
public class <%= object_name %>
{
<%
doc.elements.each("/UIObject/Members/Member") { |element|
member_type = element.elements["Type"].text
member_name = element.elements["Name"].text
%> private <%= member_type %> m_<%= member_name %> <%= "= new " + member_type + "()" if element.attributes["Initialize"] == "yes"%>;
<% }
if doc.elements["/UIObject/DefaultConstructor"]
%>
public <%= object_name %>()
{
}
<%
end%>
}
This generates something like:
public class EditBox
{
private string m_Text;
private EditBoxHelper m_Helper = new EditBoxHelper();
public EditBox()
{
}
}
As you can see, the Ruby code is more compact. Some little Ruby features help you to write less code:
- As it's a dynamically typed language, you don't need to declare variables. I'm not sure if I would use a dynamically typed language for writing a big complex application, but in this case it's more convenient.
- The XML library lets you write element.attributes["Initialize"], and it returns the value, instead of having to ask for the .Value explicitly, so you can write
if element.attributes["Initialize"] == "yes"
instead of
if (node.Attributes["Initialize"] != null && node.Attributes["Initialize"].Value == "yes")
- Expressions that result in a null value evaluate to False in conditions, so you can write:
if doc.elements["/UIObject/Parent"]
instead of
if (doc.SelectSingleNode("/UIObject/Parent") != null)
- The 'if' statement modifier lets me write:
"= new " + member_type + "()" if element.attributes["Initialize"] == "yes"
instead of
node.Attributes["Initialize"].Value == "yes"?("= new " + memberType + "()"):""
- For processing XML, ruby code blocks provide pretty much the same functionality as C# foreachs, so there is no big advantage there.
Even if the code is more compact, I don't feel I have a solid argument to convince our team to move to Ruby. C# skills are more common than Ruby skills, and the improvements are not as big to force the team to learn a new language.
I keep reading comments about being able to 'think in the Ruby way', and I'm sure I still think with my C# head, so perhaps there's a better way to write this in Ruby that will make the differences bigger...
More Posts