Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: IHP, a batteries-included web framework built on Haskell and Nix (digitallyinduced.com)
280 points by _query 17 days ago | hide | past | favorite | 70 comments

I really enjoyed your introduction. For the HN readers who enjoy summaries in the comments, they open with a 10-12 sentence introduction, but the second sentence sets up the core philosophy and primary value proposition:

> Back in the early days of the web, when server-side rendering was still a thing, javascript was sprinkled here and there to make a few parts of your web app just a little bit smoother.

It's "built on top of Haskell and Nix."

The more detailed 20 minute introduction and documentation is located at: https://ihp.digitallyinduced.com/Guide/ I think the "recipes" section provides some illuminating examples.

The creators make the following claims about durability at the end of their introduction page:

> Lots of frameworks are already gone a year after launch. Especially in the fast moving JS world. But don't worry about IHP. We have been using it at digitally induced since 2017. It's actively used by us and our friends and partners. Even without external contributors we will build new features and do periodic maintenance releases in the future. We have big plans for IHP and as a profitable and independent software company we have the ability to actually execute them over the longterm.

I'm very skeptical of web frameworks / toolkits. While I only work on personal projects, I tend to try to use pure HTML first, then add CSS where needed, then add JS where needed, then add backend where needed - always striving to minimize the amount of the next layer. This project seems to be targeted to someone with my preferences.

I'll definitely be keeping an eye on it, and poking around with it.

> For the HN readers who enjoy summaries in the comments

This was a good reminder that I should at least skim the article first.

On the other hand I wonder if there's a way for HN/Reddit to help people write summaries in comments. (Perhaps even recursively!)

Important bit missing from the title: this is using Haskell (and Nix).

IHP is supposed to become the Django/Rails/Phoenix of Haskell.

I've been using Django professionally for since 2013, but have started using IHP a couple of weeks ago. It's still quite early but with surprisingly few rough edges, i.e. the developer ergonomics are much better than I expected. It has great documentation that is improving rapidly (as opposed to many other Haskell libraries, which provide little more than API docs or even just the typed function definitions) and offers a refreshing take on database management and migrations.

Some of its killer features:

- HSX, a JSX-like template language that looks like HTML while providing type safety

- Auto live reloading without the need to setup anything

- Documentation with examples: it lets you query the database without learning about monads

- it defines |> for you ;-)

- type-safe, composable SQL queries:

  projects <- query @Project
    |> filterWhere (#userId, userId)
    |> filterWhere (#deleted, False)
    |> orderBy #createdAt
    |> fetch

> IHP is supposed to become the Django/Rails/Phoenix of Haskell.

And like these other server-side web frameworks, IHP is SQL centric. What sets it apart is the IDE integrated into the dev server. The IDE together with Nix allows IHP to be PostgreSQL only, avoiding out-of-band server installs and providing a UI for schema/model construction.

This is an interesting option and seems to have appeal beyond Haskell enthusiasts.

To help me understand better, what would be an example of an "out-of-band" server install?

I should have qualified it as "RDBMS" server install. Most new SQL-centric web frameworks support three Open Source RDBMS engines: 1. MySQL, 2. PostgreSQL, and 3. SQLite. SQLite is rarely considered appropriate (arguably) for the server-side deployment RDBMS but its value comes from being embedded in the language runtime or web framework so it is available during development. IHP includes PostgreSQL as a Nix dependency so it is as ubiquitous as SQLite in the developer environment. "Out-of-Band" is relative to the project dependencies.

Using PostgreSQL in the development environment for say Rails or Django requires "out-of-band" installation, configuration, and management. Frameworks like Rails and IHP apply the schema/migrations to a live development RDBMS and read the Catalog Metadata to generate the classes/structs used as the Data Access Objects (e.g. ActiveRecord in Rails). The RDBMS, therefore, is part of the CI/CD pipeline.

Other ORMs define their entities independent of the RDBMS. I think Java JPA and Apple Core Data work this way; the SQL DDL is generated from the Entity Model. YeSQL-style frameworks also require a live development RDBMS but they extract metadata from each prepared statement rather than catalog metadata for each table which is mapped to a class/struct.

I think sradman means that Nix enables IHP to guarantee the presence of postgres, rather than relying on the user to ensure pre-requisites get installed.

Edit: Gah. :)

A much more succinct and appropriate answer than mine :-)

