Thursday, January 17, 2013

ANNOUNCE MFlow 0.2


Hello.

This is the second version of MFlow [0], a deep-first effort in the development of a plataform for web applications at the higher level, by including as much haskell magic as possible. It is at the same time experimental and intended to be used in industry. I believe that haskell will not have its chance in the Web if it does not bring any unique advantage beyond speed and type safety. 

Deep-first means that the effort is more in adding higher level features rather than in being complete and bug free, with the conviction that feedback from real usage at the highest level is the best guide for development. 

Rather than to mimic other platforms in other languages, MFlow is as Haskell'ish as possible, and introduces new approaches like  statefulness,  event sourcing, back-execution, composable, active, self contained widgets and persistent STM. All of them collaborate to create a high level environment for web programming.

Statefulness means that the flow of execution is right in front of the eyes of the programmer, rather that in  the spaghetti code of the event-handling model,  the goto of the XXI century. it also means that the entire session is in a procedure, so the session data need no trickery.

But, like in the stateless case, any page in the flow could have a direct URL. [1]

Event sourcing in combination with statefulness means  automatic logging of all the events and automatic recovery of the execution state of the server procedure and its data,  thanks to the Workflow monad transformer [2].

So the server procedure can be stopped after timeout and restarted by the application server when the user invokes it. The programmer can determine the timeout and for how long the state is stored.

Back button management: the flow of execution can run back when the back button is pressed [3]. Thanks to a monad transformer. In combination with event sourcing, this means automatic rollback of user session data. So if the user want to undo his last item in the shopping cart, he only has to press the back button.


User interface: 

It is made of self contained pieces called widgets, made around the formlet concept, so they compose gracefully with applicative operators and other extra operators. A MFlow widget is more like the widgets of XWindows, ASP.NET or JavaServer Faces: they have their own HTML formatting, their own behaviours and interact with the server via AJAX, they execute actions when activated and they return statically typed data. They declare their required scripts, CSS links and server procedures in the form of requirements to the requirement service. They include the server and client code in the same piece of text. Being self contained and typed, they can be shared and plugged with a minimum of configuration and instructions.

The URL links are also widgets or elements of widgets and return data to the same flow, so no spaguetty event handling occur, unless the programmer need out-of-flow links.

This versions includes some  active widgets with server-side controls for creating them [4]. 

Bindings:
wai-warp, blaze-html, xhtml, HSP, hack.

Persistence and transactions: 
Global data can be transacted with any kind of persistence framework. MFlow internally uses TCache [5], which provides with persistent STM references (DBRefs). Their serialization can be configured. For rapid prototyping, they have default persistence in files. Just add a Read-Show or a Binary instance for your data and you can have a persistent, transactional DBRef to it. Use them like you use TVars. TCache can index text and register fields. It has a simple query language. Data can be accessed by key or by any indexed field.


EXAMPLE:
The human mind learn by examples. There is a online demo for some of the features that you can play with and  you can download the code [6] 










-- 
Alberto.

Monday, January 14, 2013

Stateful, but virtually stateless, thanks to event sourcing




My example application of MFlow  has two handles for two verbs: mainmenu and shopCart

addMessageFlows [(""  ,transient $ runFlow mainmenu)
                ,("shop"    ,runFlow shopCart)]



mainmenu has a set of links to different options, but because the flow is stateful, theoretically I can not address each individual option with a link:


mainmenu=   do
       setHeader stdheader
       setTimeouts 100 0
       r <- ask $ wcached "menu" 0 $ 
               wlink CountI   (b << text "increase an Int")
               <|> (p <<< wlink CountS   (b << text "increase a String"))
               <|>  br ++> wlink Action   (b << text "Example of action, executed when a widget is validated")
               <|>  br ++> wlink Select   (b << text "select options")
               <|>  br ++> wlink CheckBoxes (b << text "checkboxes")
               <|>  br ++> wlink Radio    (b << text "Radio buttons")
               <++  br <>  br <> b << text "DYNAMIC WIDGETS"
               <|>  br ++> wlink Ajax     (b << text "AJAX example")
               <|>  br ++> wlink Autocomp (b << text "autocomplete")
               <|>  br ++> wlink AutocompList (b << text "autocomplete List")
               <|>  br ++> wlink ListEdit (b << text "list edition")
               <|>  br ++> wlink Grid (b << text "grid")
               <|>  br ++> wlink TextEdit (b << text "Content Management")
               <++  br <>  br <> b << text "STATEFUL PERSISTENT FLOW"
                 <> br <>  a ! href "shop" << text "shopping"   
                 <> br <>  br <> b << text "OTHERS"

               <|>  br ++> wlink Login    (b << text "login/logout")


       case r of
             CountI    ->  clickn  0
             CountS    ->  clicks "1"
             Action    ->  actions 1
             Ajax      ->  ajaxsample
             Select    ->  options
             CheckBoxes -> checkBoxes
             TextEdit  ->  textEdit
             Grid      ->  grid
             Autocomp  ->  autocomplete1
             AutocompList -> autocompList
             ListEdit  ->  wlistEd
             Radio     ->  radio
             Login     ->  login
