Showing posts with label GUI-Design. Show all posts
Showing posts with label GUI-Design. Show all posts

Friday, October 18, 2013

Zen Style: Semantics Oriented, Contextual Programming

The title of this blog is suggestive.
Like a monk in Zen temple, a programmer should not work hard for low level thing, but just try hard to identify the essence of the problem, then the rest will follow magically with no effort.

Declarative programming style is something common to this style. we don't care some procedural steps, which are very low level, but just concentrate on the relationship.
But declarative style itself are still not powerful enough. We must be able to extend the declarative constraint enforcing mechanism in the programming. It is sort of reflective approach, the goal of this approach is to create autonomous intelligent program driven by knowledge and semantics, context, rules etc. Essentially the output is not cumming just from the written code, but the as a synthesis of machine intelligence and the directive programming which will be short in size.

Normally such kind of programming were not easy. But these days, reflection library can be used to assist such programming style. Annotation is actually very under evaluated naming, but it has big potential. we can change ordinarily programming behavior outside of written code using such annotation information and specific library using reflection.

The code I developed for GUI is such an example.
Essentially the goal of the approach is to support declarative GUI development.
Some structural/layout related coding are defined with no procedural codes.

And procedural code which are associated with how the GUI will respond to user input etc are cleanly separated from these GUI code.

In normal program, we cannot change the timing of setting some property values etc, but using reflection library, it can implicitly set these values based on annotation, field type, context class type etc.
So we may think of this as semantics driven program, or contextual program. We can improve programming productivity by delegating certain annoying patterns to such library.
This is quite close to changing our language itself. So that is the essence of reflectivity.

These things could have been done in Java, but Java's generics were poor at runtime compared to Dart, Dart has more potential utilizing generic's type information. This is important difference. Java could not know itself at runtime, but Dart can. One interesting example was the CouchDB json parser which will use provided applied generic type information to determine sub json's type information as posted before.
Another reason may come from just the basic verboseness of Java language. There are so many restrictions, like anonymous class, even something can be done better, in the faces of such a bloated code, the gain would have reduced a lot.
That would have been discouraging some effort. AOP activities were something to be mentioned, but I have never seen such AOP application for GUI library in Java.
The cascading syntax is very small syntactic addition, but it has a big potential to eliminate all html  based development. Also many future, higher order functional make code very short.
Only in such an environment, these new approach will shine.

Here is a new revised version of sample code I posted before.
in the first part of code are dedicated to GUI presentation. Also the idea of this approach is to assist component style web development which combine the behavioral logic in the component, so such sub components are also declared as final field property with annotations.
From this annotation information and the declaring class, ie, CRUDView as subclass of Component class, when the object is instantiated, the super class Component will start analysing the annotation
 through reflection library, and setting corresponding property in the subcomponents(like label value in the annotation).

class CRUDView extends Component {
  static const String CRUD = "g_cud_view";
  DivElement _content;
  DivElement _actions;

  @UI_Table()
  final Table<Expense> table = new Table<Expense>();
  
  @UI_Form()
  final Form<Expense> form = new Form<Expense>();
 
  @UI_Button(label: "Load")
  final ButtonComp loadButtom = new ButtonComp();
  
  @UI_Button(label: "New")
  final ButtonComp newButtom = new ButtonComp();
  
  @UI_Button(label: "Save")
  final ButtonComp saveButtom = new ButtonComp();
  
  @UI_Button(label: "Delete")
  final ButtonComp deleteButtom = new ButtonComp();
  
