Month: June 2016

To code or not to code – the Hamlet template language

June 21, 2016 Web frameworks, Yesod No comments

Since we managed to successfully create a route, next step is to create an actual page to show it to the user.
While you can use virtually any Haskell template engine with Yesod, the built-in one uses Hamlet, Cassius, Lucius and Julius as its input. They are used to generate HTML, CSS and JavaScript files from templates. These four languages are known as Shakespearean templates – Hamlet for generating HTML, Cassius and Lucius for CSS (we’ll focus on Cassius, as the only difference is syntax of a block) and Julius for JavaScript – before you get too excited, Julius is not a transpiler – you have to write actual JavaScript, it’ll just do some variable interpolation. If you’re looking for an actual Haskell-to-JavaScript transpiler, you may want to take a look at GHCJS or Haste.

Remember our handler for projects, located in Handler/Projects.hs? We’re going to add some actual content now. First let’s add loading the page to handler. Here’s the new code for it:

getProjectsR :: Handler Html
getProjectsR = defaultLayout $ do
	setTitle "Projects"
	$(widgetFile "projects")

it’s important that the new part ($(widgetFile "projects")) is the last invocation in series, because it uses results of the earlier ones. Here’s an important fact: this code will not compile yet. That’s actually good news, because it means that Yesod got us covered against a situation where we forget to add the content (or the template name is not valid). To feed the compilation process it is sufficient to add an empty file located at templates/projects.hamlet. But what fun is an empty file? Let’s fill it with some static content, for example this one:

<div>
  <h1 .customTitle> Available projects:
    <ul #projectList>
      <li> Project 1
      <li> Project 2
      <li> Super project

Hamlet’s syntax is fairly straightforward: basically it’s like HTML, but uses nesting instead of closing tags. Also, you should only use a single tag per line (using multiple is possible, but they are not interpreted – i.e., you get what you write. Just don’t do it) and start the line with tag. While this seems reasonable, it leads to problems with whitespaces – suddenly trailing whitespaces in line start being important. Hamlet’s workaround for this is to provide escape characters: lines ending with # have their trailing whitespaces preserved, and lines starting with \ have their starting whitespaces preserved. # is a pretty important character in Hamlet – it’s also used for variable interpolation (we’ll cover it in the next post of the series) and assigning IDs to DOM elements (see ul element in the example above). There are also several other useful features like support for Maybe or conditionals, but we don’t need them now, so let’s not bother ourselves with them. Instead, let’s add a little style to our list of projects.

To include a custom stylesheet for our projects route, it’s sufficient to create templates/projects.cassius file and Yesod will understand that we want to use it. Let’s fill it with some simple content for now:

#projectList
    text-align: center;
    margin-bottom: 30px

.customTitle
    color: #FF0000

div
    color: #00FF00

now it looks really bad. But obviously it worked and stylesheet was included – go to localhost:3000/projects to check it out (remember to run stack exec -- yesod devel before). What’s also worth noting, this stylesheet was included only on projects route (don’t believe me – check it out yourself at localhost:3000).

I can imagine some of you wheezing: “sure, that’s all nice and fine, but what’s the actual benefit from using a new language? We could just use plain CSS for this, and industry already has Sass and Less to make life easier”. Well, you’re right – I didn’t show anything you can’t easily do with CSS yet. Bad news is that I won’t do it today – variable interpolation comes next, and that’s quite a nice feature – although I believe it’s much more useful for HTML templates than CSS ones.

Let’s sum up for today – we’ve managed to create a part of page that is injected into default-layout, but can contain own CSS and JavaScript (and HTML code of course). We also found out that .hamlet file is the only required part of the page, and the server will not compile without it – CSS and JS files will be included only if available (but if they are available, they will be included automatically). We also created a really ugly piece of layout, which we’ll probably need to fix later on – but that’s not a big deal, since we used it only to prove that stylesheets will be added automatically. Up to now the new template languages weren’t really useful – they simply had a bit different syntax. In the next episode we’ll explore their actual power – variable interpolation.

Stay tuned!

Yesod – first pages

June 14, 2016 Web frameworks, Yesod No comments

We already have a working environment – it’s the best possible moment to get started with teh codez!

Yesod, like many other web frameworks, has a Model-View-Controller architecture. It has a central controller instance which routes requests to proper handlers. In the scaffolded site these routes are conveniently stored in config/routes file. If you didn’t make any changes to it, it probably looks like this:

/static StaticR Static appStatic
/auth   AuthR   Auth   getAuth

/favicon.ico FaviconR GET
/robots.txt RobotsR GET

/ HomeR GET POST

/comments CommentR POST

it contains a lot of magic. It is a syntax which is later processed by Template Haskell to generate quite some code that guarantees type safety. For starters let’s skip first two routes and focus on the rest.