I have to go to the menu first to reach any option, because mainmenu ask for the menu in the first place. Ever. But this is not that way. Each option has an absolute URL and can be accessed directly from outside. It can be copied and mailed safely to other user. This link bypass the menu and go straight to the first option: http://81.169.134.95:8081/noscript?c0=CountI It may be said that, because MFlow simulates the structure of a console application, to reach the second question it is necessary to answer  the first question. But MFlow allows to express the sequence of events (the user responses) of various steps in a single URL. In the above URL,
 c0=CountI 
is the response to the menu question, so the first 'ask' will read the menu response right from the link url. It is possible to express by hand as many user responses in a single URL as I would like, but the application now only generates links with the events corresponding to the last interaction  if the request was in GET mode. That is enough to generate a link that hop over a first step of links straight to the desired option. This example has events for two steps. it chooses the "Content Management" option and  execute the first step of this option that present a login form. But this URL has been generated by hand: http://81.169.134.95:8081/noscript?p0=()&c11=TextEdit But it is may be easy to develop an 'addressable' switch that, when activates, generates addressable URLs. It also would reset parameter numbering, so that even POST requests  would navigate to pages with a addressable URL and the page will be addressable and shareable as if the flow where stateless. With this event sourcing approack,  an stateful MFlow procedure could be as stateless (or even more) than a classical web procedure.

NOTE: by design, a link to mainmenu with no parameters will go to the current user navigation point, rather that going back to the root of the navigation (the menu). 

If there is a timeout, set with setTimeout, like in this case of 100 seconds, after this time the link to mainmenu with no parameter will go to the root.

Online MFlow demo

There is an online site where MFlow is running with some examples of some MFlow features:

http://mflowdemo.herokuapp.com

This is the frontpage:


MFlow examples


About this menu (article)