(We put those in the title after this was posted.)

I get the type-safe part, assuming it means the eventual query will produce a predictable result set compatible with wherever it's being read into (I'm not a haskeller), but a) SQL is easy enough to learn syntactically b) there are good reasons not to create dynamic SQL; it's better to write it such that a query plan can be cached (for scalability). Which is very likely possible here but is it done?

I wonder if the person who wrote this understands SQL to sufficient depth. Not saying either way, just asking.

You really can't avoid dynamic SQL if you need it for your software. For example, if you give your users the ability to select filters to apply to the data fetched from the DB, you will have to dynamically create the SQL unless the number of possible filters is extremely low. Above a certain scale this might not be feasible for predictable performance, but not everything has billions of rows.

The choice isn't to use dynamic SQL or not in these cases, it's whether you implement the feature that requires dynamic SQL or leave it out entirely.

Though interestingly (as you acknowledge via "if you need it") that also tends to be the only time a traditional site/app does need it: a /search endpoint.

Your point a) is moot, this is not what this is about. When writing manual SQL nothing stops you from doing `SELECT * FROM persons WHERE age > 'eighteen'` (the `age` field is a number, obviously). Coming from Django I was often bitten by `Person.objects.filter(age__gt=trashhold) # boom!` (note the misspelled variable "threshold") or, if you prefer manual writin SQL: `Person.objects.raw("SELECT * FROM persons WHERE age > {}", trashhold) # boom! as well`. (Admittedly this is unrelated to type safety, just a disadvantage of Python being interpreted, but still something that Haskell/IHP protects me of.)

Regarding b), yes there are good reasons for prepared statements. I won't go into your argument "for scalability" (premature optimization cough) but cached query plans aren't perfect either: data and data typologies change, and so does the optimal query plan. See https://blog.soykaf.com/post/postgresql-elixir-troubles/ for a blog post about Elixir/Phoenix/Ecto users being bitten by that.

> I wonder if the person who wrote this understands SQL to sufficient depth. Not saying either way, just asking.

I did not write the IHP code, just the above comment. But I've read many of CJ Date's books and have a good grasp on the relational model, and of SQL too. I simply don't see things as black/white, there are certain queries where I do prefer prepared statements and functions, or PL/pgSQL even, then there are ones where I use an external .sql file to keep things tidy. But most of the time (especially in the user facing part of a web app) I like my ORMs or SQL DSLs.

Unless you've got `trashhold` actually defined, tools like flake8 would protect you from that mistake with Python.