  Element _updateElement(Element elm) => 
      elm
      ..classes.add("section")
      ..nodes.add(new Element.html("<header class='section'>${table.modelType} Table</header>"))
      ..nodes.add(_content = new Element.tag("div")
        ..classes.add("g_crud_view_table")
        ..nodes.add(table.element))
      ..nodes.add(_actions = new Element.tag("div")
        ..id = "actions"
        ..classes.add("section")
        ..nodes.add(loadButtom.element)
        ..nodes.add(newButtom.element)
        ..nodes.add(saveButtom.element)
        ..nodes.add(deleteButtom.element))
      ..nodes.add(form.element)
      ..nodes.add(new Element.html("<footer class='section' id='footer'></footer>"));
 
This part defines more behavioral aspect of program.It defines how application respond to the user input etc. these are nothing to do with GUI. We may still reduce direct association of the action with each GUI components if we introduce Monitored fields as I have done in namebudge application.

  // this should be injected by AOP approach from out side..
  ICouchDbClientDAO<Expense> dao = new CouchDbClientDAO<Expense>(Expense, sampleJsonMapper);
  
  CRUDView() {
    this.classes.add(CRUD);
    Type _Expense = Expense;
    table
      ..modelType = _Expense
      ..formatFunctionMap[ExpenseType] = ExpenseTypeComp.format;
    
    form
      ..modelType = _Expense
      ..inputFactoryCache.specialInputCompMap[ExpenseType] = ExpenseTypeComp.inputCompFactory
      ..inputFactoryCache.adhocCompMap['detail'] = 'textarea'; // should be moved to annottaion!
    
    loadButtom.onClick((_) {
      dao.fetchAll().then((List<Expense> es){
        table.load(es);
        //print('loaded data from db; ${es}');
      });
    });
    
    newButtom.onClick((_) {
      Expense e = form.create();
      _changeButtonState(true, false, true);
      //print('new in db');
    });
    
    saveButtom.onClick((_) {
      if (form.e != null) {
        Expense e = form.save();
        if (e == null) {
          //print('form is empty, click New, or select arow before Save.');
          return;
        }
        // this part is tricky..
        // since e is fill from InputText, when it is empty text, it will assign "" instead of null..
        if (e.id == "") e.id = null;
        if (e.rev == "") e.rev = null;
        ((e.id == null)?dao.insert(e):dao.update(e)).then((Expense e0){
          e.id = e0.id;
          e.rev = e0.rev;
          table.addOrUpdate(e);
          _changeButtonState(false, true, true);
          //print('updated in db e0: ${sampleJsonMapper.toJson(e0)}, e: ${sampleJsonMapper.toJson(e)}');
        });
      }
    });
    
    deleteButtom.onClick((_) {
      Expense e = form.e;
      if (e != null) {
        dao.delete(e).then((ok){
          if (ok) {
            form.delete();
            table.delete(e);
            _changeButtonState(false, true, true);
            //print('deleted in db');
          }
        });
      }
    });
    _changeButtonState(false, true, true);
    
    table.row_listeners.add((ev, row){
      Expense e = row.e;
      form.load(e);
      _changeButtonState(false, false, false);
    });
  }
  
  void _changeButtonState(bool new_disable, bool save_disable, bool delete_disable) {
    newButtom.node.disabled = new_disable;
    saveButtom.node.disabled = save_disable;
    deleteButtom.node.disabled = delete_disable; 
  }
  
  Element createElement() => addSubComponents0(newElem("div"));
  
  Element update() => addSubComponents0(initElem());
      
  Element addSubComponents0(Element elm) => addListeners(_updateElement(elm));
}

This is one application of annotation and reflection, the other application I introduced was Monitor. Monitor is useful to separate GUI interaction and actual semantics.It may be considered as more efficient version of Event driven code.
Monitor is achieving similar goal as Observable does in Ploymer, but it is general purpose class, which may be used for OR mapped entity classes to support lazy loading etc.

Anyway, I will need to describe them in more detail later.

Several Dart bugs I encountered