DATABASE
  • Database Create, Store and retrieve lines of text from Amazon SimpleDB storage

  • PUSH
  • Push example A push widget in append mode receives input froma text box with autorefresh (article)
  • A push counter Show a countdown. Then goes to the main menu (article)


  • ERROR TRACES
  • Execution traces for errorsproduces an error and show the complete execution trace (article)


  • DIFFERENT KINDS OF FLOWS
  • REST navigation Navigates trough menus and a sucession of GET pages (article)
  • Stateful flow: shopping Add articles to a persistent shopping cart stored in the session log.getSessionData is read in the View monad to get the most recent shopping carteven when the back button has been pressed (article)
  • Stateful flow: Counter a persistent counter. It uses the same mechanism than shopping, but it is a more simple example


  • BASIC
  • Increase an Int A loop that increases the Int value of a text box
  • Increase a String A loop that concatenate text in a text box
  • Select options A combo box
  • Checkboxes
  • Radio buttons


  • PAGE FLOWS with MONADIC WIDGETS, ACTIONS & CALLBACKS
  • Example of action, executed when a widget is validated
  • in page flow: sum of three numbers Page flows are monadic widgets that modifies themselves in the page (article)
  • Counter A page flow which increases a counter by using a callback (article)
  • Multicounter Page flow with many independent counters with autoRefresh, so they modify themselves in-place (article)
  • Combination of three dynamic widgets Combination of autoRefreshe'd widgets in the same page, with different behaviours (article)
  • Modal dialog A modal Dialog box with a form within a page flow


  • DYNAMIC WIDGETS
  • AJAX example A onclick event in a text box invokes a server procedure that increment the integer value (article)
  • autocomplete Example of autocomplete, a widget which takes the suggested values from a server procedure
  • autocomplete List Example of a widget that generates a set of return values, suggested by a autocomplete input box (article)
  • list edition Example of a widget that edit, update and delete a list of user-defined widgets
  • grid Example of the same widget In this case, containing a row of two fields, aranged in a table (article)
  • Content Management Example of the (basic) content management primitives defined in MFlow.Forms.Widgets


  • OTHERS
  • login/logout Example of using the login and/or logout
  • Prevent going back after a transaction Control backtracking to avoid navigating back to undo something that can not be undone. For example, a payment (article)
  • Thursday, January 03, 2013

    MFlow active widgets example


    The new module MFlow.Forms.Widgets in the package MFlow  whose last version is in GtHub, (reference below) contains active widgets that can manage other widgets in order to compose complex dynamic applications. A widget is composed of form elements, links and scripts that return statically typed results.

     Now, an example of use of the active widget wEditList, described here.  This widget can manage a list of widgets of the same type. It can add or delete them. The result, when the list is sent to the server, is the sublist of the validated elements results.

    In this case, the widget managed by wEditList is a row of a table with three elements: an Int input text, a String input text and a delete link. the widget is codified using blaze.html and the MFlow input fields.

    The delete link  invokes a javascript event that delete the entire row.

    There is a "add" link that add a new row to the list. To be recognized by the wEditList widget, it has to have the identifier "wEditListAdd"



    grid = do
      let row _= tr <<< ( (,) <$> tdborder <<< getInt (Just 0)
                             <*> tdborder <<< getString (Just "text")
                             <++ tdborder << delLink)

          delLink= a ! href "#"
                     ! onclick  "this.parentNode.parentNode\
                        \.parentNode.removeChild\
                        \(this.parentNode.parentNode)"
                     << text "delete"
          tdborder= td ! At.style  "border: solid 1px"

          addLink= a ! href "#"
                     ! At.id "wEditListAdd"
                     << text "add"

    Note the use of (,) and the applicative operators <$> and <*> over the form elements getInt and getString, which
    compose a result of type (Int,String). There are also formatting operators <<< which encloses the form elements within a table colum element 'tborder' which is a 'td' element with some style. The ability to mix formatting and applicative operators is a unique feature of MFlow. It becomes quite intuitive to use after a while. A knowledge of  applicative operators is necessary. While <<< encloses a form element (or a wlink) in a html tag,  << encloses ordinary html, and this is why dellink, an ordinary html link is preceded by <<  . Finally the operator <++ append html formatting to a widget.

    Here is how the widget looks with two initial elements:


    add
    delete
    delete

    Submit

    This is how the wEditList is invoked with the row element as parameter. the 'table' holds the elements in this case. A initial list of two elements with empty strings,that are ignored, means that two elements will be show at the beginning. Finally, a submitButton will send the form result when pressed. To glue these components, the operator ++> prepends html to the widget and the operator <** is an applicative operator similar to <* which do not care about the validation result of the button (<* could have been used in this case). See Control.Applicative for the Applicative concept and the applicative operators.

    r <- ask $ addLink ++> ( wEditList table  row ["",""]) <** submitButton "submit"

    r will have the result. When I click add, two times and  edit some of the fields, the look is as follows:

    add
    delete
    delete
    delete
    delete


    Submit

    if we add an additional line to print the result in a new web page. after pressing the submit button:

    ask $   p << (show r ++ " returned")


    The page will show this result:

    [(1,"text1"),(2,"text2"),(3,"text3"),(4,"text4")] returned

    The complete code is part of demos.Blaze.hs. 


    This example uses the last version of MFlow at https://github.com/agocorona/MFlow.
    It uses the last version of  Workflow  https://github.com/agocorona/Workflow


    grid = do
      let row _= tr <<< ( (,) <$> tdborder <<< getInt (Just 0)
                              <*> tdborder <<< getString (Just "text")
                              <++ tdborder << delLink)
          addLink= a ! href "#"
                     ! At.id "wEditListAdd"
                     << text "add"
          delLink= a ! href "#"
                     ! onclick
                        "this.parentNode.parentNode\
                        \.parentNode.removeChild\
                        \(this.parentNode.parentNode)"
                     << text "delete"
          tdborder= td ! At.style  "border: solid 1px"

      r <- ask $ addLink ++> ( wEditList table  row ["",""]) <** submitButton "submit"
      ask $   p << (show r ++ " returned")
          ++> wlink () (p << text " back to menu")