Saturday, April 29, 2006

UI Design: Edit then List vs List then Edit

Today I was thinking about the way I build UIs (List then Edit) and the way most people I know build UIs (Edit then List) and the relation that the way you build you UI has with the way you store the data you manipulate in you UI.

List then Edit

In this "pattern" for UI structure, after the user selects an option in the menu he sees a window that allows searching with some controls (generally in the top of the window),and with some control in the bottom that represents the search results, then the user selects one of the search results (an object, or row if you prefer) and he proceeds to work (edit, modify) it, for that he opens a new window "the editor" (perhaps by double clicking the selected object, perhaps by clicking an "edit" button in the list window) in the editor he may modify the object being edited as much as he likes, and then click "save" if he wants to commit his changes or "cancel" if he wants to rollback them.
If the user wants to create a new object, the list has a "new" button that also calls the "editor" so that the user can set the initial values for the fields before the object is committed to the database for the first time

Edit then List

In this other "pattern" for UI structure, after we select an option in the menu we are right there in the editor, but all the controls that could allow us to modify the current object (or row) are disabled, because we haven't searched for any (or created a new one) from here the user can choose to create a new object that action has the effect of enabling all the control in the editor, or search for an already persisted object (or row) by clicking the "search button", that shows the search "list" window, in the top of that window there are controls to configure the search criteria, and in the top a control to represent the search results, from here the user can choose one of the search results (an object or row), and click on the "accept" button, which takes him back to the editor that now is displaying the previously selected object, here the use may choose to make some changes and click "save", or just cancel click "cancel" but actions have the effect of disabling the controls in the editor UI until the buttons "search" or "new" are used again.


Edit in List
When an application generally follows List the Edit, sometimes, if the info in the selected object is very simple, the user may modify it right there, but for for objects with medium to complex (several fields, to one or to many relations with other objects) calling a window to modify the object is more comfortable for the user

Search (List) in Editor
Some times, the developer likes to use the same UI to Edit and to Search, this works like some kind of "query by example", that is when user enters the editor, instead of being disabled an waiting for a click on the "new" or "search" button, the controls are enabled, and if the user writes some data in to them and clicks "search" the already persisted object (or row) that is more similar to the partial information already written in the editor is loaded. Sometimes there are many objects that match the query by example, here is when a navigator control can be a nice thing to have.

Master List, Detail Editor
This is also a very common configuration, both the list and the editor are in the same window, the list generally in the top, and the editor in the bottom, I think this somewhat corresponds with Two Panel Selector.

Persistence
Okey, until now I have exposed what I think are the some of the common "patterns" used to create UIs that manipulate data, now... what I find more interesting about this is the the way this "patterns" affect the way the data is stored or retrieved from persistence:

  • If we use Edit then List:
    • The Edit is displayed on the screen
    • The user clicks "search" and the search List window appears
    • The user configures the search criteria in the List window
    • The objects (or row) matching the criteria are shown in the List window
    • The user selects one of the matching objects and click in the "accept button" in the List window
    • We return to the Edit window, that now is displaying the selected object.
    • We can make changes to the current object by clicking "save" or click "cancel" to dismiss the changes, if we do either action the Edit controls are disabled and we again have to click "search" or "new" to work with an object
    • The problem here, is that the user might want to see the same search results he used the last time, but each time we call the search List window, we are creating a new object, and all of the configuration from the last time we called it is already lost (this disadvantage has a "nice side", because we don't have to worry about showing "stale data" to our user)
    • Another disadvantage is that maybe not all the controls we use to manipulate the data in the edit windows are "databindable" so we have to manually reset the state of the Edit window, and if we don't do it correctly we could have bugs that "transfer information between edits". (First I edit John and set his age to 24, then I edit Mary, and her age is also shown as 24, but her age is 56, and we had no intention of changing it, it happened because we forgot to clear the text-box value)
  • If we use List and then Edit:
    • The list is displayed on the screen
    • The user configures the search criteria in the List window
    • The objects (or row) matching the criteria are shown in the List window
    • The user selects one of the matching objects and click in the "edit button" in the List window.
    • The "Edit" window appears on top of the List window, and is displaying the selected object.
    • We can make changes to the current object by clicking "save" or click "cancel" to dismiss the changes, if we do either action the Edit window is closed and we return to the List window
    • One of the advantages of this approach is that we don't have to worry about the "transfer between edits" bug, because each time we call the Edit window, it is a new window, without any data, ready to configure itself to match the data contained in the object we are going to edit.
    • Then problem of keeping the search results to reuse them is also automatically solved, because the search List window was never closed, it was there all time, behind the edit window.
    • But the problem now is that some of data shown there may not be updated, or perhaps, it has data that has never been on the database, and that we do not want on the database, how can that be? well, we edited the object in the edit window, and the databinding ensured that the changes were written to the object before we clicked "save" or "cancel", if our intention is to keep those changes and we clicked "save" in the Edit window then we don't have a problem... but if we clicked cancel, now we need to rollback in memory changes and some of this changes could have modified relationships with other objects, or properties of the other objects, we could have created, deleted or updated a complex graph of objects but "only in memory" and now, we need to rollback all this changes, if we are using an Object Relational Mapper (ORM) that supports this (like Apple's EOF) or a relational cache that allows for in memory transactions (like the .NET DataSet) we can solve this problem easily (of course the DataSet has other disadvantages), but if we are using an ORM like NHibernate that AFAIK does not rollback in memory changes then you have a problem, you have to re-fetch the information from the database.