Using type hints would also protect you from using variables with incompatible types with a better designed API (Django's ORM API is anything but).

As for SQL performance, I've usually only worked with up to hundreds of millions of rows per table, and the most important thing at that scale was to attempt to keep indexes in memory cache (that improves or degrades the performance by a couple of orders of magnitude). I haven't had a need for query plans to be cached, though I did use subselects to force particular query plans when needed (which has the similar problem of query plans not being the most efficient ones when data evolves sufficiently).

The SQL composition seems really intuitive. I'm pondering whether it's worth the effort to port my Servant application to this or not.

IHP includes a GUI to build postgres schema - this is really cool and much appreciated. Databases have been existing for ages now and so are the GUI tools to manage them. However, it's unfortunate that most web frameworks fail to provide functionalities like this.

Working in similar space[1], I have been talking to many early customers. Right from somebody who knows enough programming to product managers to CTOs, the idea of having a GUI within web framework and to have CRUD APIs ready with just few clicks gives them an amazing head start in building web apps. Getting past this redundant phase of creating basic CRUD with no hassle means - they can devote their energies on the business side of things. It will not be wrong to imagine in few years this workflow will become a norm.

[1] : https://github.com/xgenecloud/xgenecloud

> It will not be wrong to imagine in few years this workflow will become a norm.

I hope so too but we had this in different forms since the early 80s already (maybe earlier) and it never got big for some reason.

>> we had this in different forms since the early 80s already

Could you name them, happy to check them out.

I think enough time has passed that we're collectively forgetting the good reasons why so many moved from server side rendering, which I would say it was mostly the difficulty in make complex uis. Then it became a trend, now going old school seems appealing.

Anyway in my particular case if I had any project that was a good fit for server side rendering I would probably now go with php and some libraries but probably no framework. I've been looking at some "weirdly coded 90's style php projects". An while the code is a terrible mess there's also the magic that I can read everything that's happening pretty quickly because it's just there or in a file next to it and not hidden in a library and a sub-library with calls to functions that I never seen before.

I think the problem here is that you are setting up a situation where it is some binary choice between the insane complexity of SPAs and everything that entails and some random 90s style hand rolled PHP file.

There are a whole bunch of options between those two extremes and I can’t for the life of me think why people don’t talk about them more often.

For example, I think the new Hey.com implementation hasn’t received anywhere near the level of recognition that it probably should have.

It’s an entire email application with a single set of screens that power all web, desktop and mobile apps, does so with all the speed of an SPA, has no need for advanced state management, has the ability to push live updates on a per component basis on any screen and does it all in under 40kb of JavaScript.

Seriously go and look at the source code. I’ve only seen a tiny number of people talking about it like in this post https://dev.to/borama/a-few-sneak-peeks-into-hey-com-technol...

But to me the past few years of SPAs are starting to look more and more like a mistake to me where they became the rule when they should have probably been the exception.

Unfortunately it is hard for me to comment on the hey.com web app as they currently have restrictive registration.

The benefit of building with a de-coupled JS frontend (SPA) and an API is that it can extended and adapted far easier than using server-delivered HTML.

If you have an API that delivers JSON/Protobuf/whatever, you can easily make new interfaces to that backend. If you are currently delivering a web app in HTML/JS, but decide you want a native Mac/iOS app written in Swift, you'll just end up building an API anyway.

Sure, there are plenty of websites that wont ever need additional interfaces, but if your goal is to make an app that can easily have new interfaces added to the mix, de-coupling is the way to start in my opinion.

You make a good point, and this is one of the reasons why I really like the Phoenix web framework (of the Elixir ecosystem). It firmly guides you towards building applications where Phoenix is only a single interface to your underlying Elixir application, and the web layer, by design, doesn't contain business logic, but rather just gives you a web-friendly way to talk to the application itself. The community has come up with the mantra of "Phoenix is not your application" to drive this point home.

This approach and separation of concerns also means that building e.g. REST or GraphQL APIs on top of your application is simple, as your web framework has no say in how the data is actually structured or queried.

I hear what you’re saying. I think the main thing I would push back on is the order in which you make those decisions however. Why take on all the additional cognitive overload from the start of the project because you might want a native screen at some point in the future? It’s basically another version of the micro services debate.

I think there is a heavy if unconscious bias among web developers now that the “one true way” to build web apps is to take the same methodologies and frameworks from Facebook and Google usually.

I’m obviously not the first person to point this out but trying to replicate the software development processes of some of the largest companies in the world is in no way correlated with a better anything (user experience, dev experience, code, time to market etc).

In fact I would take it further and say that there are a not insignificant number of new developers especially from the dev boot camp style pipelines who literally don’t even know how to build anything without reaching for one of these tools. We saw the same thing with people reaching for Bootstrap or now Tailwind for a long time and not knowing how to do anything outside of it. This isn’t to give them a hard time, I have been that kind of Stack overflow driven developer myself for a long time. I just think that maybe as an industry we have made some poor choices that have become gospel overtime and it might be worth revisiting that.

To show off their frontend stuff, they left all of the JS available on https://app.hey.com without logging in. I think they plan on open-sourcing their improvements into new updates to Rails and turbolinks, eventually. If you've used Basecamp before it's fairly similar in speed, as far as I can tell (turbolinks + stimulus is responsible for that).

Here's the library they've written: https://github.com/turbolinks/turbolinks

For the record it is worth mentioning that there is a major update pending for that library that handles some of the specific things outlined in the post I referenced above, however, even in its current iteration I think it is a much more sensible default to reach for than say React & Redux would be for a large number of applications.

There is a second library that they have used along side that for handling all of the app specific JavaScript here as well https://stimulusjs.org/

Tech is a circle that goes round and round.

Remember when everyone thought NoSQL was a good idea and wanted to get rid of their relational DBs? Nobody remembered _why_ we went to relational DBs until after all of their data was duplicated and inconsistent in NoSQL solutions.

I think the root of this is a lack of appreciation for or lack of knowledge of the history of software engineering.

> I would probably now go with php

seriously? 2020 and you'd pick php for a greenfield project?

and you mention this here, where we're discussing a project that provides: strong typing, typed safe queries, type safe templates, and more.


Today's PHP projects (at least the ones for which I've done consulting) are modern and clean code bases that use strict/strong typing, run static analysers and have stellar package management thanks to composer.

