Test‑coverage metrics can hit 100 %, yet critical bugs still slip through. Property‑based testing and type‑driven design show why – and what to do about it| Jezen Thomas
You’re probably already using a few tools to automatically check your software — like linters, automated tests, code formatters, or a type-checking compiler. These are all great, and we use them at Supercede too. The more checks we can run, the better. And the earlier in the development process, the better. What I’ve noticed over the years though, is that we tend to focus on more advanced, often esoteric forms of analysis. With training and practice, we can express our application’s l...| jezenthomas.com
When testing a web application, you often want to make sure that a certain email would be sent — without actually sending it. How do you test that? Take something like a transactional email: a user signs up, resets their password, or completes a purchase — and your application needs to send a notification. You don’t care how the email gets sent — just that it was triggered correctly. The simplest implementation for the email-sending function might look like this. sendEmail::Recipient-...| jezenthomas.com
Many of us at Supercede use GHCi directly when developing Haskell projects. It runs the local development server, and the automated test suite, and serves as a scratch pad for ad hoc expression evaluation and type inspection. We make heavy use of integrated tests with the yesod-test framework. One of our projects now has more than 500 tests. Running the tests in GHCi takes about 150 seconds. Not terrible, but not great either. Certainly not fast enough to encourage developers to practice TDD ...| jezenthomas.com
The main function provided by the yesod-form library for processing form submissions is runFormPost. As the name implies, this function processes POST requests. But what if you want to use a different verb, like PUT? The library is a little confusing in this way, because the post in runFormPost doesn’t actually refer to the HTTP method that triggered the execution of the handler code. The point of runFormPost is actually just about running the parser against the request body, rather than th...| jezenthomas.com
Over the years, a house style has emerged for all the Haskell code we write at Supercede. We expect all new code to generally follow this style, and since style pertains to more than just the language itself, this style guide will touch on some aspects of the Yesod ecosystem and software design more broadly. Philosophy Style is taste, and taste is subjective1. There isn’t one right way to write Haskell code, which is why I format most Haskell code manually. I might use tabular to align some...| jezenthomas.com
Year 2024 has come and gone. Number of bones broken this year — only one. Here are some other thoughts on how I kept busy. Personal I bought a motorcycle. It’s a Ducati SuperSport 937. I didn’t think I would ever like motorcycles, but they’ve very much grown on me. Part of it is escapism from a career where I mostly sit in front of a computer. Another part of it is escapism from traffic and high fuel costs. That and as a machine, it’s really rather pretty. Cars are always becoming m...| jezenthomas.com
I awoke to the sound of a violent explosion earlier than I had wanted that morning. The walls, windows, and furniture vibrated. A cruise missile had struck a warehouse owned by a national supermarket chain, roughly a kilometre from the hotel I was staying in. The russians had fired it – targeting civilian infrastructure as they regularly do – perhaps a dozen minutes earlier. It was June 24th, 2024. The time was 07:03. Plume of smoke from a russian cruise missile hitting a supermarket ware...| jezenthomas.com
Someone working on the team at Supercede asked the following question regarding some perplexing GHCi output. I must have missed something obvious because I’ve been staring myself blind at this for the past few minutes. Isn’t it saying one thing is not in scope and then immediately suggesting that very same thing as a replacement? ghci> :t API.Handler.V20201001.Types.tscaExcluded <interactive>:1:1-40: error: Not in scope: 'API.Handler.V20201001.Types.tscaExcluded' Perhaps you meant one of ...| jezenthomas.com
After several years working on Supercede, I’ve had time to reflect on some technical choices we made. Some of them worked well, others I’d approach differently if I were starting again. Here’s what I regret, and why.| Jezen Thomas