The syntax is fairly simple: route route-type handled-methods. So, for example, line /comments CommentR POST means: from all requests directed to route /comments accept only POST requests and define type CommentR which will be used to redirect to this route (in Yesod routes are type-safe, so you need types for them). Additional feature is that route handlers are invoked automatically – in out example it would be postCommentR function (you can find its implementation in scaffolded site in Handler/Comment.hs file. Handler names are created from lowercase method name concatenated with route type name. It’s a nice example of Convention over Configuration pattern, and it frees us from writing an awful amount of code which we don’t really want to write (at least I don’t). Adding R postfix (shortcut for Route) to route type is also a Yesod convention, which does not need to be kept, but may help others read your code.

Ok, enough chit-chat, let’s write some codez!

First, let’s edit config/routes. Just stuff in there /projects ProjectsR GET. Great, now your code doesn’t compile and complains about lack of getProjectsR function. Let’s fix it the way scaffolded site does it – create a Handler/Projects.hs file with the following content:

module Handler.Projects where
import Import

import Yesod.Form.Bootstrap3()

getProjectsR :: Handler Html
getProjectsR = defaultLayout $ do
    setTitle "Projects"

add the handler to <code>Application.hs</code> as well:

-- Import all relevant handler modules here.
-- Don't forget to add new modules to your cabal file!
import Handler.Common
import Handler.Home

-- new one
import Handler.Projects

as the comment says, you also need to add this file to your <code>.cabal</code> file to this block:

        exposed-modules: Application
                     Foundation
                     Import
                     Import.NoFoundation
                     Model
                     Settings
                     Settings.StaticFiles
                     Handler.Common
                     Handler.Home
                     Handler.Comment
                     Handler.Projects

that’s important, because if you won’t do that, you’ll get an unknown symbol error at startup. Now run stack exec -- yesod devel and go to localhost:3000/projects. The result might not be very impressive (an empty page), but you might guess that it’s already using our route – it has our title (not very impressive either).

That’s all nice and fine, but if you take a look at the page source, you’ll notice that there’s quite some stuff already, including Bootstrap and jQuery. Where did it code from?
If you recall the handler code, it was really simple: getProjectsR = defaultLayout $ do setTitle "Projects". All the magic lies in defaultLayout call. It picks up a default (for the project) layout file and fills it with data from the argument. This default template layout is split between two files: default-layout.hamlet and default-layout-wrapper.hamlet, both in templates directory. .hamlet is an extension for Hamlet files, which are Haskell form of HTML templates, serving roughly the same purpose as Jade, Jinja or Smarty. I’ll cover Hamlet templates in greater detail in the next post – for now let’s just treat a .hamlet file as a HTML without closing tags. Since pretty much everything seems to be in default-layout-wrapper.hamlet, you might wonder why are there two – this is generally related to the purposes – default-layout-wrapper.hamlet is roughly a static structure that will be filled with data, while default-layout.hamlet is more dynamic and can contain some conditional logic and similar stuff. Additionally, CSS and JavaScript files with the same name are automatically added to default-layout.hamlet (this is because default-layout.hamlet is treated as a usual Widget. We’ll talk about Widgets later in the series). Go ahead, change something – for instance, add a new div in default-layout.hamlet and some text in default-layout-wrapper.hamlet and refresh the page. See how default-layout.hamlet was inserted in place of ^{pageBody pc} ?

If you don’t, go ahead and call stack exec -- yesod devel. Remember that stack might be able to reload Hamlet templates, but is not really able to hot-swap actual Haskell code, so you might need to restart it, especially when adding new files.

That’s it for today – in the next episode we’re gonna create a template view for our projects.

Stay tuned!

Environment setup

June 7, 2016 Web frameworks, Yesod No comments

Let’s start with the tooling.

Obviously something can go wrong during development, so version control is a must. I prefer Git, but if you use Mercurial, Bazaar or Subversion (or whatever else) it’s fine as well. If you wanna feel super-haskellish, try out Darcs.

As for OS platforms, this series will cover Windows and Linux setups. I’m going to use Windows 10 and CentOS Linux (a RHEL derivative), so if you’re using Ubuntu you may need to adjust the code a little (e.g. use apt-get install instead of yum install), but there shouldn’t be bigger differences – if you’re using something like Slackware, Arch or Gentoo, I assume you already know what to do better than I do. As for Windows, it should work out-of-the-box on all reasonably new machines (say, starting from Windows Vista up).

A few more words about the setup before we dive into the code: while working code examples can be found on my GitHub repository dedicated for this blog: https://github.com/Lewerow/SlightlyBetter, I do have quite a complex local setup, involving a version control server and a continous integration server. I use a local setup of Gitlab along with Gitlab-CI on a CentOS sitting inside a VirtualBox. While this sounds pretty complex, it’s not that bad – I’m going to cover automatic creation of such setup in one of future series.

Anyway, let’s get back to Haskell and Yesod stuff. Setting up a simple web page from existing template (“scaffolded”) is generally quite easy, but might require installing some extra packages. First let’s install  Stack – a build tool for Haskell projects. Installation is typical for your platform (installer for Windows, .rpm packages for CentOS, .deb packages for Debian) and is described in detail in Stack documentation.

Only thing that still remains to be done is executing following commands (beware: it takes some time):

stack new TaskOrganizer && cd TaskOrganizer
stack build yesod-bin cabal-install --install-ghc
stack build

Assuming that everything went fine (which is not obvious on Linux machines – you might need to install additional development packages, like build-essential, zlib1g-dev or libpq-dev – watch out, .rpm development packages usually use -devel instead of -dev used in .deb packages), you now have a working Yesod site. Check it out by running stack exec -- yesod devel and going to http://localhost:3000/ with your browser. If it worked – congratulations! Your first Yesod app is up.

Next week we’re gonna do more stuff – add custom routes for projects. Stay tuned!

And don’t forget to add your project to Git! (For example by git init . && git add --all . && git commit -m "Initial commit")

Yet Another Web Framework?

June 5, 2016 Web frameworks, Yesod No comments

If you’re writing a web application, it is likely that you aren’t going to write all the code from scratch – there is a tremendous amount of work that was already done dozens of times and you don’t really want to repeat it. So you’re going to pick a framework – and it isn’t easy! Rails, Hanami, Django, Flask, Express, KOA, Spring, Play, Lift, Phoenix, Revel  and dozens of others, most of which I’ve never heard about. Why create next one? There are several reasons, language focus being one of the strongest. Rails, Hanami, Padrino and Volt focuses on Ruby. Django, Flask and Pyramid on Python, Express, KOA and Synth on JavaScript (specifically Node.js), Spring and Struts on Java, Lift and Play on Scala (though Java/Scala framework division is a little artificial, since Play works on Java as well), Phoenix on Elixir, Revel on Go etc. Another one is the focus on programming model – most of the popular frameworks use MVC (Model-View-Controller) approach, but some – like Lift, Wicket or Asta4D – use different, View-First approach. Of course, there are also lots of different reasons – changing some old paradigm, using new language feature, solving a problem other frameworks have for long time or simply “writing a more elegant framework”.

In such a jungle, choosing the best framework for the job is vitually impossible, so we settle for “good enough”. And this usually boils down to choosing one of the most common frameworks – Rails, Django or Express, possibly Spring if your company is Java-inclined, or something from Go if you’re feeling hippie (or maybe Elixir or some other new language if you’re feeling super-hippie).

And it is usually a good decision – not a perfect one, but good. You know the language, you know the framework, you can write code fast. Cool, eh?

Well, yeah. If you’re writing a one-team app or a prototype, or at least an app in write-and-forget mode, then choosing Rails, Express or Django is a great choice. But for bigger projects, well… sure, it’s possible. But if you lack discipline your Sentry (you have Sentry or something similar hookend up on your production servers, right?) will start shouting with things like undefined is not a function or 'NoneType' object is not callable. If you have discipline things are slightly better and you simply have to maintain gazillions of unit tests for all weird scenarios where internal flow was not valid or user data was not properly sanitized or whatever. And you usually have to either maintain these unit tests forever, or drop features. What’s worse, these UTs usually aren’t well-written
and are an obstacle for refactoring, while you would want them to aid it. Sounds familiar? Well, bad news then – it’s not a problem of the framework.

There are two main reasons for such situation: one is obviously the development process – with a perfect process and discipline, you can go really far with any tool you want. But using the right tool makes it easier (or at least forces you to keep the discipline). Dynamically typed languages, like Ruby, Python or JavaScript are great for small projects, small teams or prototypes, but on bigger ones well-known problems appear: interfaces. It’s hard to define interface on a language that roughly checks the syntax of the source code – of course, possible, but much harder than in statically typed languages with compilers – like Java, Scala, C++ or Haskell. There are attempts to create things like “JavaScript with types” (TypeScript, Flow), but this simply doesn’t work – it’s a part added artificially to a language after it’s already in the field, and doesn’t really make people happy.

Statically typed languages, on the other hand have another problem – they usually have a steep learning curve, and some of them (for example, Java) require quite some boilerplate to create reasonable applications. Scala with its type-safe approach is much better in the area of enforcing interface contract – value of features like type-safe database queries is hard to overestimate. Scala is quite a new language (started in 2001) with a very interesting paradigm and full power of the JVM behind – it’s really worth checking out.

However, in this series I’m going to focus on a different alternative to Ruby/Python/JS frameworks. One that is considered arcane and hard and has quite a steep learning curve if you have mostly a dynamically-typed background. I’m going to show you how to develop a simple web application in Haskell, by using its arguably biggest web framework – Yesod. If type-safe database access sounds like “wow”, then you’re going to like it – in Yesod even routes are type-safe. And since I’m lazy, I believe in tools imposing as much useful restrictions as possible. Since I believe type-safe stuff to be incredibly useful, I’ve decided to give it a try. This is the first post of a series of introductory posts to Yesod (occassionally also with Haskell insertions). Fun starts next week.

Stay tuned!

Greetings and salutations

June 5, 2016 Meta No comments

Welcome to SlightlyBetter – a blog about doing IT stuff slightly better than before.

I’ll mainly focus on automating testing, deployment and configuration, but there will be also occasional posts about programming and software development in general. I hope you’ll be able to learn something and develop software that is slightly better than you developed before you visited me.

First series, about using Yesod to implement a simple web application starts next week

Stay tuned!