Since the first post in #ourstack, I wanted to write about my prefered components for web application development. This is my first post and I will name the components, show alternatives and explain why I find them superior to any alternative ;)
I will also talk about the different components used at work and why we choose them (if not just legacy).
Disclaimer: I will not tell you where I work, but it may be googleable. There are better software projects at work but I will only tell about the one I have to work with most of the time.
Cut between frontend and backend / REST
Good
I really like a nice, smooth cut between frontend and backend. If you start a new web application of any kind, start with an API description. Make this description as complete as possible. Use something like OpenAPI for your description, as this is reusable, machine readable and human readable. You could even reuse this description as a complete documentation for your API and making it usable by third parties is just a matter of configuration, if any.
When everything is running over the API, it is easy to make an app for your app, connect other services and script things. It may also be a lot simpler to test frontend and backend (spin up a test server with static data or run scripts against your development backend to test it).
Also, with an REST API, you only transfer data between your server(s) and your end user. The application is only loaded once and (hopefully) already cached. This is extremely important for any web application which may be used on slow or expensive internet (mobile network, out of data volume, ... meh).
Bad / the way we work
No cut. Our server code has database operations right before page content functions calls. Something like this:
my $rs = $c->dbi('Table')->search({foo => 'bar' });
$page->add_js('$("#foo").hide();');
You really do not want to do this. We did it this way because the time this project started, nobody at work knew better (some more years ago). But, choosing this kind of architecture, it is really hard to change it later. Also, lots of our customers are industrial customers - we are happy if they use Internet Explorer 7.
Frontend frameworks
Angular 4
I enjoy writing client side applications in Angular 4. It is not JavaScript (a good thing). It does use Webpack by default (another good thing). It has great tooling (yet another good thing (I'll stop that thing now)). It is also used by Google, has a good documentation and community.
The only thing I don't like about Angular is the relatively high code size on deployment.
The old way / what we do at work
Our frontend at work is a big bunch of javascript files (named something like "global.js" and other nearly as good names) combined with jQuery, inline css and, please do not hurt me, even inline javascript. It is really not nice to work with that, but it works.
Our HTML is generated on the server and delivered to the client. Nothing works without javascript, but everything works down to IE8 and sometimes even IE6.
Alternative
This has some advantages, but I would strongly suggest not to do this. If you cannot use a fancy client side web application framework, maybe doing another server side application which calls your REST API is an option? You can change the frontend without further problems and you can even have both at the same time.
Server side / backend
Perl, AnyEvent, Dancer2, DBIx::Class
Perl, AnyEvent
I really like the perl programming language (perl 5 for the nitpickers). It has a lot of great modules ready for installation. It is flexible enough to not be in the way for asynchronous programming and it is easy to write. With some practice and coding standards it's also easy to read, even if other people tell otherwise ^^
A great module for async programming is AnyEvent. It does all the annoying things and just works. You can do file operations, background processing and other things with it and easily serve multiple clients at the same time with just one worker. There is also a ready-to-use webserver for AnyEvent: twiggy. And the best: Twiggy works great with Dancer2's async route support.
Dancer2
One of the coolest modules for web applications in perl is the Dancer2 framework. The most basic example is like this:
# lib/Dev/To/Dancer2/Example.pm
package Dev::To::Dancer2::Example;
use Dancer2;
get '/' => sub {
return 'Hello dev.to!';
}
1;
# app.psgi
use Dev::To::Dancer2::Example;
Dev::To::Dancer2::Example->to_app;
This is a simple hello world app, returning 'Hello dev.to' at the / url.
Alternatives
A popular alternative to Dancer2 seems to be Mojolicious, which also seems to be the successor of Catalyst. Mojo seems to be much more complete, but also like an isolated bunch of components where everything is rewritten to match that frameworks philosophy or something. I may be wrong at that^^
Also, when doing REST-APIs, you may also look at Raisin or PerlSwagger (not yet on CPAN, will be rewritten, written by me). Both are frameworks aimed at api-only web applications.
DBIx::Class
Most web applications have some kind of database. I prefer relational database systems and especially PostgreSQL. Because writing SQL queries by hand is annoying, inefficient and - when done incorrectly - a security nightmare, I always use DBIx::Class in my applications.
DBIx::Class is an Object-Relational Mapper which means, it has classes for all your tables and you get objects for every database query - either ResultSets (i.e. multiple results, a whole table or no result at all) or Results (a single row from the table). It can also handle your relations and give you the artist of your album - if you have the right foreign keys.
I also like defining my schema in code and prefer giving the versioning of the database to code, too. My favorite for that is DBIx::Class::Schema::Versioned::Inline.
What we do at work
Our stack at work is a little bit outdated, but not as bad as our frontend.
We use Catalyst for the foundation of our web application. We have some custom plugins thrown into it and do some hacky things to have some global things (like the Catalyst object we use to access our database and stuff).
For our database we use DBIx::Class almost exclusively. There are some hand-written queries, mostly for performance reasons. Our schema is versioned manually and updated in the database. We generate our DBIx::Class classes from a reference database.
The worst hack we have is the runtime-patched DBIx::Class to support our non-foreign-keys (we have foreign keys but the database does not know about them) and our virtual file system, loading all packages from a single file delivered to the customers server.
Sadly, we do not even use templates very much. Most of our pages logic is in the controller where it belongs, but also what the page should look like is located there ... we have a lot of inline javascript and css, which bloats our generated HTML - mostly just for having the same code with just another generated ID.
We have a pretty nice form generator, though. Most of our pages just store things in a database entry and look something like this:
package pages::test::simple;
use Moose;
extends 'core::GUI::Page::Detail';
has '+default_form_groups' => (
default => sub {
return [
{
label => 'Element details',
elements => [
{
# generate form elements automatically for the database columns
columns => [qw(name description starttime endtime)],
},
{
# or set things manually and have more control
type => 'text',
readonly => 1,
label => 'Name of related entry',
column => 'fk_other/name',
}
],
},
];
},
);
1;
I really like our form generator, it is just annoying it can only work with the database. If you do something not stored in the database you have to do a lot on your own. Mostly this means creating the form elements, telling them they are not saved, adding IDs and do an AJAX request to a server-side function doing the work ... It works, but is not that great.
Conclusion / the end
When writing a new web application, try to cut a line between your business logic, you pages logic and the way the pages define how they look. One of the greatest ways to enforce this, is to use a REST API between 2 different applications: frontend and backend. This is the most important rule for me and I also try to spread it at work (and because of customer demand: this may actually been successful \o/).
I hope you learned something new and I did not write something wrong or boring. Please comment if you have questions or I made some mistakes here.
Thank you for reading!
Top comments (2)
Wow I haven't heard of anyone pro-perl since the '90s. Thanks for sharing!
Count me in on the pro-perl thing please.