Reflections on Using Haskell for My Startup
alistairb.dev
alistairb.dev
- It is an accomplishment if you get your basic project setupped in 2 weeks
- It is very hard to make popular libraries work together
- 1/3 of the popular libraries are not well maintained, there are no docs and maintainers do not reply to PRs
- It is hard to use latest GHC versions because of the previous problem
- It is hard to get additional devs
- Compile times are ok-ayish but can be a pain
- There is no good IDE and refactoring
But it is still somehow "the best general purpose language"?
And don't get me wrong, Haskell is on top of my list of purely functional languages that I would like to learn.
BUT, if I want to build an actual app and try to earn money from it I would just use something that is very popular, well maintained, easy to push features, easy to deploy and find additional devs for. For me it is ReactJS on the frontend and Kotlin on the backend. OR it is a jackpot if I could just make it in something like NextJS. Haskell can wait for when I earn enough money with other languages so that I can just play with it and satisfy my own engineering itch without any production expectations I have from other languages.
And in fact very detailed criticism can be a good indication that the person is not some beginner frustrated with "that bad feature" but a developer who cares a lot about the technology but is also realistic about the things that aren't as good as they could be.
The third point is the same with just about every ecosystem in my experience, there are libraries written by big open source contributing companies which are completely dead as far as maintenance. I've even been bitten _this week_ by a JS library which is dead in the water.
Compare and contrast how happy are users of Java the language vs JVM the ecosystem (Clojure, Scala, Kotlin, etc).
I'm happy when I'm productive and ship stuff. I'm unhappy when I have to struggle with obscure/undocumented libraries/tools.
Not the author, but my reading of his motivations was that the "challenging to learn, but extremely fun to write" part is way more important to them than the "best general purpose language". If your main motivation is to make as much money is as little time as possible then JS or Rails might get you off the ground sooner (although Haskell might catch up in the long run when the type system really starts paying off).
If you enjoy programming in Haskell and are looking to have a good time while building your startup, more power to you for using the language you like.
But that speed flips once you have a larger system and need to maintain it.
- “The ‘monad’ abstraction is excellent for dealing with code with a lot of failure conditions (ie. parsing) and avoids ‘pyramid of doom’ type code. Haskell worked out really well in this key area.”
- “Another strong positive for writing Deadpendency was testing. Haskell has a lesser-known style of testing libraries that do ‘property based testing’ (PBT).”
- “Haskell is very safe to refactor thanks to the type safety the compiler brings, which is probably the most important thing.”
- “My core Haskell had very few logic bugs. This is because Haskell is very safe by default and I had opted into strict types that help catch edge cases”
- “At this point I think it is actually pretty stable. I consider the project a big success. A huge part of this has been due to Haskell and its excellent ecosystem.”
I loved learning Haskell in university. It's an interesting language. I came into intro CS class thinking I could already program & the class would just be about sharpening my axe. Then my intro CS class started with Haskell which threw my brain for a loop and made me think about programming completely differently. That was a great intellectual experience and good for my long term thinking.
Haskell also seems like an incredibly impractical choice for a production language that only a stubborn purist would make. Of course the last bit is purely opinion, your experience may vary.
And several others listed here: https://wiki.haskell.org/Haskell_in_education
Getting a web application started in Ruby is easy because it does so much for you out of the box.
There are frameworks that make similar choices for you in Haskell as well: IHP, Yesod, etc.
I think taking two weeks to "set up" a Haskell project is a bit long but I read it as the author taking two weeks to learn enough Haskell to make two rather advanced libraries work together... which means they had to make all the little micro decisions that frameworks make for you, etc. With more experience that could've been done in less time.
If they had started with IHP I think it would've been your usual day or two.
It's enough to make Haskell really seem like a reasonable choice to "jump in with" without fear of never reaching some mundane goal.
And if I was new to Java, I wouldn't know which frameworks I wanted...
npx create-react-app foo-app
cd foo-app
yarn start
In ~2 minutes (10 if you had to install node/npm/npx), you have a hot-reloading live site to play with.That doesn’t make React great nor solve all of the issues that lie between minute 1 and v0.1 in production, but the startup is smooth and painless (for me who comes from C/C++/C#/SQL, and my javascript is at a level where beginners can still help me).
curl -L https://nixos.org/nix/install | sh
cat > ./script.sh <<EOF
#! /usr/bin/env nix-shell
#! nix-shell <nixpkgs> -i runghc -p "ghc.withPackages (x: [ x.yesod ])"
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Yesod
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App
getHomeR = return $ object ["msg" .= "Hello!"]
port = 3000
main = warp port App
EOF
chmod +x ./script.sh
./script.shYes.
Hey you just threw that in yourself. That's cheating! I think it's actually easy to get Haskell devs. I'm capable and I apply to every Haskell job. I never get hired so I imagine companies have no trouble finding other even more capable Haskell devs.
We let some features and monads go and picked F# instead of Haskell.
>> It is an accomplishment if you get your basic project setupped in 2 weeks
More like two hours if you absolutely cluless.
- It is very hard to make popular libraries work together
Not an issue.
- 1/3 of the popular libraries are not well maintained, there are no docs and maintainers do not reply to PRs
Not an issue.
- It is hard to use latest GHC versions because of the previous problem
Not an issue.
- It is hard to get additional devs
Same. Few F# devs out there.
- Compile times are ok-ayish but can be a pain
Not an issue.
- There is no good IDE and refactoring
Not an issue (VS, VS Code, and a few dozen others)
I know it is not as strict as Haskell but we have really a good time so far.
If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "no-o, no shortcuts, use a proper monad", or takes years to master to that level.
Maybe I'm just missing the point.
First, it is often a sort of humblebrag (as the kids say). I am using this language that is SO advanced that I am a mere intermediate after X years of development. Looks how smart I am for using it. That tends to lead people to dramatically over-estimate how hard it is to become productive in the language.
Second, the emphasis on correctness means that the ecosystem goes to great lengths to explain how all the abstractions work internally and how they are grounded in Category Theory. In other ecosystems (such as Java) they seem to be more focused on talking about the interface and the practicalities of using a library. Spring is extremely complicated but you don't see much ink spilled explaining all the internal implementation details.
I also consider myself intermediate, because I often can't readily grok what are the compiler devs talking about when they discuss e.g. linear types.
I consider myself a Python expert since I can follow PEPs and DSLs with ease.
That doesn't mean that Python is a better language. It does not make the same value proposition.
Spring is a good example too. I used it quite a bit in my junior years and felt like I would never come to master a framework that is so broad (and that felt over-engineered).
This doesn't mean you cannot be productive using a subset of the language. There's a balance in what you should allow in a codebase being maintained by a team of varied skillset. Maybe Haskell is on the extreme end here, but the other way (like Python, JS, Go) is even worse in my opinion.
I still feel this way. I work on all kinds of weird / cool technologies on the side and I can’t imagine ever coming to call myself in expert on anything because I only use a subset to solve a problem.
Servant is very complex by itself. It's hard to tell at what scale it pays off. But it gives you more safety than other solutions.
I would love to have the OP on my team, because they have the ambition to build reliable software and I can compromise with them. It's hard to compromise the other way around.
Certainly possible with other languages + frameworks, but I felt really confident relying on it to catch issues due to the strong type guarantees.
They're not so much talking about the language itself, but more about the way thing can be built in it. That's an open-ended problem, since Turing-complete languages let us use any computatable process.
I might consider myself a 'Python expert', since I've used it for over a decade, written code at the CPython level, all the way up to the metaclass level, built many projects, written extensively about the language, critiqued and discussed proposed features, taught it to others, etc.
Yet I wouldn't consider myself an expert in 'the way things can be built with Python'. For example, I can build Python wrappers for native binaries, but that doesn't imply that I'd come up with a design as clever as numpy. I've done a lot of statistical analysis using Python, but that doesn't mean I could come up with a library as elegant as pyro.ai. And so on.
> If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "no-o, no shortcuts, use a proper monad", or takes years to master to that level.
What do you mean? System.IO.Unsafe.unsafePerformIO lets us write impure code; Unsafe.Coerce.unsafeCoerce lets us bypass the type system. Is there something else you'd want to do?
If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "it's fine to cast that pointer, don't worry about it," or takes years to master to that level.
Maybe I'm just missing the point(er).
You can repeat this argument for any X language you want.
For me you want to work in a language that doesn't let you cut any corners by default. This is what Haskell and some other FP languages do. I can perform unsafe pointer operations in Haskell but it's going to be loud, noisy, and painful to write. As it should be!
In languages like C++/Java/etc you have to be disciplined and opt-in to maintaining the kind of code that Haskell defaults to.
I’m a pretty basic C++er but can use it effectively, if not efficiently. It seems, from the outside, in Haskell you need to know a lot more before even a basic level of effective use is possible.
The effect is pronounced if you're experienced in C++ (and C-like languages in general) and attempt to learn Haskell. There is almost no transferable knowledge from those kinds of languages to Haskell which means you're basically starting from the beginning. That can be infuriating for an experienced developer. It certainly was for me -- twenty-some years of programming knowledge that wasn't terribly useful at all!
When moving from C++ to C# or Rust it's not as big a deal: there are the familiar concepts we can use to bridge the gap towards understanding the missing information.
Haskell is just fundamentally different.
Fortunately though I feel like the "Haskell cliff," is over-stated. The concepts you need to learn to get started and write useful programs is not as high as you might think. The ceiling, like in C++, is really high. Most mainstream languages have, or are planning to add in the next couple of years, all of those features you need when getting started with Haskell: ADTs, pattern matching, parametric and ad-hoc polymorphism, type inference, higher-order functions, and immutable values.
So I think it depends on the code-base you're starting on and what you mean by effective use. If you're trying to contribute to a security analysis tools that uses a lot of type-level programming to encode specification invariants then you'll have a lot of learning to do before you can get started. If you're contributing to a SaaS web application then there's a good chance that only a "basic" level of knowledge about how to program with monads is all that will be required.
I caution readers looking for advise on building a start up. Early on, this reads as a post celebrating the joy of programming. Which is great! Working on something you enjoy can be personally fulfilling, but that doesn't mean that it's a start up.
At the end of the day, a start up is a business, and a business needs to make money. The ultimate validation is finding users willing to pay for your service. Waiting 8 months before finding users is a huge risk, and signals that this is is a fun personal project that may generate profit if it happens to find product/market fit.
The author's closing remarks address the idea, but I think they're a little late for a post about building startups.
> Have I spent too much time geeking out on Haskell and not enough time thinking about the idea? I guess we will see .
Step 2: post something slightly decisive on HN that mentions your product and use case at least 1 time.
Step 3: monitor conversions, wait for signups.
Step 4 (optional): repeat
This obviously isn't bad. I enjoyrd the reading and honestly deadpendancy seems very useful and I'd have never heard of it if not for this post.
I guess it's a 'chicken-and-egg' problem. Popular languages get tooling investment because they are popular.
E.g. with Haskell Language Server there's now a good and standard way for having autocompletion, etc. inside VSCode and other editors.
In the web development space we now have IHP, which is like rails but with type-safety. It's already the second largest haskell framework, even though it was just launched last year: https://ihp.digitallyinduced.com/ (Disclaimer: I'm founder of the company that makes IHP)
Second to Yesod, I presume? How do you measure size, as in, what exactly is the quantity you measure, and how do you go about calculating/estimating that quantity?
https://star-history.t9t.io/#digitallyinduced/ihp&yesodweb/y...
We also have a very active community, e.g. over 100 people in Slack, over 180 in Gitter, over 100 weekly active projects (https://ihp-telemetry.digitallyinduced.com/admin/Events <- here's some telemetry)
I'm using VSCode and the official extension (https://github.com/haskell/vscode-haskell). The default experience is not at the level of what I have with Go or Typescript but already quite good (though it's not that stable IMHO, I have to restart the server more than I would like).
The Haskell Platform (https://www.haskell.org/platform/) makes it simple to install almost everything you need to get started (the compiler, standard libraries, build tools, etc).
It's not there yet, the beginner dev experience is still painful and frustrating, but things improved quite a lot.
Is this the norm for production-ready Haskell codebase - basically throw away laziness?
Haven't read it but there's a book called "Real World Haskell", which I thought was funny considering your question. Right now I'm really enjoying "Functional Design and Architecture"[1] by Alexander Granin (it does assume you've already got some experience). In addition, make sure to revisit Stephen Diehls "What I Wish I Knew When Learning Haskell"[2].
[1] https://leanpub.com/functional-design-and-architecture [2] http://dev.stephendiehl.com/hask/
I'll take a look at that functional design and architecture. THanks.
PS: Hi Christian! You were a TA when I was a student at Fullstack :)
I think this only might be a problem if you don't want to hire remote.
It's more interesting what constitutes niche, AND as the parent notes what constitutes a "language to have enthousiasm for".
VB, JScript, ActionScript, ColdFusion and BASIC are all niche (nowadays), but without enthusiasm its not interesting.
Besides the niche-enthusiasm, there is also something for "usefulness". Haskell+ecosystem (and others in the FP camp) bring a nice set of features to the table not often found in other languages.
No they didn't all start off as a niche. They started off with a small user base of early adopters. Haskell is a niche because it's been around long enough to pick up users. There is a difference between a new language with a small number of early adopters and a niche language that has been around for decades.
And languages like Swift did not start off small.
definitely not. Java was presented at SunWorld. When C# came out there were ads in computer programming zines. Swift came out on a wide concert stage with most of the Apple community having their eyes riveted on the video stream: https://youtu.be/MO7Ta0DvEWA?t=45
All that ensures that the "critical mass" adoption to get the language out of niche status would be a non-issue
And some return to small user bases :) I think the number of VB programmers has drop to level below Haskell nowadays.
ahahaha
https://trends.google.com/trends/explore?q=%2Fm%2F01dpgv,%2F...
For example, Elm is still a tiny, niche language, but from what I hear it's relatively easy to hire for Elm because there are many more people who want to work with it than there are companies that are hiring for it.
If I may shill, if anyone is hiring for Haskell or FP roles, please let me know.
https://apply.workable.com/io-global/ https://iohk.io/en/team/
There are probably more people who use Haskell or want to use Haskell as their main language than there are job openings to work on a Haskell code base.
If you're willing to work with a remote team your inbox will probably never sit empty.
These maintainers don't even switch off Dependabot, not to say merge the PRs that updates dependencies with potential security risk. And it bothers me a lot....
For JS Dependabot becomes a spammer, because there are just so many packages even in a "hello, world" project.
In one of my projects I just gave up and set up auto-approve/auto-merge on minor updates. This is what the commit history looks like: https://i.imgur.com/cC7h7T7.png And there are 20 more major ones waiting for resolution.
My hunch is that in many projects devs just on't have the capacity to deal with the deluge.
I started writing go at the same time i started to work on production with it. In 2 weeks time i had a working service and learned the language, instead of the setup.
Interestingly enough the main problem was the pyramid of doom though (due to various http middlewares)!
Nowadays i don't have issues with the pyramid of doom.
Still it seems that in the long run the benefits are similiar, except for the time it took to build it, so if it was fun i think it was worth it.
What they don't cover here are any of the benefits of the language. The abstractions of the language provide an excellent toolkit to express the intent of your code succinctly. That makes it easy to reason about, cheap to maintain, and fast to develop.
Go gets you started quickly, but your code will be no more expressive after 5 years of development than at 5 weeks.
As an example, Either-monadic code automates an error check on every line, immediately returning on the first error. The go equivalent is a ton of mind-numbing "if err != nil" checks between every relevant line of code. The go equivalent is mostly mechanical clutter. But all those LOC still add maintenance. People have to read and check them (no wrong operators, no references to the wrong variables, etc).