PHP 8 is due to be released this fall which improves the situation even more.

Symfone is the web framework that had the highest count of contributions over all frameworks in all languages.

The PHP community took a 180 degree turn from the 90's style flat files with a mix of HTML, SQL and code in the last decade. That times are gone (of course that kind of code is still laying around)

For someone who already knows PHP, starting a project in 2020/2021 in PHP is an excellent choice.

Which other languages are you fluent with? I find many that love PHP have a bit of a "when all you've got is a hammer" bias in favor of it.

I had the same! Then I invested in learning some Haskell/ Elm/ Reason/ Rust/ Kotlin: it changed my preferences for ever. I now look for proper sum types and (pattern) matchers, strong typing discipline and null safety.

I use Scala, Typescript, R, some Go and some Swift daily and have been using typed languages for 20 years+ and would still recommend PHP to someone wanting to throw together a brochureware site for the best cost/hassle ratio.

Almost no one is solving FANG problems, and people literally throw their clients/businesses money away on poor value because they've lost focus on what's important: delivering a solution for what they need right now, not what you want to spend your time playing with.

Also what is the big deal with type safe templates when you're literally just abstracting building HTML strings?

I totally agree with what you're saying.

While PHP is still a joke compared to even Java which it very hard tries to become (which I think is a good thing), for someone who only knew PHP the entire time, the situation still got much, much better over the last decade...

I am someone using React, NextJS and Typescript who really wishes they went with Symfony. It'd be so much simpler.

I've heard you can combine React with Symfony, which sounds really cool.

You may want to try some more functional languages to complement your experience: Reason/OCaml/F#/Haskel/Elm/PureScript or even the more OO ones that copy some features over: Rust or Kotlin.

React is not a language. TypeScript is very close to PHP, both in imperativeness, in OO-ness, in did-not-initially-support-it-but-sometimes-added-it-later-but-now-its-a-mess-ness, in BW-compatible-ness, in quirkiness.

I’ve (informally) taught Haskell and I’ve used Elm/Erlang/Elixir/etc. I absolutely love functional programming and definitely regard it as the “ideal future”, but it’s not ready today. Especially the ecosystem.

I know React is not a language, but I listed the whole stack to compare it to IHP, which seems to try to combine everything. Which is good! I’d love a Django/RoR esque Haskell platform.

I love when people are shocked because someone decides which tech to use based on the merits of the tech instead of what the current year tech fashion dictates. It's hilarious.

Or, you know, simple things like being able to easily attract people. No matter how I prefer Purescript/Haskell/Ocaml/F#/k or even Idris (not practical but I like writing things in it); if I need people fast, PHP/C#/TypeScript are just a better bet (I am surprised how easy it is to find good people with these skills now; seems unemployment hit these as well?).

But it depends on what you are doing ofcourse.

> if I need people fast

Exactly, this is a real reason for not using the technologically superior.

