The road to Salamanca

To content | To menu | To search

Thursday, July 16 2009

Salamanca 1.0.1 (alpha 2) is released

The second version of Salamanca has just been released : 1.0.1 (alpha 2).

image

Changes from the previous release include :

  • A complete refactoring of the libraries : all the base classes are now grouped together in a single assembly (Data Rules, Data Access and Data Activities), available in 2 editions (.NET Framework and .NET Compact Framework). Additional assemblies are available for the use of external libraries (Enterprise Library).
  • The concept of enumerations has been added to the SDML designer.
  • Many bug fixes.

Note that you will have to uninstall the previous version of Salamanca before installing this one.

There are a few things to be noted about the new enumerations :

  • Enumerations defined in the SDML can obviously be used as data types for entity attributes.
  • Enumerations have an underlying type (pretty much like in C#). This defines how enumerated values will be stored in the database.
  • An enumeration translates into a lookup table in the database (each tuple matching an enumerated value).
  • An underlying value must be provided for every enumerated value (this is optional in C#).
  • The default underlying type for an enumeration is a string (impossible in C#). This allows for the use of mnemonics in the database. Your DBA will thank you for this !

And as a conclusion, here is a short list of features that are planned on our roadmap to a final release :

  • Multi database provider SQL code generation : we should at least be able to generate code for Oracle systems.
  • A first pick at a SAML designer. Salamanca looks a lot like (yet) an (other) ORM framework right now, but this is not all there is to it. The ability to design activities (that may use our entities) will bring huge benefits to developers and will show what our vision truly holds.

But for now, enjoy this release. And any feedback will be more than welcome !

Friday, June 19 2009

New blog in town

imageGood news (if you understand French, that is) : Pierre just opened a new blog about Salamanca today called A bord de Salamanca (and yes, it’s in French). In his first post, he says he will, as a Salamanca user, share his experience about Salamanca (some bad, but mostly good I hope…). He will also share tips and tricks about using it.

Now is thus the time to reconsider the use of our Salamanca feeds. If you were a subscriber to this blog feed (http://feeds2.feedburner.com/noury/salamanca), you will also automatically get updates about the new blog (as well as various Salamanca related links as we gather them around the web). If you only want to get updates about this blog (due to an allergy to French, for instance), a new feed is available at the address http://feeds2.feedburner.com/noury/salamanca/road. Links on the website will be updated soon.

Welcome aboard !

Thursday, March 12 2009

Salamanca 1.0 (alpha 1) is released

Great news today : we just released Salamanca 1.0 (alpha 1) !

image

As promised, this release includes :

  • a SDML designer, and code generation :
    • Domain entities (.NET Framework 3.5).
    • Data mappers (based on Enterprise Library 4.1, .NET Framework 3.5).
    • SQL scripts for tables creation and stored procedures for CRUD access (SQL Server 2005, 2008).
  • Updated libraries, now targeting the .NET Framework (2.0, 3.0 and 3.5) and the .NET Compact Framework (2.0 and 3.5).
  • Complete Visual Studio 2008 integration (via an installer).

There is still a great deal of work to be done, and you should be aware of some limitations for this release :

  • Primary keys for the generated entities are Guids (uniqueidentifier on SQL Server). This cannot be changed.
  • Types for the entities attributes are limited to the following list : bool, DateTime, float, double, int, long, short, Guid and string (by default).
  • Entities can only be linked by one association at a time. This should cover the vast majority of cases though…

You are welcome to play with our brand new Software Factory and give us any feedback about it. I’ll post later about what the future holds for Salamanca.

We hope you will have a pleasant trip !

Monday, February 23 2009

Salamanca in words

It is often said that a picture is worth a thousand words.Wordle: Salamanca How about a picture made of words (click on the image to have a larger view) ?

I just gave this blog the Wordle treatment, and the result is quite cool I think. But the best is that two of the words that stand out the most are '”Data” and “Activity”. These are indeed two concepts that lie at the heart of Salamanca.

Wednesday, January 28 2009

First maintenance release : 0.9.1

We discovered an issue in the current release of the Salamanca libraries (0.9.0) that was important enough to make us deliver a maintenance release : version 0.9.1. You can use these new libraries as a drop in replacement for the old ones.

Note that the issue discovered concerns only the libraries that depend on Enterprise Library :

We previously compiled these libraries against version 4.1 of Enterprise Library, which requires the .NET Framework 3.5. As our libraries were only supposed to target the .NET Framework 3.0 at best, this introduced a very unwelcome dependency. So the new version is compiled against version 3.1 of Enterprise Library, which only requires the .NET Framework 2.0.

As for the next release (1.0.0), these dependencies has been fixed as followed :

  • .NET Framework 2.0, 3.0 targeted libraries : depend on Enterprise Library 3.1.
  • .NET Framework 3.5 targeted libraries : depend on Enterprise Library 4.1.

Did I just write about version 1.0.0 ? Here is in two sentences what is to be expected :

  • updated libraries, now targeting the .NET Framework 3.5 as well.
  • our first SDML designer ! Still limited, but entirely functional, with code generation from SQL to C# entities…

image

Stay tuned !

Friday, December 19 2008

Take the S train

I've got some news just before the holidays :

  • the Salamanca repository just got itself a new (shorter) URL : http://salamanca.codeplex.com/, thanks to the CodePlex guys. The old one (that I won't write here) remains valid.
  • as some of you probably already noticed, Salamanca got itself a logo.

Not so surprisingly, it is a train (the name Salamanca is a reference to The Salamanca, the first commercially successful locomotive built in 1812). The original design for this picture can be found on the Open Clip Art Library.

The streamline design of this engine fits well with the concepts of industrialization that are behind our vision of our Software Factory. And it is also a reference to the excellent Streamlined Object Modeling book. Though our vision of business object implementation differs somewhat from what can be found in this book, their description and analysis of 12 "collaboration patterns" for modeling real-world relationships is an invaluable resource for any person who is involved in modeling activities. As Salamanca users will inevitably be.

Early in the new year to come, you will have the opportunity to exercise your modeling skills on the first version of Salamanca, that will include a SDML graphical designer and code generation. But for now, I've got a train to catch.

Wednesday, October 29 2008

To Salamanca via Oslo ?

Now that our libraries are functional enough, it is high time we started getting into the modeling part of our software factory. The first step is to define proper syntaxes for our s : the Salamanca Domain Model Language (SDML) and the Salamanca Activity Model Language (SAML).

In fact, as a proof of concept, we have already tried to define a syntax for our SDML. Based on XML, it would describe the Domain in terms of types, enumerations, domain elements and associations. Here is an example written in this SDML :

<dml
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.nourysolutions.com/salamanca/DML"
xsi:schemaLocation="http://www.nourysolutions.com/salamanca/DML ../Models/dml.xsd"
>
<serializable name="string">
<native type="string"/>
<sql dbtype="VARCHAR"/>
</serializable>
<serializable name="Boolean">
<native type="bool" nullable="false">
<conversion language="C#">Convert.ToBoolean({0})</conversion>
</native>
<sql dbtype="BOOLEAN">
<conversion language="C#">Convert.ToByte({0})</conversion>
</sql>
</serializable>
<serializable name="Chars">
<native type="string"/>
<sql dbtype="CHAR"/>
</serializable>
<serializable name="long">
<native type="long" nullable="false"/>
<sql dbtype="BIGINT"/>
</serializable>
<serializable name="Date">
<native type="System.DateTime" nullable="false"/>
<sql dbtype="DATE"/>
</serializable>

<enum name="RegionType">
<base name="Chars" size="3" />
<value name="Department" code="DEP">Département</value>
<value name="State" code="STA">State</value>
<value name="Land" code="LAN">Land</value>
</enum>

<domain name="Region" shortName="Regions">
<attribute name="Id" visibility="none" required="true">
<type name="long"/>
</attribute>
<attribute name="Name" required="true">
<type name="string" size="63" />
</attribute>
<attribute name="Type" required="true">
<type name="RegionType" />
</attribute>
<key attributes="Id"/>
</domain>
<domain name="City" shortName="Cities">
<attribute name="Id" visibility="none" required="true">
<type name="long"/>
</attribute>
<attribute name="Name" required="true">
<type name="string" size="63" />
</attribute>
<attribute name="HasPostalOffice">
<type name="Boolean" />
</attribute>
<key attributes="Id"/>
</domain>

<assoc name="RegionCities" association="composition">
<end name="Region" target="Region" multiplicity="1"/>
<end name="Cities" target="City" multiplicity="*"/>
</assoc>
</dml>

Based on this syntax, we would perform numerous transformations (with ) to generate Visual Studio solutions, projects, source files (SQL, C#), resources and even graphical representation of the domain (by driving the excellent Graphviz). But we found several drawbacks to this method :

  • XSLT code is tedious to write and hard to debug.
  • a DSL modification need the manual refactoring of many, hard to maintain files.

And indeed, our code soon became so complex that we had to leave some things out of the generation process, like the implementation of the many to many relationships...

So I started lately to delve into the Visual Studio DSL Tools, armed with my courage, my computer and the appropriate reference. And it looks very promising, though somewhat limited for our grand vision. As Daniel Cazzulino wrote :

The DSL Tools is basically the first step in the road to realizing the full SF vision outlined in The Book. Hence, if you try to build a real-world factory just using DSLs, you will find it fairly incomplete and not supporting typical scenarios such as providing an initial solution structure where you will put your DSLs, etc. The missing features, though, are most probably those that will come (or become unnecessary) as the full vision is implemented. In the meantime, it feels lacking.

Anyway, the first impressions are excellent, and it feels like time invested in designing our DSLs around these tools will be far from being wasted time.

This is how I felt this morning, when I discovered that Microsoft is just starting to communicate about a new product, that they label as a modeling platform, and that is codenamed Oslo. Hear Bill Gates about it :

It's actually taking the kind of models that you're seeing arising in specific domains, like software management in System Center, or your data design over in SQL, or your process activities over in BizTalk and saying, we need to take all these domains and be able to put them into one model space. In fact, we need to let people create their own domains that aren't just isolated, but that exist in this one modeling space. And that's what Oslo is about.

I could not agree more. Salamanca needs to have domain models and activity models in the same modeling space, simply because a business activity is by essence bound to manipulate business objects : a SAML model is linked to a SDML model.

Good Morning, Oslo

So it looks a lot like Oslo could be the best way to go to Salamanca. That is sure going to be a long journey, but very likely to be an interesting one. For now, I am sticking to my DSL Tools.

Thursday, October 9 2008

QuickStart : the Activity

Whereas Data Access could be considered as yet another solution to a very common problem (the ORM problem), Data Activities is quite original in its conception and implementation. The concepts involved here are much less refined or complex, but have already proved to be very powerful.

FindProductListByNameFirst of all, we have to define an activity in terms of questions and treatments. The simplest activity I could imagine is the following :

  • this activity is about getting a list of products that match a specified name.
  • the first state is a question that asks for the name.
  • the second (and last) state is a treatment that finds the corresponding states.
  • let's add to this a rule that specifies that the name we are looking for should not be empty (nor null).

For this activity, we'll reuse the Product class we have defined in the Domain Model quick start. The proper way to implement this would be to add a FindByName method to this class and query the database, but we'll do it the Activity way this time.

An activity manipulates data. We need a class to store :

  • the name of the Product.
  • the list of products matching that name.

There is a base class in the Salamanca.DataActivities that will help us implement the IActivityData interface :

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Salamanca.DataActivities;

namespace QuickStart
{
public class Data:
ActivityData
{
private struct Backup
{
public string Name;
public Product[] Products;
}

protected override object CreateBackup()
{
Backup ret=new Backup();
ret.Name=_Name;
ret.Products=_Products.ToArray();
return ret;
}

protected override void RestoreBackup(object backup)
{
Backup b=(Backup)backup;
_Name=b.Name;
_Products=new List<Product>(b.Products);
}

public string Name
{
get { return _Name; }
set { _Name=value; }
}

public IList<Product> Products
{
get { return _Products; }
set { _Products=new List<Product>(value); }
}

private string _Name;
private List<Product> _Products=new List<Product>();
}

}

You see there is a bit more than just having a Name and a Products property. When inheriting from ActivityData, you have to implement two abstract methods that create and restore backups on the data. We won't really need this system in this activity, but data must implement IBackupable and this is quite straightforward as you can see in the code above.

Our activity will ask a question. This question is going to be implemented in the UI layer (likely via a TextBox on Windows Forms), so we need a way to allow it to plug itself into our activity. We do that via a question factory, as follows :

using System;
using Salamanca.DataActivities;
using Salamanca.DataActivities.UI;

namespace QuickStart
{
public abstract class QuestionFactory
{
public abstract Question AskProductName(IActivityController controller);
}
}

Our question state will need this QuestionFactory (or, rather, an implementation of it). And I anticipate that our treatment state will need a DataMapperCollection as we will retrieve all the products from the database via the Product.FindAll method. These are the dependencies of our activities, and we will group them in a parameter class :

using System;
using Salamanca.DataAccess.Collections;
using Salamanca.DataActivities;

namespace QuickStart
{
public class Parameters:
IQuestionFactoryParameters<QuestionFactory>
{
public Parameters(QuestionFactory factory, DataMapperCollection dataMappers)
{
_QuestionFactory=factory;
_DataMappers=dataMappers;
}

public DataMapperCollection DataMappers
{
get
{
return _DataMappers;
}
}

public QuestionFactory QuestionFactory
{
get
{
return _QuestionFactory;
}
}

private DataMapperCollection _DataMappers;
private QuestionFactory _QuestionFactory;
}
}

We are now ready to create our two states. The first one must implement IActivityInitialState, which is just a marker interface. As a question state, we can simply derive it from the QuestionActivityState base class. The second state just fills our Data with a list of products matching the name that was returned by the question :

using System;
using System.Collections.Generic;
using Salamanca.DataActivities;
using Salamanca.DataActivities.UI;
using Salamanca.DataRules;

namespace QuickStart
{
public class FindProductListByName:
QuestionActivityState<Data>,
IActivityInitialState
{
public FindProductListByName(Data data, QuestionFactory factory, DataMapperCollection dataMappers):
base(data, new Parameters(factory, dataMappers))
{
}

protected override IList<IRule> CreateRules()
{
IList<IRule> ret=base.CreateRules();
ret.Add(
new PredicateRule<FindProductListByName>(
"The name must not be empty.",
new Predicate<FindProductListByName>(
delegate(FindProductListByName s) {
return !string.IsNullOrEmpty(s.Data.Name);
}
)
)
);

return ret;
}

protected override void OnInitialized(ActivityStateEventArgs e)
{
Question=((Parameters)Parameters).QuestionFactory.AskProductName(e.Controller);
base.OnInitialized(e);
}

protected override IActivityState NextState
{
get { return new FindProductListByNameFindProducts(Data, (Parameters)Parameters); }
}
}

internal class FindProductListByNameFindProducts:
ActivityState<Data>
{
public FindProductListByNameFindProducts(Data data, Parameters parameters) :
base(data, parameters)
{
}

protected override ActivityStateResult Handle(IActivityController controller)
{
List<Product> allProducts=new List<Product>(Product.FindAll(((Parameters)Parameters).DataMappers));
Data.Products=allProducts.FindAll(
new Predicate<Product>(
delegate(Product p) {
return p.Name.Contains(Data.Name);
}
)
);

return ActivityStateResult.Next;
}

protected override IActivityState NextState
{
get { return new EndActivityState<Data>(Data); }
}
}
}

Note in the question state how we enforced our business rule (the name must not be empty).

Our activity is ready. Or is it ? What we have here is still an abstraction, and we need an implementation for our QuestionFactory. And that is precisely the magic of it all : we just need a concrete QuestionFactory.

Say, for instance, that we want to test our activity : we need a question factory that automatically provides the Data with test product names and checks the results. Here is an implementation of this question factory :

internal sealed class TestQuestionFactory:
QuestionFactory
{
public TestQuestionFactory(string name)
{
_Name=name;
}

public override Question AskProductName(IActivityController controller)
{
Question ret=new AnsweredQuestion();
ret.Answering+=new EventHandler<AnswerEventArgs>(
delegate(object sender, AnswerEventArgs e) {
((Data)e.Data).Name=_Name;
}
);

return ret;
}

private string _Name;
}

Based on this factory, a test would look like this (there are two products containing Queso in their name in the Northwind database) :

[TestMethod]
public void CanFindProductList()
{
Data data=new Data();
ActivityController controller=new ActivityController(
new FindProductListByName(
data,
new TestQuestionFactory("Queso"),
DataMappers
)
);
controller.Execute();

Assert.IsTrue(controller.HasCompleted);
Assert.AreEqual(2, data.Products.Count);
}

You can see here how an ActivityController is used to execute an activity. As all answers are automatically provided, our activity is executed from the beginning to the end in one phase. In a Windows Forms application, the execution would stop at the question state to let the user fill a text box in. When a Find button would be clicked, the controller would be told to resume the activity execution.

You can find a complete working example, as a Visual Studio 2008 solution, here. The same activity is implemented as a unit test, and as a Windows Forms application (the underlying database is Northwind on SQL Server, for which a data file is included in the downloadable sample).

Tuesday, September 23 2008

QuickStart : the Domain Model

Now that the first release is out, let's start playing with it. The first step is to design our business objects ; we'll eventually have a DSL for this (the SDML), but basic UML will do for now.

Quick Start (UML)We'll begin with a (very) simple model. Sorry, I could not think of anything more simple ;-) Our application will deal with products, whose sole property is their name.

The associated database could be created with the following script :

CREATE TABLE Products (
ProductID INT IDENTITY(1, 1) NOT NULL,
ProductName VARCHAR(40) NOT NULL
CONSTRAINT PRIMARY KEY (ProductID)
);

Now we can create our Data Access Layer. What we need first is a class to handle the primary key for our product. We have a base class for it, in the Salamanca.DataAccess namespace :

using System;
using Salamanca.DataAccess;

namespace QuickStart
{
public class ProductPrimaryKey:
PrimaryKey<int>
{
public ProductPrimaryKey():
base()
{
}

public ProductPrimaryKey(int key):
base(key)
{
}

public static implicit operator ProductPrimaryKey(int key)
{
return new ProductPrimaryKey(key);
}

public static explicit operator int(ProductPrimaryKey key)
{
return key.Value;
}
}
}

Then we need a class to be used as a data holder. More specifically, it will be used as a Data Transfer Object :

using System;
using Salamanca.DataAccess;

namespace QuickStart
{
public class ProductDataTransfer:
IDataTransferObject
{
public object Clone()
{
return MemberwiseClone();
}

public int Id;
public string Name;
}
}

What remains to be defined is our Domain Model and our Data Mapper. To avoid too tight coupling between both, we'll define an interface that will have to be implemented by a product related Data Mapper :

using System;
using Salamanca.DataAccess;
using Salamanca.DataAccess.Collections;

namespace QuickStart
{
public interface IPersonMapper:
IDataMapper
{
Product Find(ProductPrimaryKey key, DataMapperCollection dataMappers);
DomainModelKeyedCollection<Product> FindAll(DataMapperCollection dataMappers);
}
}

For a starter, we'll only need two methods :

  • one to get a specific product instance from the data backend.
  • one to get all the products form the data backend. The DomainModelKeyedCollection returned can be used a regular Collection, as well as a Dictionary where products are indexed with their primary keys.

Now we're ready to define our Domain Model :

using System;
using System.Collections.Generic;
using Salamanca.DataAccess;
using Salamanca.DataAccess.Collections;
using Salamanca.DataRules;


namespace QuickStart
{
public class Product:
DomainModel<ProductPrimaryKey, ProductDataTransfer>
{

public Product():
base()
{
}

public Product(DataMapperCollection dataMappers):
base(dataMappers)
{
}

protected override ProductPrimaryKey CreateId()
{
return new ProductPrimaryKey(Data.Id);
}

public static Product Find(ProductPrimaryKey key, DataMapperCollection dataMappers)
{
return ((IProductMapper)dataMappers[typeof(Product)]).Find(key, dataMappers);
}

public static IList<Product> FindAll(DataMapperCollection dataMappers)
{
return ((IProductMapper)dataMappers[typeof(Product)]).FindAll(dataMappers);
}

internal void SetId(int id)
{
Data.Id=id;
}

[StringLengthRule(40)]
[NotNullRule]
public string Name
{
get
{
Load(true);
return Data.Name;
}
set
{
if (Data.Name!=value)
{
Data.Name=value;
RaisePropertyChanged("Name");
}
}
}
}
}

As you can see, this is quite straightforward : just inherit from Salamanca.DataAccess.DomainModel, override CreateId and add your properties. The static methods have just been defined here for convenience. Also, note the attributes above the Name property, that define our first business rules.

Final step : define a Data Mapper for our product. We'll choose the ADO .NET based abstract implementation that is found in the Salamanca.DataAccess.Data namespace as a base :

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using Salamanca.DataAccess;
using Salamanca.DataAccess.Collections;
using Salamanca.DataAccess.Data;

namespace QuickStart
{
public partial class ProductMapper:
DataMapper<Product , ProductDataTransfer ProductPrimaryKey>,
IProductMapper
{
public ProductMapper(DbConnection connection, ICacheManager cacheManager):
base(connection, DomainModelCreator.CreateDefault<Product>(), cacheManager)
{
}

public DomainModelKeyedCollection<Product> FindAll(DataMapperCollection dataMappers)
{
IDbCommand[] commands=new IDbCommand[1];

commands[0]=Connection.CreateCommand();
commands[0].CommandType=CommandType.Text;
commands[0].CommandText="SELECT ProductID, ProductName FROM Products";

return Load(commands, dataMappers);
}

protected override IList<IDbCommand> CreateSelectCommands(ProductPrimaryKey key)
{
IDbCommand[] commands=new IDbCommand[1];

commands[0]=Connection.CreateCommand();
commands[0].CommandType=CommandType.Text;
commands[0].CommandText="SELECT ProductName FROM Products WHERE ProductID=@Id";

IDbDataParameter p=commands[0].CreateParameter();
p.ParameterName="@Id";
p.DbType=DbType.Int32;
p.Value=key.Value;
p.Direction=ParameterDirection.Input;
commands[0].Parameters.Add(p);

return commands;
}

protected override IList<IDbCommand> CreateDeleteCommands(ProductDataTransfer data)
{
IDbCommand[] commands=new IDbCommand[1];

commands[0]=Connection.CreateCommand();
commands[0].CommandType=CommandType.Text;
commands[0].CommandText="DELETE FROM Products WHERE ProductID=@Id";

IDbDataParameter p=commands[0].CreateParameter();
p.ParameterName="@Id";
p.DbType=DbType.Int32;
p.Value=data.Id;
p.Direction=ParameterDirection.Input;
commands[0].Parameters.Add(p);

return commands;
}

protected override IList<IDbCommand> CreateInsertCommands(ProductDataTransfer data)
{
IDbCommand[] commands=new IDbCommand[1];

commands[0]=Connection.CreateCommand();
commands[0].CommandType=CommandType.Text;
commands[0].CommandText="INSERT INTO Products (ProductName) VALUES(@ProductName)";

IDbDataParameter p=commands[0].CreateParameter();
p.ParameterName="@Name";
p.DbType=DbType.String;
p.Value=data.Name;
p.Direction=ParameterDirection.Input;
commands[0].Parameters.Add(p);

return commands;
}

protected override IList<IDbCommand> CreateUpdateCommands(ProductDataTransfer data)
{
IDbCommand[] commands=new IDbCommand[1];

commands[0]=Connection.CreateCommand();
commands[0].CommandType=CommandType.Text;
commands[0].CommandText="UPDATE Products SET ProductName=@Name WHERE ProductID=@Id";

IDbDataParameter p=commands[0].CreateParameter();
p.ParameterName="@Name";
p.DbType=DbType.String;
p.Value=data.Name;
p.Direction=ParameterDirection.Input;
commands[0].Parameters.Add(p);

p=commands[0].CreateParameter();
p.ParameterName="@Id";
p.DbType=DbType.Int32;
p.Value=data.Id;
p.Direction=ParameterDirection.Input;
commands[0].Parameters.Add(p);

return commands;
}

protected override ProductDataTransfer GetDataTransferObject(IList<IDataRecord> records)
{
ProductDataTransfer data=new ProductDataTransfer();

int ord=records[0].GetOrdinal("ProductID");
if (!records[0].IsDBNull(ord))
data.Id=records[0].GetInt32(ord);

ord=records[0].GetOrdinal("ProductName");
if (!records[0].IsDBNull(ord))
data.Name=records[0].GetString(ord);

return data;
}

protected override void OnInserted(Product domainModel, IList<IDbCommand> commands)
{
IDbCommand command=Connection.CreateCommand();
command.CommandType=CommandType.Text;
command.CommandText="SELECT @@IDENTITY";
command.Transaction=commands[0].Transaction;

domainModel.SetId(Convert.ToInt32(command.ExecuteScalar()));

base.OnInserted(domainModel, commands);
}
}
}

That's it : derive from DataMapper and fill the gaps with pure ADO .NET code. You can already understand that this is where code generation will greatly improve the developer productivity.

Our Data Access Layer is now complete : we can build a simple application based on it. The only (?) tricky thing is that you will need to create an instance of DataMapperCollection. For our sample, simply use this code :

DataMapperCollection _DataMappers=new DataMapperCollection();
_DataMappers.Add(typeof(Product), new ProductMapper(Connection, new NoCacheManager()));

It creates a new collection based on a prexisting Connection, and our data is simply not cached in memory.

You can find a complete working example, as a Visual Studio 2008 solution, here. As you can see, we can build a simple application that integrates our Domain Model in a very few lines of code, with business rules validation (the underlying database is Northwind on SQL Server, for which a data file is included in the downloadable sample).

Quick Start Sample

Next time, we will create our first activity. Stay tuned !

Tuesday, September 16 2008

First public release

Today is the day when Salamanca hits its first public release, tagged 0.9.0. You can download it here.

This first release consists of the binaries for the three sets of libraries (Data Rules, Data Access and Data Activities), for the three following environments :

  • .NET Framework 2.0
  • .NET Framework 3.0
  • .NET Compact Framework 2.0

There is also (some) documentation with (some) sample code. Work on this matter is obviously still in progress, but you can find more complete sample code in the source code. Check for the Northwind  projects, that are used for our unit tests, based on the Northwind sample database. They are quite complete at this stage and are used to demonstrate what generated code could look like.

The future looks bright, and there is a lot of very interesting work to be done (most of which has already been introduced in this blog). The following list is unordered and incomplete :

  • Migration to Visual Studio 2008, and .NET Framework 3.5 compatibility.
  • Unity integration.
  • LINQ integration.
  • JSON serialization.
  • ASP .NET AJAX integration.
  • WPF integration.
  • A Domain Model designer, an Activities designer, and related code generation, the whole thing being integrated into Visual Studio : a true and real Software Factory.

If you want to hit the road with us, you are more than welcome. For the time being, Salamanca has never been so close. Olé!

Monday, September 8 2008

Inside the libraries (III) : Data Activities

Data Activities defines the base classes that help us implement our architectural pattern, centered around business activities. All the concepts developed in this context owe a lot to the vision and the ideas of Yves Darmaillac.

We define an activity as a part of a business process. All the business process parts that are involved in a business application define this application activities. An activity is a , comprising two kinds of states :

  • treatment states : those require no external data (think user interaction). For instance, a treatment state can perform an action on our domain model (create a new reservation), or directly on the data (calculate booking fees). All a treatment state needs to perform its action is data.
  • question states : those do require external data. For instance, a question state can ask for data for a domain model instance (fill reservation details), or it can ask for a specific domain model instance (pick up your seat). Usually, a question is answered via user interaction (but not necessarily, like in the case of unit tests where answers can be automated).

The golden rule here is to make sure that all the application behavior is defined in terms of activities. Treatments are by definition self-sufficient and generic. Questions define abstractions that have to be implemented by the HMI layer. In effect, such abstractions can be implemented by all kinds of presentation technologies (console applications, Windows Forms, ASP .NET, WPF...) with no impact on the business logic.

BasicsThe fundamental interfaces defined in this library are :

  • IActivityState is an interface implemented by an activity state, and treatment states in particular. IQuestionActivityState is a specialization that is implemented by a question state.
  • IActivityData is implemented by an activity data holder type : it holds the data that is manipulated by a specific activity.
  • IActivityParameters is implemented by an activity parameters holder type. An activity parameter could be seen as an immutable activity data.
  • IActivityController is implemented by an activity controller. Such a class is essential to the activity execution : it initiates the activity, terminates it and controls all the state transitions in between.

All the states must be validated before transition : this is achieved via the integration of Data Rules. The library defines base implementations for all these interfaces, and helpful classes to implement questions in specific presentation technologies (so far Windows Forms and ASP .NET).

Activities are at the core of our architecture : they manipulate data and act as a separation of concerns between the business logic and the presentation. In the future, we will be able to design our activities via our own DSL (SAML), and have base implementations (and best practices) for questions in other technologies such as WPF or ASP .NET AJAX.

I would like to finish with an analogy that might confuse some readers, but hopefully enlighten others : imageI like to think of a business activity as a RNA translation process, which is part of the protein biosynthesis. The elements involved in this process are :

  • a mRNA template. It holds the code for a specific protein. This code has a start and an end, and has to be followed in order. This is our finite state machine, each codon being seen as a state.
  • a ribosome. This is the protein "factory". It "reads" the codons one by one and performs an action on each of them : add the corresponding amino acid to the chain that will become our protein. This is our activity controller.
  • the protein. This is the result of the entire process. This could be seen as our data.

Monday, September 1 2008

Inside the libraries (II) : Data Access

This one is simple : Data Access is an (ORM) library. As such, it owes a lot to the experience of NourY Solutions in the field of data management. But our ability to structure this experience and put it into words has been greatly enhanced by the remarkable work of Martin Fowler. Many concepts in use in this library are described in his book Patterns of Enterprise Application Architecture.

There are many .NET ORM libraries out there. As evoked before, we don't believe "one size fits all" applies when it comes to ORM ; the mismatch between the object world and the relational one is so huge that it can only be solved by specific solutions under specific sets of constraints. Data Access has been designed with these constraints in mind :

  • integration with Data Rules.
  • easy serialization of business object instances (XML for use in Web Services, for Ajax applications...).
  • persistence backend abstraction : business objects should easily be persisted against any database backend, like a standard RDBMS solution (Sql Server, Oracle, SQLite...), or a web service, or even a flat file.
  • the developer always has to be in control : for instance, no on-the-fly SQL generation (though this could be added later as an option).
  • easy code generation (we want to build a Software Factory, after all !).

This library is organized around 4 interfaces :Basics

  • IDomainModel : is implemented by a . There is also an abstract class (DomainModel) that can be used as a base implementation for your business objects. It provides Data Rules implementation, serialization, and UI integration (through the implementation of the standard IDataErrorInfo, IEditableObject and INotifyPropertyChanged interfaces).
  • IDataMapper : is implemented by a Data Mapper, which basically provides the persistence backend abstraction. The library provides base implementation for persistence based on standard ADO .NET, Enterprise Library Data Access Application Block or Web Services.
  • IDataTransferObject : this interface is implemented by a Data Transfer Object. It is used to hold the data of a Domain Model, to transfer it between a Domain Model and a Data Mapper and to serialize our Domain Models.
  • IPrimaryKey : is implemented by custom Identity Fields types.

A DSL to design our Domain Models would look a lot like a class diagram. And it does actually ;-) (more on that later).

Our plans in the future for this library are :

  • Unity integration.
  • Ability to serialize trees of objects.
  • JSON serialization.
  • Powershell integration.
  • SSIS integration.

Next time will be the time to introduce Data Activities.

Tuesday, August 26 2008

Inside the libraries (I) : Data Rules

Now is the time to delve a bit more into the libraries that lie at the core of our factory. On top of them lie Data Rules.

First of all, note that this library owes a lot to the work of Paul Stovell, and that most of the concepts discussed here can be found in this article of his.

So Data Rules is a validation framework. The goal here is to handle invalid data in your custom types a bit like DataSet does : instead of throwing an exception every time invalid data is affected to it, it records whether the data it is containing is valid or not; and if not, why. This allows for much smoother UI integration (that is what ErrorProvider and IDataErrorInfo are all about).

This library is organized around 2 interfaces :Basics

  • IValidatable is here to help the developer define a custom type that has such a behavior. A validatable type is one for which any instance can be validated against a specified set of rules. In Data Access, our business objects are validatable : you can always know whether data is valid or not, and why. And if you try to persist an invalid business object, you will get an exception.
  • IRule is an interface implemented by a validation rule. A rule can be specific to a property of your custom type (is it null ?), or not (for rules that involve many properties for instance). The description of a rule contains a message that can be displayed to the end user (like "This field is required").

The library predefines a set of useful rules (like NotNullRule, StringLengthRule, RegexRule...). These rules can also be specified as attributes. And there is an adapter that allows to integrate the Enterprise Library Validation Application Block in Data Rules.

As previously stated, Data Rules is used by Data Access to add validation capability to our business objects. It is also used by Data Activities to enforce business rules in our data flow.

In the future, we can imagine to create our DSL to design our rules, and why not store some of them in a configuration file.

Next time, I will try to summarize the vast subject of Data Access.

Wednesday, August 20 2008

Visiting Salamanca

Fundamentally, Salamanca is designed around three sets of libraries :Architecture

  1. Data Access is the easiest to explain in a few words : think of it as (yet) an (other) (ORM) library. Why another ? We believe that there is not nor will ever be a perfect solution for this problem ; call us "ORM limitations acceptors". Our belief is that an ORM solution has to be designed to fulfill a specific set of issues under a specific set of constraints (which definitely sounds like a product line to me). After all, if you want to go around and around in circles without going anywhere, you are more likely to win the race with a formula one car. If you want to drive home, you will be better off with a standard commercial car : it has been designed for average roads, and priced accordingly. This library will help us handle business specific data in a (DAL).
  2. Data Activities is a library that helps define the business data lifecycle into a specific layer. The latter is a which lies at the core of our architecture : it manages business data, drives the HMI, and as such acts as a perfect (?) .
  3. Data Rules is a validation framework. It will be used to implement our business rules in our activities transitions and our data.

These libraries represent the fundamental abstractions around which our applications will be built. Best practices can be documented around their use, that can be written with our own (DSLs). We have defined two DSLs so far :

  1. SDML (Salamanca Domain Modeling Language) : this language will help us structure our data in order to implement our DAL. But more than that, it will help us create reusable states for our activities, or reusable component for data edition (user controls in Windows Forms for instance). Its representation is very close to a UML Class Diagram.
  2. SAML (Salamanca Activities Modeling Language) : this will help us define our activities. Activities reuse concepts defined in a SDML model. Its representation is inspired by the (BPMN).

Implementing an application with our libraries once the models are properly defined should be quite straightforward. So straightforward that we will be gain a lot by creating two tools that will greatly enhance our productivity :

  1. A Modeler : a graphical tool that will help us visually model our application and serialize it in SDML and SAML formats.
  2. A Generator : a tool that will implement our best practices and take our model as input, in SDML and SAML formats, and generate our C# code. Though it is imaginable to generate a whole functioning application, the developer will have the possibility to customize the generated code to make it more usable, or implement parts that could not be modeled. Usually, developers will ... develop a usable HMI on top of the generated code.

As for now, the libraries are quite in an advanced state, the DSLs definition is in progress and the tools are part of our to do list.

Monday, August 4 2008

Getting on the tracks

So, if Salamanca is a software factory, what is the product line associated with it? The answer is simple : business applications.

Alright, I think I can be more specific than this. In our context

a business application is a software that handles business specific data while implementing parts of business specific processes (which we will call activities) and enforcing business specific rules.

There are a few things we can infer from this definition :Hotel Du Nord

  • to handle business specific data, we will deal with a database backend ; more often than not a real like Sql Server or Oracle, but also possibly a web service or even a simple file (XML, CSV...). For instance, a hotel room booking application would be built upon a proper database, with structured data such as the rooms, their rates, their vacancies...
  • the data lifecycle has to be integrated into well defined activities. At all times, from the state that we know the system is in, there are only a few well known actions that can be taken. Without this concept, an application like Excel would fit into our definition. For instance, a basic activity involving a hotel room and a customer would be : book, then check in, then check out.
  • rules must be enforced at all times. Some of them are specific only to some piece of data, some others can be also specific to  a specific activity. For instance, a booking date in the system cannot be anterior to the date the hotel was built : this is a general rule. But for new reservations, the same booking date has to be in the future : this is a rule that applies to the same data, but that is specific to the activity called "book a room in the hotel".

Our vision with Salamanca is to be able to design a business application in terms of data, activities and rules and be able to generate a complete and functional (if not user-friendly) software.

But we also want to leave the developer at the center of our factory. There are many libraries and tools (think of code generators) out there in the field that work very well, provided you respect their predicates (data structure, software architecture...). But in real life, you almost always have to adapt your code to business specific conditions : already existing databases, specific procedures, architecture... Applications built with Salamanca must be open to adaptations by developers. Think only of the : would you use a software exclusively designed by automated tools ? I know I would not.

Through the concept of activities, which I will elaborate on more in another post, we also created a new way to clearly separate the concerns of presentation from the core application, which we found to be very promising so far. Once created the core of your business application (data handling, activities and rules), you could develop your HMI layer in any (.NET related) technology you like : Windows Forms, Windows Presentation Foundation, ASP .NET... Or in all of them. Or, maybe wiser, you could develop part of your application as an ASP .NET application, and part of it as a Windows Forms application (on Windows TabletPC or Windows Mobile for instance), while reusing the same set of core libraries with your business specific data, activities and rules.

I really hope I made you want to know more about it. In future posts, I will talk about our libraries, our models and our tools. Stay tuned !

Tuesday, July 29 2008

A first glimpse of Salamanca

Welcome to the team blog of Salamanca!

Salamanca is a business applications software factory. The goal is to enable developers to create business oriented applications in a more efficient, reliable and coherent way through a specific set of libraries, models and tools. To make it short, we define a business application as a software that handles business specific data (you can think of it as a low scale enterprise application). Salamanca is designed to help managing the whole life cycle of business data : storage, display, edition, validation, processing... More on that later.

Salamanca is an open-source project, hosted on CodePlex. Its name is a reference to The Salamanca, the first commercially successful locomotive built in 1812.

We are delighted to have you on board, and we hope we will have a pleasant trip together ;-)