This seems like a big omission from the NHibernate guys... but it isn't exactly so, everything I have exposed here, has been on the assumption that we are working in a "Smart-Client" that holds local information, and Hibernate was born in "the web world". In the web, you "need" to re-fetch the information on each request (so when you go from editor to list or from list to editor you always reload the data) and you don't really pass the object you are going to edit from the list to the edit, it easier, and more efficient to just pass the primary key, of course the problem there is that you can only do that with objects previously persisted in the database, if you object is new it has to be serializable and some times that just isn't advisable (but that is an issue for another discussion)...

The thing with web based application is that the controls in the UI don't actually store the information directly in your object, their store it in the view-state, or in the query-string, in cookies, in the session or in an object that "represents the form", and only when you finally want to save, you extract the information from the web-controls and write it in to your object (at least that is more/less was the way I did it in the Java servlet world) but this is a "feature" that might be going away... the problem is that with the new JSF databinding, or with the new databinding facilities of ASP.NET 2.0, you can actually bind you controls directly with you datasources... and then how will we rollback the in memory changes? should we build a framework on top of NHibernate, a kind of "in memory object context" that handles the commits and rollbacks in memory?

More Questions

  • And what about the case when a list window calls an edit window that has an embedded list control that calls another edit window? (complex multiple level or nested interfaces) should the object relational mapper make it easier for me to build this kind of UIs?
  • Or Should a new kind of framework deal with the problem of communicating the persistent objects with the UI?
  • is using DTOs really the solution? Does Apple's EOF go beyond the responsibility of an ORM by providing in memory transactions?
  • If NHibernate can almost transparently persist objects to the UI, shouldn't this other framework be able do the same and transparently present the object in to the UI without having to manually create objects to do this job?

    I am thinking about publishing this post as an article in the Wikipedia to see how it evolves... I would love to read some comments about this article to improve it.





Monday, April 24, 2006

User Interface Process Application Block V3 (Unofficial)

I have created "my proposal for V3 for the UIP" (Microsoft seems to want that we all change to the Composite UI framework... while I agree it is amazing and superior in many ways, I miss some features of the UIP, like the Navigator or ASP.NET support, my final goal would be to make UIPv3 a kind of "module" for the CompositeUI AppBlock that make it easier to migrate UIPv2 to .NET 2.0 and brings the advantages of the ObjetBuilder IoC to ASP.NET)

Okey, okey, what did I uploaded? Unoficial UIPv3 Alpha1 includes the bugfixes from hswami , my last version for the UIP.Attributes, separation of the UIP internal logic in layers (Common, Factories,UIProcess (Core) & Attributes), replacement of weakly typed Hashtable an HybridDictionary with strongly typed Generic<> Dictionary and other minor bugfixes here and there.

This is just the first step, IMHO the main problem with UIP internal architecture was that it was not layered, so changing the way objects were created in a centralized way was hard... for the next release (Alpha2 probably next weekend) I will integrate the new Factories layer with the ObjectBuilder and replace internal ArrayLists with strongly typed generics....