For many years we went for the tech that made us implement software faster than others. We picked productive languages (clojure/lisp) or languages to express more with less and with less bugs, we wrote frameworks, DSLs and even a few language etc; it worked indeed and we were faster. However, longer term (5+ years) it would be impossible to find people to update/support the code. The win at the start (sometimes a win that would have us win large fortune 1000 projects over the competition) would suffer in the long term from no-one (outside myself and maybe 1 other person) understanding how it works (other people left/went on to other things etc).

So now we just mostly deliver things in old, boring but very standard tech. Using almost written by us and definitely no custom low level stuff like we used to. Because we did all that work before, we know how to optimise for performance everywhere, how to optimise dbs, how to optimise frameworks and webservers. We do everything according to the standards and best practices; now we know that we can get people in 20 years to work on our code. But it is much much slower at the start; so much setup and plumbing. Very boring and tedious. I guess that's the point.

Now to what extend is Haskell already boring and old? :)

It'd old, but it's not boring!

It's a fantastic reason. Writing code is a job. A well-run business is dictated by factors that will usually dominate language design.

If these other languages were better in a holistic sense, businesses would switch.

I would argue against the "technically superior" position on three merits:

1. Finance, 2. Median productivity 3. Long-term product stability

Network effects mean that familiar languages will dominate. PHP, C#, and Javascript are familiar.

PHP has had staying power because it is extremely well-documented (with examples) for the novice, prioritizes backwards compatibility, and is reasonably if not very productive for most developers. The documentation section of PHP.net is probably the most important language "feature" of PHP - it trumps almost any language design feature you think is important.

It reads easily. It's easy to implement. It interacts natively with JSON in a completely fluid way. The database handling routines are rock solid and fast. The core language team spends a lot time improving the safety and performance of existing code. There's a good debug story.

It's its own templating language - no need to bolt on a hand-rolled templating mechanism. Just PHP all the way down. It prioritizes language features (reflection) that make writing libraries and frameworks easier. It promotes building reusable tools. Important features are pulled directly into the runtime, based on popularity in the ecosystem. The kitchen sink is included and it's portable.

Basically, it's a language that has been developed by people who actually have to build and maintain projects over a long period of time. A useful language is more than it's design.

So why do I see it going down the hole that Perl and ColdFusion are already occupying?

I see the other side: it's a sinking ship. FB comes to rescue PHP, but internally seems to like anything but PHP for greenfield projects: Java, C++, Erlang (chat msg broker), OCaml/Reason (messenger.com app), even Haskell is used for some spam filtering tool.

> the merits of the tech

In relation to PHP, really? Sure it has come a long way recently, but there's too much still in there that can never be fixed.

I dont think what IHP delivers is some sort of "fashion": they choose to be server-side only, pretty old school. The typing discipline is not very fashionable either: old, time tested, established, but not often leveraged for the development of simple websites/webapps.

Great work!

I wasn't able to find anything on deployment in the docs. What does it look like?

I've been looking for a framework with the following requirements:

  - Functional-ish language
  - Statically typed with Result<T, E> error handling. 
  - Garbage collected. 
  - Compile time checked HTML templates, with autoformatter  and IDE support (like working with JSX/TSX in VS Code). 
  - Some kind of SQL DSL that has decent IDE support (like Ecto on Elixir, Diesel on Rust).
This framework checks off more of those than any framework I've seen. I'll definitely be giving it a try.

Deployment documentation is WIP at the moment and will be released soon. In the future we want to release a Cloud where the deployment will be as easy as clicking a button and having it online in a few seconds :)

Because you mentioned Result specifically: I've recently seen a talk by Rich Hickey that (for me) made a pretty strong case against Result/Maybe/etc. and for union types instead. Maybe you'll find it interesting: https://www.youtube.com/watch?v=YR5WdGrpoug

