Tuesday, June 19, 2007 

Client Side-Augmented Web Applications

In the last few posts I've been writing a lot about AOP, and very little about what I'm doing every other day. It's plain impossible to catch up, but here is something that has kept me busy for quite a few days lately: Client Side Augmented Web Applications (I should file for a trademark here :-). What I mean is a regular web application, that can be regularly used as a stand-alone application or, when you install some additional modules on the client, can also interact closely with other applications on the client side (e.g. the usual office suite, and so on).

Naturally, that means web pages must have a way to send data to client side application, and to obtain data from the client side application. For several (good) reasons, we wanted this data exchange to be as transparent as possible to the web app developers. Also, we didn't want to write different web applications (regular and augmented). That would have had a negative impact on development and maintenance times, and it could also have proven to be an inconvenience for the users. This had some impact on page navigation design, which could be an interesting subject for a future post.

Now, I can't get into the specifics of the project, or disclose much about the design of the whole infrastructure I've designed and built (yes, I still enjoy writing code :-). However, I can show you the final result. If you want your ASP.NET page to obtain (e.g.) the filename and title of your Word document, and send back to Word a corporate-wide document number, all you have to do is add a few decorated properties in your .aspx.cs source file, like:

public partial class DocumentProperties : System.Web.UI.Page
  {
  [AskClient("filename")]
  public string Filename
    {
    get
      {
      return filename;
      }
    set
      {
      filename = value;
      }
    }

  [AskClient( "title" )]
  public string Title
    {
    get 
      { 
      return title; 
      }
    set 
      { 
      title = value; 
      }
    }

  [SendClient("description")]  
  public string Description
    {
    get
      {
      return description;
      }
    set
      {
      description = value;
      }
    }

  // here goes the usual stuff (methods, data members)
  }

that's it. The attributes define the property name as known on the client side; the invisible infrastructure will take care of everything else. In a sense, communication between the web application and the client side application has been modeled as a virtual machine concern, and the attributes are used to tell the virtual machine where interception is needed. Of course, this is only the tip of the iceberg. There is a lot going on under the hood, also on the client side, as your browser and your favorite application are usually not good friends, and to be honest not even acquaintances.

Is my abstraction leaky? Sure it is. To make all that stuff working, you also have to drop a non-visual component into your page at design time. That component, if you follow the virtual machine metaphor, is indeed the implementation of the (server-side) virtual machine layer that will deal with the communication concern.
If you don't drop the component into the page, the virtual machine layer just won't kick in, and your attributes will stay there silently, stone cold. This is a functional leak that I'm aware of, and that as a designer I have accepted. In fact, all the alternatives I've considered to avoid this leak had some undesirable consequences, and keeping that leak brought the best overall balance. Besides, there are ways to somehow hide the need to drop the control into the page (like using page inheritance or a master page), so it's really no big deal.

A final reflection. I do not believe that something like this could come out of refactoring code that was simply meant "to work". It's relatively trivial to make a web application and a client-side application talk. It's quite different to make this talk transparent. Having prototyped the first option (just to make sure a few ideas could actually work) I can honestly say that without the necessary design effort (and skill), it's extremely unlikely to come close to the final result I got.

Time to drop a few numbers: overall, I've spent roughly 20% of total development time experimenting with ideas (throwaway code), 35% designing, 30% coding (this includes some unit testing), 10% doing end-to-end testing, 5% debugging. Given the relative novelty of several techniques I adopted, I should actually consider the 20% prototyping an inherent portion of the design activity: you can't effectively design much beyond the extent of your knowledge. Sometimes, the best way to gather more knowledge is to talk; sometimes, to read; sometimes, to write code. Of course, I was looking for knowledge, not for code to keep and cherish, so I happily scrapped it away to build much better code. In the end, that's often the difference between intentional and accidental architecture.

Labels: , , ,

Comments:
A questo punto vorrei un ulteriore commento sulla questione del refactoring: Quanto pensi che le comuni tecniche di refactoring possano migliorare il codice di quell'applicazione? Ciò che mi interessa (diciamo che è un'intuizione) sapere è se effettivamente il refactoring è più una pezza che serva a posteriori se non si progetta come si deve che uno strumento utile anche dove il design è ben fatto
 
Nel caso specifico dell'infrastruttura di cui parlavo: pochissimo. Il design e' molto curato. In effetti ho una classe un po' grassottella per i miei gusti, cosa che sapevo gia' prima di scriverla, e sapevo anche come sistemare la cosa (pattern strategy). Siccome avevo cose piu' prioriarie da fare, ho messo una nota nel diagramma e nel codice, e l'ho lasciata com'era.
Verso novembre/dicembre credo servira' aggiungere alcune cose in quell'area e in quel momento qualcuno (non necessariamente il sottoscritto) fara' un piccolo refactoring localizzato. E' stata, comunque, una decisione conscia di design, non una sorpresa del tipo "uh, il codice fa schifo :-), devo rifattorizzare".
Dopodiche', non ho nulla contro il refactoring. Anzi, devo dire che proprio nel mese passato, pensando ad un mio cliente che per ben due volte ha tentato un redesign massiccio di un sottosistema critico, col risultato di arenarsi in entrambi i casi di fronte allo sforzo di sostituire il sottosistema vecchio con il nuovo, ho ipotizzato una strategia basata su micro-step di refactoring. Che non ci portera' ad una rivoluzione architetturale, ma ci dara' dei benefici immediati e ci avvicinera' ad una architettura piu' moderna, in modo da limitare poi il futuro costo del rimpiazzo.
Tuttavia, la pur utilissima possibilita' di operare miglioramenti localizzati non puo' essere vista come un sostituto della capacita' di visione che permette di progettare qualcosa di realmente bello. Questo mi ricorda che avrei qualcosa di lungo e polemico :-)) da dire su alcune definizioni di Software Architect che leggevo nei giorni scorsi saltellando tra i blog. Una volta o l'altra lo faccio :-)).
 
"It's relatively trivial to make a web application and a client-side application talk."

Ciao.
Mi interessa moltissimo questo punto.
Potresti darmi alcuni Hints per capire come fare?
 
Post a Comment

<< Home