Friday, April 14, 2006

Dynamically Loading Assembly for MSBuild Task

For a task that has to analyze an assembly using reflection (in this case
a task to export the hbm.xml or the Sql from an assembly with Plain Old .NET Objects
using NHibernate.Attributes)
one has to be able to load and unload the assembly dynamically (without that, it is
impossible to "build" two times the solution , because the first build will "block" the
assembly with the annotated Plain Old .NET Objects)
So, first I tried with loading the assembly using the Reflection Only Context but it turned out that the code inside of the NHibernate.Mapping.Attributes.HbmSerializer uses the
constructors of the attributes, which can not be called, to examine custom attributes loaded in the reflection-only context, use the CustomAttributeData class.
Well... I wasn't going to recode the HbmSerializer to make it work with the new .NET 2.0 API (not for now) so I have only one option left... create a new AppDomain an make the analysis there... but doing that is proving to be harder than I originally thought

Thursday, April 13, 2006

Visual Studio C# Express: Can Not Update with AttachDBFileName

Hi! Today I spent all morning teaching my father how to do CRUD with C# Express, but despite my best efforts, each time I ran my project, the database was completly empty... it turned out to be a "feature" of databases that are part of the solution (visual studio copies the database from the the source folder into the \bin\Debug\ folder each time the application compiles) the solution as as Humble Weeble posted, is to:

  • Select the database in Solution Explorer
  • Locate the 'Copy to Output' property in the Properties window
  • Change it from 'Copy always' to 'Do not copy'


Of course, after that, the problem will be that the connection string in you app.config is not pointing to the "output" database anymore, so AFAIK you will have to use an absolute path. (As I did)

Tuesday, April 11, 2006

NHiberntate Attributes + MSBuild = SQL DDL Generation

All right... I am building a system that uses NHibernate
as the persistence mecanism to save in to the database
and i decided that the best way to go... was to draw the
object model using the new VisualStudio 2005 Class Designer
the add the attributes... and then generate the SQL... but the
problem is that I have to run an extenal tool to do that... and I want the
DDL SQL to be re-generated each time I compile...
so I guess I will have to create a new MSBuild Task that integrates the
SchemaExport with MsBuild

So... I have written my task... but it does not work... now I am reading
How to: Write a Task to find out what am I missing... perhaps it is because
my task depends on an external assembly (NHibernate)... mmm no... that was not the problem... the problem was that I was not specifying the correct path for the source assembly.

It works.... well it worked... but only once... it seems that the source assembly gets blocked... lets think... how could that be fixed...

Sunday, April 09, 2006

Domain-Specific Language Tools... Class Designer Power Toys... where to start?

I am not sure where to start... should I create new functionality for the
Class designer? (perhaps exend it for object relational mapping?... or shuld I create my own
Domain-Specific Language

Saturday, April 08, 2006

Guidance Automation

I have been reading Guidance Automation
it seems to be an easy way to extend Visual Studio Functionality to a degree never seen before...

Wednesday, April 05, 2006

Why in ADO.NET the DataSet has to work with DataRow and not an Interface

Right now... there are two ways of handling an XML file in an easily and with object orientation:

  1. the intrusive (but more dynamic) TypedDataSet, generated bye the xsd.exe
  2. And object serialization generated by XSDObjectGenerator.

Each one has its advantages and disadvantages... but I wonder... why we can not combine the advantage of the by changing the internal design of ADO.NET... How?

Well the DataSet... is a collection of DataTables... the DataTable is a Collection of DataRows....
why it is not built to be more flexible? i.e. :

  • The DataSet could be an implementation of IDataSet
  • The default implementation for IDataSet " the DataSet" could be a collection of IDataTables
  • The default implementation for IDataTable "the DataTable" could be a collection of IDataRows
  • The default implementation of IDataRow... could be "the DataRow"

This way... I wouldn't have to worry about having to inherit from the DataSet, DataTable or DataRow classes... if that is not what I want... and this way I could create my own independant object hierarchy and... if I want to handle it as a DataSet well, all I have to do is implement the appropriate interfaces...

Of course... making Microsoft change the ADO.NET API to add this flexibility... could be too much to ask (after all there are a lot of applications built on top of the "legacy" ADO.NET) but... what about Mono? they could create an extensible non intrusive interface based dataset... don't you think?

Sunday, April 02, 2006

Implementing a DataProvider Independant ADO.NET DataAdapter

Okey... sometime ago... (in ADO.NET 1.x times) I wondered why data access for Odbc, for OleDb, for SQLServer or for Oracle had to be that different...
So i read Implementing a .NET Framework Data Provider
and I read ADO.NET: Building a Custom Data Provider for Use with the .NET Data Access Framework and I understood the processes that has to be followed to build a Data Provider... but I found something strange...

First... since ADO.NET 1.x it was possible to create a connection, and encapsulate that creation inside a factory that read the class type from a config file (you had to do-it-yourself but it was possible)... after that, using only interfaces and abstract classes common to all the Data Providers... it was easy to create a Command with the IDbConnection.CreateCommand.

But then... the problem arised... how to create the correct DataAdapter? (an IDbConnection couldn't create a IDbDataAdapter... an IDbCommand couldn't create an IDbDataAdapter... an IDataReader couldn't create an IDbDataAdapter...)
So... What is the difference between the DataAdapters and everything else? Why was it excluded from the "factory chain" (IDbConnection to IDbCommand to IDataReader)

With ADO.NET 2.0 that problem is solved, thanks to the new DbProviderFactory.CreateDataAdapter... but back then when only ADO.NET 1.x existed I began to think that maybe there was something really different between the IDbDataAdapter/DbDataAdapter and everything else... and I started looking for the difference... and the results were startling... there were absolutely NO difference... take a look at this example code from Microsoft... and now tell me why this "TemplateDataAdapter" couldn't have been included in the .NET Framework... perhaps as "DataProviderIndependantDataAdapter" or take a look at... for example... the SqlDataAdapter or the OleDbDataAdapter..., or the OdbcDataAdapter and tell me... exactly... what do the do that it is specific for SQLServer... or for OleDb... or for Odbc?

I you copy& paste the example code from Microsoft to one of your projects... and then in every place where you use the SqlDataAdapter you change it to the TemplateDataAdapter... what functionality do you miss? (if any) and... in the remote case that you do find something missing (I couldn't find anything)... is that functionality really database provider dependent?

Okey, okey, you want to know what is my point... well my point is:
  1. if the job for a DataAdapter is to represent a set of data commands and a database connection that are used to fill the DataSet and update a database (and I didn't invent that, Microsoft wrote in in the documentation for the SqlDataAdapter)
  2. and the DataSet is data provider agnostic...
  3. and it is possible to update the database using only interfaces like IDbConnection, IDbCommand, IDataReader... (and the base class DbDataAdapter already implements most of the logic needed to do that) then...


Why in .NET we don't have a DataProviderIndependantDataAdapter ? (as I said before it is so easy to build one, you just have to do a search an replace form the code of the TemplateDataAdapter in the example code from Microsoft but that doesn't answer the question).
Well, you might think... maybe it is just not worth the effort... maybe it is just a much better idea to have different DataAdapter classes... one for each DataProvider.... wrong.. that is simply not true...

Even with the new and improved DbProviderFactory.CreateDataAdapter there is a problem and the problem are the DataAdapter events

 adapter.RowUpdating += new SqlRowUpdatingEventHandler( OnRowUpdating );
adapter.RowUpdated += new SqlRowUpdatedEventHandler( OnRowUpdated );

Have you already seen the problem?

Even if you use the great new DbProviderFactory.CreateDataAdapter if you need to trigger provider independent logic using the the adapter.RowUpdating or the adapter.RowUpdated events... what do you do? there is no easy answer... (or maybe there is... to create a DataProviderIndependantDataAdapter )

First... I don't see why we have to use an "SqlRowUpdatedEventHandler" ? why ADO.NET does not include an "DataProviderIndependantRowUpdatedEventHandler" ? AFAIK the SqlRowUpdatedEventHandler has no special difference from the OleDbRowUpdatedEventHandler ... or do you see any? (of course, there is one you might say, the SqlRowUpdatedEventHandler uses SqlRowUpdatedEventArgs and the OleDbRowUpdatedEventHandler uses OleDbRowUpdatedEventArgs) so, the question now is... why we do not have a DataProviderIndependantUpdatedEventArgs ? is there an important difference between the SqlRowUpdatedEventArgs and the OleDbRowUpdatedEventArgs... well... there is none... they both inherit from RowUpdatedEventArgs... and add nothing... but they do create a problem... if you have a code like this:


 DbProviderFactory dataFactory =
DbProviderFactories.GetFactory("System.Data.SqlClient");
DbDataAdapter adapter = dataFactory.CreateDataAdapter();
DbCommandBuilder builder = dataFactory.CreateCommandBuilder();
builder.DataAdapter = adapter

// Create and fill DataSet (select only first 5 rows)
DataSet dataSet = new DataSet();
adapter.Fill(dataSet, 0, 5, "Table");

// Modify DataSet
DataTable table = dataSet.Tables["Table"];
table.Rows[0][1] = "new product";

// now... how do I add handlers?

if (adapter is SqlDataAdapter){
((SqlDataAdapter)adapter).RowUpdating += new SqlRowUpdatingEventHandler( OnRowUpdating );
((SqlDataAdapter)adapter).RowUpdated += new SqlRowUpdatedEventHandler( OnRowUpdated );
}

// now... that WAS NOT a DataProvider independent code...



Maybe we are missing something... lets take a loot at the guide for "Writing Provider Independent Code in ADO.NET"... mmm... no, the examples in Retrieving Data with a DbDataAdapter just do not cover the case when one needs to use the RowUpdating or the RowUpdated events

Of course that could have been easily fixed.. if we had a
DataProviderIndependantAdapter.. with its DataProviderIndependantUpdatedEventHandler and its DataProviderIndependantUpdatedEventArgs... so... why ADO.NET 2.0 does NOT provide one... don't ask me... but if you want to write code that is REALLY DataProvider Independant then you just have to create your own DataProviderIndependantAdapter.

ADO.NET vs ObjectRelationalMapping

So... why I don't like DataSets? Well, first of all, it is not that I think that DataSets are useless, it is just that I feel that Object Relational Mapping (ORM) is a far better solution, because, when properly built:

  1. You don't have to worry about primary keys of foreign keys (or the proprietary identity mechanism of a particular database)
  2. You don't have to worry about creating the master row first, and the detail rows later (master detail relationships are automatically handled by the ORM)
  3. You don't have to worry about saving all the changes in your data in the proper order(CRUD operations are automatically ordered following master detail relationships)
  4. You can easily add optimistic locking to you code without having to change all your SQL "UPDATE" or "DELETE" code.
  5. Your domain model is more abstracted from the idea that is being read from a database (a really good ORM should be able to read from a different relational source... or perhaps even a hierarchical source (Object Hierarchical Mapper?)... for example... from an XML file.
  6. You automatically get "cache" benefits, transparently, and sometimes you can even plug special caching strategies.

What Do I Know?

I am a software developer... I am certified (MCP) in WindowsForms.NET (with C#) development and I really like that platform (I specially love version 2.0)... I also know how to code in Java (I love Hibernate, I love Spring and somewhat like Velocity... but I think the future is in JavaServerFaces... or perhaps in Tapestry or... to compete with XAML... the best choice is OpenLazlo ) , I know a little of Delphi... and I have worked with Oracle and SQLServer... but to tell you the truth... the best technology that I have used is WebObjects (sadly IMHO Apple just doesn't seem to know the real value of it) and I really don't like to write SQL or Stored-Procedures... i believe the way to go is to use Object Relational Mapping and I really dislike ADO.NET DataSets... i mean.. they are good for web-services data exchange... but build the business rules of a software system.. there is nothing like the Domain Model pattern... with something like Apple's EOF... o Hibernate (or NHibernate)... so I am really sad that ObjectSpaces is delayed

TEOFL, Scholarship

Well, okey, my native language is Spanish... but I want to make the TEOFL exam... and maybe get an scholarship and to get a Masters Degree to USA... or Canada... or the UK... so, I need to practice with my english... and when my posts are not about philosophy... they will be about sofware engineering... and in the software development world... english is kind of the "lingua franca"... so I guess almost all of the post here will be in english

Startup! Iniciando!

Hi! This is my first entry in the blog!
Hola! Esta es mi primera entrada en el blog