[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Case for using a web framework, eg Mojolicious


I don't think "moving to a web framework" is the right way to look at LedgerSMB's direction.  This way of framing things presupposes that LedgerSMB will always be primarily a web app, and I don't think that's a good idea.  We already have users who are up against the limits of what you can do in a web app format and eventually I would like to ensure that we have thick clients as well, and I don't think the "primarily a web app" is necessarily a good model esp when we get into higher volume transaction processing.

I think you should look closer at Mojolicious and also if you aren't familiar with Rails/Gems spend a little time on that for inspiration (I find a lot of nice things in Rails that I use in my Perl apps)

A web framework is supposed to *encourage* you to decouple in the way you describe.  That the input is via a GET request for an HTML file, or a json request, or a PDF request is largely a detail, if your app is decoupled. The framework removes all the logic on receiving input via http and leaves you with a "router", whereby certain input (GET /somewhere/ap.pl) causes some Module::Function(*variables) to be invoked.  This is of course your "Controller", so that also is decoupled from the logic which exists in various "Model" modules

So if you wish to make it a desktop app then likely you will need a new set of "controller" modules, but likely it will be a reasonably straightforward implementation and most of the code will be re-used.

- Which implies: easy external automation of various tasks, define new
"Commands" which could be used either as a form of API or to automate
certain tasks:

I think that the key things we get from this have to do with request handling (a lot of the things we use LedgerSMB.pm and LedgerSMB/Form.pm for).  This is valuable.  Not sure it is possible to do with the SQL-Ledger code in a sane manner however.

On the surface these appear to be examples of where the code is too tightly coupled with being a web app?

In Mojolicious you can use the router and a "bridge" (or a hook) to ensure that any such decoding is performed cleanly and externally to the controller code.

Also see Rails for inspiration on a very clean way to handle form naming such that it's converted into a nested structure for easy use in the application.

The key issue as far as I see it at present is that right now we have two codebases.  One supports code caching reasonably well. The other (the one we inherited) is a mess.  Getting it to work on Starlet was not a simple task (took me over a day of just fixing bugs and troubleshooting) and in the end if you don't fork, run, and die (i.e. each child serves one request only), after 5 runs of the chart of accounts report or 10 runs of the sales invoice screen (yes, each line entered counts), something gets corrupted and old code will just show internal server errors.

I find this quite baffling actually?  I'm really not sure how I could design an application in Mojolicious to fail in this way?!

I suspect that there are global variables being created which in turn are getting trampled on?  If that is the case then there will also be threading issues and corruption due to simultaneous requests... 

Mojolicious' solution is to introduce a session level "global" called the "stash" (hey, all the other options are somewhat nasty..).  This is where you can pop all your global variables and generally go nuts, but they remain isolated from subsequent requests.  This may be a slightly time consuming retro fit to lsmb, but it's a surefire way to nail this once and for all

Mojo isn't per-se going to fix the issues you describe above, but it will force developers (or rather make it easy) to rejig their applications such that initialisation code is called before forking and per-request code is called in a localised per-request thread

1)  Getting a really good cross-language database interface in.  We still need some work in this area.  Probably during the 1.5 development time, I expect to try to build a CPAN module to do this, and then we can begin to move code over onto it in the 1.6-1.7 timeframe.

Can you flesh out some thoughts on what this means?  I'm not sure I understand?

In general DB interfaces have been done to death and CPAN is a veritable graveyard of previous attempts.  Although I concede I don't understand the extent of the variations, certainly DBI/DBIX/DBIX::C, have lasted through some design kicking and there are a dozen spin-offs designed to suit various ways of working. I think you should thoroughly explore existing options before building something which has defeated many others before?

Personally I don't see multi-DB support being terribly important on a business critical service such as an accounting system.  I concede that I only really understand mysql and have almost no experience of postgresql, so if you asked me which you should use for a brand new project you know what I will pick...  However, I personally wouldn't want you to expend effort on supporting mssql or mysql, instead I will learn my way around postgresql...  (There are few good examples of projects that work really well on more than one main DB.  Most other projects support one DB well and others only with plenty of limitations...)

At the same time, I think moving onto someone else's code for request handling would be a good thing.  I would just prefer not to invest a lot of effort in it while the codebase is in the kind of flux it is at the moment, and so far Mojolicious seems like the obvious choice. 

Well, it's not the only game in town, but *I* like it and it seems a good middle ground between catalyst and Dancer.  It's fairly small and self-contained, good quality code and it's only lightly "opinionated".

In the case of LSMB I really think it can develop:
1) Drop in initially as a CGI replacement
2) Next use the router to simplify dispatching and decoding of business logic such as form handling/auth
3) Next up abstract the templating and router features to unify output as html/pdf/ps/json/xml all via a single controller call, all that should vary is the output presentation of the call. Also use the reverse routes feature of the router to generate your internal links around the app

Step 3 is a good bit of development along, but step 1 and some of 2) should drop out fairly easily.  At this point you will naturally have a structure on the app such that one develops in a much more modular fashion anyway.  There is no need to change the core business logic of LSMB in any of the above, it's completely about abstracting the CGI side, routing requests to controllers, and optionally improving presentation abstraction such that generating a PDF is the same basic code path as generating an HTML view.  Increasing use of controllers and pushing the business logic into yet more LSMB:: classes will mean you are increasingly insulated from knowing that you are being called by some CGI.


Ed W