I refactored the codes so that new implicit delayed UI component initialization can be used.
And I found a few restriction and bugs of Dart.

  1. I needed to define default constructor without taking optional values. this is required to create UI component object without taking any parameters, in particular, parent value can not be passed at the property declaration time.
    So I first tried to use optional parameter '{}', but when I combined with Monitor suing Mixen, I found it does not allow to use mixin with a class in which the default constructor has optional parameters.
  2. So I first try to avoid changing existing constructors(although it was not bad idea to change so, but it needed more changes), I moved Monitor class to be used as super class of the top level Component class. Then what I saw during execution was very strange problem. There was annotation class called Monitored, and reflection will get the instance through metadata, and in order to identify proper annotation class, it uses 'is" operator.
    What happened was that 'obj is Monitored' was not true even obj's runtimeType is Monitored!
    This kind of things happen in Java when different class loaders are used to instantiate an object, but in Dart, we will not manipulate class loading, so quite strange. So I basically abandoned this approach, and took the mixin approach again.(this was OK, since this approach would be more narrowly scoped, and appropriate for the purpose).
  3. after all required changes are finished, and could run properly with DartVM mode, I tested this app with static mirror library which are to be used for javascript mode.
    If I run this with Dart VM, it run properly, but if we use javascript mode, the dart2js compiler crashed.
    Actually the message of the compiler problem was the same as a bug I reported before, and it was quickly fixed(but  I did not verify it for myself.) So I thought this would be fixed if I update the dart sdk(r28355) since the fixed version was older that that revision.
    But I found it was not fixed. Actually there were some workaround to fix previous problem using variable instead of direct type value, but this issue was not fixed by this workaround. So this may indeed be another bug.
  4. Another problem I faced was the getting ClasssMirror of generic type. In order to provide javascript mode, portal mirror need to provide basic reflection features from concrete classes.
    For instance it need to use generic type's type(Type). right now, in order to have right type value, namely the type where parameters are substituted is only to go through instantiating the object.
    but new implicit delayed UI component initialization will call reflection library when  the default constructor is called. So this introduced infinite loop. Actually these kind of problems were I anticipated when I knew the current  way to get Type. Essentially this is very dirty trick. Also some case, this will case unnecessary resource usage as well. I avoided this problem using dirty trick to use static variable not to call the sub component initialization(although the global variable is defined as private, so it is not so bad way..).
  5. This issue also made clear the current constructor has a lot of restriction, lack of flexibility. The simple way to avoid this in Java was to define another constructor to take such flag to disable calling sub component initialization. But in Dart, if we define one constructor, there is no other way to define another.   So I was forced to use global variable.

Wednesday, October 16, 2013

Implicit Delayed Initialization of GUI Components with Reflection

Previous sample code is a bit inferior compared to polymer HTML GUI specification style since the layout related codes were scattered around many places. It should have more declarative specification gathered in the close places.

One of the main reason for this mess was these sub components need to know the parent and it is impossible to get access in field declaration parts. So they must have been moved to constructor.
Also attribute related specification clutter the codes.