Nix seems to be heading toward a critical mass in Germany. I use NixOS for my work computer, and couldn't imagine using any other OS. I keep a LinkedIn search open for nixos, and almost all of the hits are German. I'm interested in what kind of an organization might try out something like IHP? I've had a tough enough time introducing Typescript and more functionally oriented patterns in my team, so my guess is that organizations that would seriously consider IHP probably have a significantly different corporate culture.

A Haskell project with docs, this is a pleasant surprise.

I’ve been playing around with Phoenix recently and I’ve been missing a decent type system (Dialyzer is pretty bad). I know very little Haskell but this makes me want to dip my toes in.

First off, nice work!

I always thought it is better to mix client/server rendering; the 'everything client' or 'everything server' both do not work for a large number of applications. So why not mix them. Unfortunately not much out there battery-included that consistently supports that model.

I did not dive into IHP (I heard about it as the RoR for Haskell) but, after reading the introduction, I'm probably going to get depressed when I hear how you do the inevitable client-side stuff here; there is a really good opportunity to mix them as there is HSX and you can compile Haskell to JS. So there should be an opportunity to appoint, where supported, some (parts of) a page as serverside/clientside.

Thanks for your feedback! :)

We have been tinkering a bit with building something close to Phoenix LiveView with HSX. Hope we can show something in that direction later this year.

That sounds good; thanks for the response. Most stuff I do is in the middle between static/dynamic; needs solid SEO and prerendered parts for various reasons but also contains, for browsers that support it, quite a lot of dynamic elements. Now we just use asp.net/static-with-some-react but that is driving me bonkers.

Static with some react sounds like a nightmare. One of the primary reasons why many moved to JS frameworks was to have a better separation of concerns and a single place where GUI logic resides.

May I suggest you have a look at Next.js. It lets you solve this in a very ergonomic way. Maybe even for your existing project.

Yeah it is a nightmare; it is not my choice. It is the same ‘everyone uses it so we need as well’ type of thing thrown in by partners.

Thanks for Next.js: I did not know it.

How do you think IHP would interact with something like concur-replica(https://github.com/pkamenarsky/concur-replica)?

I would love a IHP LiveView equivalent!! Thank you so much!

Wow! Love it. I use my own hand rolled framework but will consider switching to this.

I've just played about with this and love what I see so far. If anyone wants a small site set up and are willing to take a bet on this tech, let me know - I'd be happy to collaborate and see what this is like in prod :)

Looks really cool!

I like the neat UI, auto refresh and everything. I even skimmed the 27-minute demo video (that's a bit long guys), but I don't see any reference to testing, making this a nonstarter for me.

Hey, thanks for your feedback! :) We're internally using hspec for testing our code. We're going to add some more documentation on using hspec with IHP soon.

So as i see, this is like a Rails framework with static type checking. Best of both worlds !

I'd love to see a guide on integrating with webpack or any frontend tech in the stack.

This sounds awesome! I'm using NixOS for almost a year now and am still very pleased with it. It can take some time to get things to work, but when it works you'll never have to look at it again! My biggest problem with Haskell is usually getting the dependencies right. So, the Nix package manager seems like a good fit.

This looks interesting.

I like how your code generation seems to expose most of the structure for customization, but have you thought about having different customizable templates for code generation? Like generating just REST API for this table vs generating user visible views.

This is something we plan to do in the future. We have been thinking about adding a plugin system, where the plugins can provide custom code generators to the dev environment :)

Using Nix to handle dependencies(haskell, pg) in a framework is really cool!

But would IHP work in Windows natively? AFAICT, Nix doesn't work in Windows unless you use WSL(and even here I'm not sure how smooth it is).

Thanks for your feedback :) Running IHP with WSL works pretty well so far. Some of our closed-beta testers have been running IHP on windows. We even made a video to get people started easier on WSL: https://www.youtube.com/watch?v=fM0WTMLdmVw

Seems very interesting, and a move in the right direction.

What's it like to debug when something goes wrong?

Nitpick: Javascript is usually compiled.

What's the difference with Elm?

Regarding execution, Elm is for client-side rendering, whilst this is for server-side rendering. As a language, they're very similar, one could even argue that Elm is a subset of Haskell :-)

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact