Yesod

What’s a Widget, Precious?

August 2, 2016 Web frameworks, Yesod No comments

Widgets in Yesod are a way to add some nice features – like order independence – to created parts of page.  That’s because Widgets are more semantic elements than a set of tags – they also contain some information about tag location – for example if it should be inserted in the header or body of the page. For example, let’s assume we want to add a button that will redirect from each detailed project page to the list of all projects.

To do this, we’re gonna create a Hamlet template (in templates/back-to-projects.hamlet) for the widget first. It’ll contain the following code:

<div .comeback-link>
  <a .btn .btn-default href="@{ProjectsR}" role="button">Back to project list

Then let’s create a Cassius template (templates/back-to-projects.cassius) for styles:

.comeback-link
  margin-top: 10px
  margin-bottom: 10px

And in the end let’s use these templates in our Handler/Project.hs:

renderPage :: (Int, Text) -> Widget
renderPage projectEntry = do
  setTitle $ ("Project " ++ projectTitle)
  $(widgetFile "project")
  $(widgetFile "back-to-projects")
  where
    projectTitle = (toHtml projectId) ++ (toHtml projectName)
    projectName = snd projectEntry
    projectId = fst projectEntry

As a result, we get a nice button below the description of the project – this way we can add widget after widget to the page. Of course, we can also compose them to create bigger widgets. Now, that’s not something very interesting – after all we just added a piece of HTML below our previous HTML and it appeared below, so what’s the fun? Well, a bit of fun happens with the stylesheet and JS files (we don’t have a JS file here). Stylesheet got minified and added to the page stylesheet, returned in the header. If we had a JS file, it would also be included as a script (or file, depends on configuration) in the header. Of course, it may be that you actually want the JS to appear in the body – for this, Yesod offers toWidgetBody and toWidgetHead functions, which let you modify HTML head and body respectively. Widgets can be used not only for web pages – there are also functions – like toWidgetMedia that can help you create all other types of data, including print styling or API.

One more note – if you wonder what a Widget is, it is just an alias for WidgetT <<AppName>> IO (), where <<AppName>> can be defined in Application.hs (by default it’s MyApp). It is important to note that Widget is typed per-application. And we’ll discuss why exactly is it important next week, when discussing foundation datatype.

Stay tuned!

404: Not Found

August 1, 2016 Web frameworks, Yesod No comments

In the previous post we’ve managed to create a page with links which are typechecked. I believe that’s really cool, but we’ve missed one ultra-important feature: error 404: Not Found. Current implementation (available with step-by-step changes all the time at GitHub) returns a default page in this case – with <<Unknown>> project. That’s an ugly workaroud for the fact that we didn’t know how to return errors back then. Now we’re going to learn how to do it.

Let’s start with splitting getProjectR (in Project.hs) into three separate functions, like that:

getProjectR :: Int -> Handler Html
getProjectR projectId = defaultLayout $ selectPage projectId

selectPage :: Int -> Widget
selectPage projectId = renderPage project where
  project = maybe (-1, ""::Text) id projectEntry
  projectEntry = find (\x -> (fst x) == projectId) projects

renderPage :: (Int, Text) -> Widget
renderPage projectEntry = do
  setTitle $ ("Project " ++ projectName)
  $(widgetFile "project")
  where
    projectTitle = (toHtml projectId) ++ (toHtml projectName)
    projectName = snd projectEntry
    projectId = fst projectEntry

I’ve added type signatures to top-level functions, both to make GHC stop complaining and to introduce another important topic which we’ll discuss later in the series – Widgets. For now let’s simply assume that Widget is part of a web page.

Now, since selectPage is the only entity aware that something might go wrong, we should change it to return a 404 page in such case. It actually turns out to even remove some code:

selectPage :: Int -> Widget
selectPage projectId = maybe notFound renderPage projectEntry
  where
    projectEntry = find (\x -> (fst x) == projectId) projects

Check it out – it really does the job!
When I started writing this post I thought about implementing it the brute force way (fromJust). However, classy-prelude, a modified version of standard library which Yesod relies on doesn’t have a fromJust function. That turned out being actually quite nice, as I believe current implementation to be quite elegant, while the brute-force one would by, by definition, a brute-force one.

Next episode – more about Widgets – coming still this week. By the way, sorry about the delay in adding this post, I wanted to add it during the weekend but was unable to. I’ll do my best to avoid such situations in the future.

Typesafe routes

July 28, 2016 Web frameworks, Yesod No comments

Greetings and salutations!

Todays’ post will be about – you guessed it – typesafe routes in Yesod. First, let’s talk a little about what does a “typesafe route” actually mean. Type safety is related to compile time (perhaps with exception for dependent types, but let’s not dig into it for now), so all guarantees you can get are compile-time guarantees. Compile time guarantees are related to the structure of data rather than the data itself. So, for example, if we used a typesafe route for the example from previous post (/project/#Int) it would prevent us from directing to /project/phew, but not from /project/423, regardless whether /project/423 did actually exist – it is not possible to decide in compile time, and it might exist, so the route is allowed.

And there is one more drawback – typesafe routes are type-safe only in scope of your site (and of course do not guarantee reachability, network connection etc.). It might be a lot or a little, depending on your use case – still, it’s more than other frameworks offer out-of-the-box. What’s important is to remember that – while they might simplify your life – they are no magical way to solve dead link problems. And of course 404s will still occur, so usual testing is still needed.

Enough talking, let’s write some code. Today we’re going to make a link-per-project on the /projects route. We already have the routes both for main projects page and for each project (no content though!), so today we’re just going to link them together.

First, let’s extract the projects to a separate file – in the end it’ll be a database, but for now a separate module is sufficient. Let’s create a new top-level directory, Database, a module Projects there and export projects constant from there:

module Database.Projects (projects) where
import Import

projects::[(Int, Text)]
projects = [(1, "Project 1"), (2, "Project 2"), 
  (4, "My extra project"), (5, "Project 10")]::[(Int, Text)]

then add an import to both Projects.hs and Project.hs:
import Database.Projects(projects)
.

In Projects.hs remove projects = ["Project 1", "Project 2", "My extra project", "Project 10"]::[Text] (it is loaded from Database.Projects module) and in projects.hamlet change projectName variable assignment to a tuple: (projectId, projectName) (compiler will complain that projectId is not used, but we’ll use it in a minute). You can check that everything still works fine.

Now let’s change Project.hs file. We’re going to display both title and id of the project. Database.Projects is already loaded, but there is a little trick: it might be that requested project does not exist. Ideally we should return a 404: NotFound in such case, but for now we can live with some default behavior (no worries – we’re gonna raise a 404 in the next post)

getProjectR projectId = defaultLayout $ do
  setTitle $ ("Project " ++ (createTitle projectId))
  $(widgetFile "project")
  where
    createTitle projId = (toHtml projId) ++ projectName
    projectName = toHtml $ maybe "" snd projectEntry
    projectEntry = find (\x -> (fst x) == projectId) projects

this might look a little complicated, but the toughest thing here is handling the default case. Let’s also add 

Name: #{projectName}

to project.hamlet, so that it’ll be easier to see if it works. Check that everything works fine – it should.

And now, time for the clue – routes. They’re quite simple – just change

<li .list-group-item>#{projectName}

to

<li .list-group-item>
  <a href="@{ProjectR projectId}">#{projectName}</a>

in projects.hamlet.

And that’s it. Congratulations, you’ve just created a set of type safe routes in Yesod! Next episode – about handling failure cases – comes still this week.

Stay tuned!

Routes with parameters

July 25, 2016 Web frameworks, Yesod No comments

Hi all,

sorry for the long break. It started with me getting the last DLC for The Witcher 3 – Blood & Wine (check it out if you didn’t play it yet), and then loads of stuff happened. Anyway, I’m back and I’m going to do my best to make up for the delay. Let’s start with parametrized routes, like /project/10, eat/200 etc. We’re going to add support for such routes in our project management app for each of the projects, indexed by some unique ID (artificially given).

Yesod handles routes in a relatively simple way – whole route is splitted by ‘/’ (forward slash) and a list is generated – for example, /project/2 will translate to ["project", "2"]. Don’t worry about trailing slashes or double-slashes, Yesod has you covered – routes are translated to a canonical form and users are redirected to them. In Yesod you specify a route parameter by it’s expected type name preceeded by # (if the value is between two forward slashes) or * (in case of more complex type).

Hence adding a new route is simple – just add

/project/#Int ProjectR GET

line to config/routes and we’re done. Well, not entirely – we still need to add proper handler, and that’s what we’re going to do now.
To do it properly, create a Project.hs file and add it to all required places (you can check which places are required in one of earlier posts). It’s content should be simple:

module Handler.Project where
import Import

import Yesod.Bootstrap()

getProjectR :: Int -> Handler Html
getProjectR projectId = defaultLayout $ dodo
  setTitle $ ("Project " ++ (toHtml projectId))
$(widgetFile "project")

This also requires a projects.hamlet file, equally simple:

<div>
  <h1 .page-header> Project: #{show projectId}

aaaand it’s working – check it out yourself! Here’s a little bonus – on a request for a resource that doesn’t match the type signature (for example, project/x) Yesod will automatically return 404: Not Found without even bothering you. Current 404 page isn’t nice, but it’s customizeable, obviously (we’re gonna deal with it in the future).

You might’ve wondered what will happen if you create two routes matching the same pattern, for example /project/#Int and /project/#Text (overlapping part is everything that is parseable by /project/#Int). Try it out yourself! Apprently, quite a nice exception is thrown:

Overlapping routes:
("ProjectR","ProjectR")

but what if you actually want routes to overlap, and simply choose “numeric handler when argument is numeric, and textual when it isn’t”? Good news is that you don’t need to push parsing logic into the handler – you simply need to change the route definition from /project/#Int and /project/#Text to disable overlap checking – but only for these routes. If you do that, be aware – first matching route wins, so be careful with the order!

Next episode – linking with typesafe routes – coming still this week. Stay tuned!

Working on the Hamlet template

July 9, 2016 Web frameworks, Yesod No comments

If you’re following the series, you definitely saw how ugly our page was at the end of the last post. Well, good news – we’re gonna fix it right now. Before you close the window, let me explain: I’m not going to start doing graphical design here, as I do not know enough about it. Instead, I’m going to show you how to use Yesod with one of the best design libraries in the world – Bootstrap. Yesod has kind of built-in support for Bootstrap – you might’ve guessed it by the import Yesod.Form.Bootstrap3() line in Projects.hs. It’s actually not exactly what we’re looking for, so let’s change it to import Yesod.Bootstrap() and add Yesod.Bootstrap to build dependencies in .cabal file. You might need to run stack solver --update-config && stack build before next run.
And that’s it – Bootstrap is already included in our files. Now let’s get rid of the ugly projects.cassius and let’s replace it with some nice styling!

But before this, you might be a little surprised that including Bootstrap didn’t require us to add any additional CSS files. That’s not actually true – we simply already have one. It’s located in static/css/bootstrap.css. If you are able to access the site after running stack exec -- yesod devel, you have this file – otherwise the site wouldn’t even compile.

Now you can delete all the classes and IDs we used in previous post and replace the .hamlet file with something like this:

<div>
  <h1 .page-header> Available projects:
  <div .jumbotron>
  <ul .list-group>
    <li .list-group-item> Project 1
    <li .list-group-item> Project 2
    <li .list-group-item> Super project

looks much better now, doesn’t it?

The hardcoded project names are quite a shame, we should get rid of them. Let’s make our Hamlet template an actual template that is filled with some data! For the first shot let it be a simple list of project names – typed [Text]. Wonder why not [String]? Short answer is: it’s more efficient. For a slightly longer one you can check out The Yesod Book. Anyway, our goal now is to have a list of Texts passed to the template and same output rendered. To do this, we need to add a little big of logic to our template. Lines starting with $ are treated as special instructions, virtually typical Haskell operations. #{someName} is used for variable interpolation. Check out the code for projects.hamlet:

<div>
  <h1 .page-header> Available projects:
  <div .jumbotron>
    $if null projects
      There are no ongoing projects
    $else
    <ul .list-group>
      $forall projectName <- projects
      <li .list-group-item> #{projectName}

Quite a change, isn’t it? But it’s quite simple – if there are no elements in projects container we show a message, otherwise – list all elements one-by-one.

But the code doesn’t compile again. To make it work you have to add projects variable to the scope of widgetFile invocation. This can be done for example by adding

    where
      projects = ["Project 1", "Project 2", "My extra project", "Project 10"]::[Text]

to getProjectsR function.

And that’s it! we can feed the template via the list in Projects.hs file. Nice, eh?

Actually, no. Right now it’s even worse than it was – previously it was sufficient to modify projects.hamlet and yesod runner automatically reloaded all the stuff. Now the compilation has to be done manually, by running stack build. Have no fear, we will change this in the future. but the next step is different. The next step will introduce Yesod’s killer feature – typesafe routes.

Stay tuned!

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!