We can fix these issues by introducing two ideas.
  1.  use annotation for sub components in which attribute specification(small GUI related information, will be specified.
  2.  Implicit delayed initialization of sub components. This means when a component is instantiated, it will inspect these annotated sub component fields, and set the parent and additional information depending on the annotation and its parameters. The nice thing about this approach is that this procedure is recursive.
    when  the component is created, it starts initializing the sub components whose sub components are already initialized when the sub component is created.
Followings will be the new way to define layout.

class NameBadge extends Component with Monitor {

  @UI_TextInput(label: "Enter New Name:", String)
  final TextInputComp textInput = new TextInputComp();
  
  @UI_Button(label: "Generate pirate name")
  final ButtonComp button = new ButtonComp();
  
  @UI_Radio(label: "Male", name:"maleOrFemale")
  final RadioComp maleRadio = new RadioComp();
  
  @UI_Radio(label: "Female", name:"maleOrFemale")
  final RadioComp femaleRadio = new RadioComp();
  
  Element _createElement(Element elm) => 
      elm
        ..nodes.add(
            new Element.div()
              ..classes.add("entry")
              ..nodes.add(textInput.element)
              ..nodes.add(button.element)
              ..nodes.add(maleRadio.element)
              ..nodes.add(femaleRadio.element))
        ..nodes.add(
            new Element.div()
              ..classes.add("outer")
              ..nodes.add(new Element.div()..classes.add('boilerplate')..text = 'Hi! My name is')
              ..nodes.add(_initDiv0(new Element.div()..classes.add('name')..text = _badgename)));
  ...

  NameBadge(Component parent): super(parent, const[APP]) {
    this.button.onClick((e) { badgename = pirateName(); });
    this.maleRadio.onClick((_, comp){ male = true; });
    this.femaleRadio.onClick((_, comp){ female = true; });
    ...

Monday, October 14, 2013

Reflective Interceptor, Monitor in Dart (Part 1)

In GUI, persistent data programming, the interceptor for the field access is fundamental.
It can enhance the field access with additional behaviors.
It may trigger another action, or keep recording of some internal changes.
But these behaviors should be irrelevant for the caller of these getter/setter.

These things has been implemented as part of general AOP type injection mechanism like CGlib, asm etc, but these approach would not be possible in Dart,  and overkill for this limited range of interception (getter/setter).

Dart introduced @observable Observable mixin, but Observable class seems not general purpose class, but restricted to polymer html file.

So it is interesting to find an alternative way to support similar idea in more general setting,and apply it to my web-framework, gui-components library.

For this purpose, I created the Monitor class. for the name of the field annotation  to be monitored by Monitor class is 'Monitored'. This Monitor class can be used with mixin as well as subclassing, so any class can be changed to a Monitor class easily.

Tuesday, October 8, 2013

Dart's annotation

I refined the look and feel of sample app using Dart's annotation.

This feature is very useful for customizing a lot of thing without touching the code itself.
So there are quite a lot of area to use annotations.

The annotation mechanism of Dart is quit easy to use, it is also part of dart:mirrors. So in order to use this on browser, we still need to use my portable_mirror library(I extended the API for this).

The things I have done is:
  1. Table
    • remove id and rev column from table
    • change expenseType to type
       
  2. Form
    • disable id, rev text input
These are specified by annotation for the getter  in Expense class.
Also I fixed table so that it has max height and can use scroll.
So this GUI is now looks beter. but it will be useful to support more annotations to adjust look and feel such as ordering specification. location to put text etc.

class Expense  {
  ....
  
  @GUI_Table(invisible: true)
  @GUI_Form(disabled: true)
  String get id => _id;
  void set id(String i) { _id = i; }
  
  @GUI_Table(invisible: true)
  @GUI_Form(disabled: true)
  String get rev => _rev;
  void set rev(String value) { _rev = value; }
  
  @GUI_Table(label: "type")
  ExpenseType get expenseType => _type;
  void set expenseType(ExpenseType i) { _type = i; }
  
  ...
}

Sunday, October 6, 2013

GUI action design pattern

The sample app(CRUDView) class is not so clean with respect to the implementation of how mouse action would trigger window state changes, like some button are disabled and the others are enabled etc.

Each component class should not have to know anything except what they suppose to do, i.e, some state change.

All the GUI action should be understood as state transition.
 if we append listener to each node's listener, that is still bad.

the controlling logic is tightly associated with specific GUI action.
But what the mouse action will change is the state and that state change is the reason for the logic of GUI change.

so the logic should be centered around the state change.

for instance, following code may describe the state transition of each mouse click for the buttons.

state('a1')..>state('a2')['load'] = load
    ..>state('s3')['save'] = save;

state('a2')..>state('a2')['clear'] = clear
    ..>state('s3')['edit'] = edit;

That way, we see the real logic behind the GUI action. often such a  state is not explicitly expressed in the application code as in the current CRUDView code. and action methods are called from many places associated with buttons.
That messy way should be avoided.