HNHacker News
TopNewBestAskShowJobs

antew

104 karma · joined February 10, 2014

submissionscomments
antew··on Warp Terminal changes pricing model
In my ghostty config I use:

  scrollback-limit = 512000000
  keybind = super+f=write_scrollback_file:open
It writes it to a temporary file and then opens the file in the default text editor when I hit Cmd+F.
antew··on Elm Compiler Written in Elm
There was a similar project to `go fix` with elm-upgrade (https://github.com/avh4/elm-upgrade). We migrated a ~100k LOC app at work from 0.18 to 0.19 and while it was tedious, the compiler really has your back and makes it easier.

We weren't bit by the removal of native/kernel code, but it definitely turned a lot of people away that may have been committed to Elm before.

antew··on Observable Plot
As a D3 user for years, this looks great, the API looks really clean, congrats on the release!
antew··on Why we chose Elm for Humio’s web UI
Sorry, I didn't mean to say that nobody has negative experiences with it, but that "X considered harmful" style posts tend to get more attention on sites than positive experiences generally do.

What was something that left you unsatisfied with Elm? The biggest one for me until relatively recently was handling state updating state from leaf components, it was fairly cumbersome to have `(Model, Cmd, ExternalMsg)` in lots of places. At work we recently switched to the Effect pattern (https://sporto.github.io/elm-patterns/architecture/effects.h...) which has alleviated a lot of the overhead.

antew··on Why we chose Elm for Humio’s web UI
I think we are somewhat in agreement, Elm is certainly Evan's language and framework, and if you live within the boundaries of it you'll have a pleasant experience.

I have read all of the bad experience posts on Elm because I've spent a while working with it now and it is always valuable to see someone else's perspective on it. In practice the pain points either haven't really been a problem for me, or I've found a satisfactory way around them using web components, ports, code generation, or other ways.

My experience is just more anec-data and I know it won't represent everyone's experience. I'd encourage anyone hesitant about Elm to give it a go, it's been a joy to work with.

antew··on Why we chose Elm for Humio’s web UI
That "Why I'm Leaving Elm" post comes up on most Elm discussions, and I would implore anyone to give it a try for themselves before deciding against it. I've been working in Elm professionally for a few years now and I think Luke's experience in that blog post is certainly atypical.

For writing web applications Elm is an excellent language to work in, the compiler is friendly and fast, there are basically zero runtime exceptions, refactoring is a breeze, and it really shines on larger code bases. Web-components are discounted pretty quickly in that post, but they really fill an important gap where ports are awkward.

In the years I've been using it I haven't run across a problem that I couldn't solve in a nice way. That is not to say my experience is universal, but the negative posts tend to garner a lot more attention than positive posts, and I'd feel bad if someone were to skip over what is an awesome project due to them!

antew··on Why we chose Elm for Humio’s web UI
Glad to see more posts on Elm out there, it really is a great language and ecosystem! Like any large project, it has some issues, but in my day-to-day writing code I have never had as much fun, or had as much confidence that my code does what it says on the tin, as I have with Elm.

I wanted to give a shout out to one of Jeroen's other projects in the Elm ecosystem, elm-review (https://package.elm-lang.org/packages/jfmengels/elm-review/l...), it is an excellent linter/fixer and allows writing your own rules as well.

antew··on Why I Love Tailwind
Tailwinds also acts a design system for your site, you have a set of paddings, margins, colors, font sizes, breakpoints, etc that make up your design system.

In my experience it results in more consistent designs because everything must come from what you make available in your tailwinds config.

antew··on macOS Big Sur
For Safari specifically you have to use Apple's push notification service (APNS), which is a lot of hassle compared to web push.

There is a ticket open for adding support into Safari, but it probably won't happen anytime soon. https://bugs.webkit.org/show_bug.cgi?id=182566

antew··on Redux – Not Dead Yet (2018)
I always see you in these Redux threads and you are always so helpful, thank you!
antew··on Why I’m Leaving Elm
I've been working in Elm for a few years, and I feel like I can answer some of the questions.

0.19 introduced a new restriction on Native code (javascript), previously you could compile kernel code in your own projects, now you can't. You've never been able to publish a package using native code to the package site (only packages under the elm or elm-explorations github namespace can).

If you feel strongly about it there are ways around it, forking the compiler, or giving your project a fake "elm/whatever" name so that the compiler will build it, there is also a set of shell scripts on github that allows you to get around the restrictions. I've used it before to make some tooling to track virtual-dom performance.

The biggest miss in the post in my view is not looking more at using Custom Elements for the internationalization needs. Having a custom element where you pass in a posix time and have it formatted using the Intl APIs is very possible, and it also allows you to wrap up the interface between Elm and JS in a nice, type-safe way.

The 0.19 upgrade was fairly large, but manageable. Our app was around 70k LOC when we upgraded from 0.18 to 0.19, the upgrade was fairly smooth, and it hugely improved our build times. I had actually forked the 0.18 compiler to improve build times, full builds took around 2 minutes, and incremental builds around 45 seconds. In 0.19 full builds take 4 seconds and incremental builds less than a second.

I share in some of his experiences as well, I have had posts deleted on the Elm Discourse page for mentioning a way for someone to run a fork of a core package to get a fix. I stopped working on a private package manager for Elm after someone described an existing solution as a hostile attack on Elm.

Overall the benefits of Elm still outweigh the downsides for me, no other language I have used has made development a joy like Elm has, refactoring is honestly fun, change whatever you want, follow the compiler errors, and at the end everything works again. Packages are generally high quality and work, an Elm package that hasn't received any updates in a year probably isn't abandoned, it's finished. Coming back to code I haven't worked on in a while is easy, the type system has my back, and most Elm code looks similar due to using the elm architecture and elm-format.

antew··on A list of companies using Elm in production
I don't have one on Ellie, but Ellie itself has a nice example with how it wraps CodeMirror (https://github.com/ellie-app/ellie/blob/master/assets/src/El...)

I don't know if there is a formal name for this pattern, but we've been calling in the "un-attr" pattern, you define an opaque type like

  type Attribute msg
      = Attr (Html.Attribute msg)
And then expose functions that allow you to set attributes you whitelist. In the JS you use setters to hook into when the attribute changes and respond to it (https://github.com/ellie-app/ellie/blob/master/assets/src/El...)
antew··on A list of companies using Elm in production
They are fine for a general FFI mechanism, and in certain cases they fit into the code very nicely (e.g. websockets fit the publish/subscribe pattern very well), but for handling events from the DOM or interacting with existing JS libraries it breaks down a bit.

For instance, we have a text editor that wraps Quill so that we can support things like mentions, hashtags, and emojis. We can have multiple instances of the editor on the page at once, so the port needs a way to uniquely identify which instance the event is for, and handle delivering any responses to the correct instance of the editor. I find it a lot easier to partially apply the ID of the editor to the message so that everything is defined where it is used in the code. It is also possible to forget to add the necessary subscriptions when adding the editor to a new page, whereas with a custom element it is all handled internally.

Another case where ports had a bit of an impedance mismatch is on using existing browser APIs, like the Intl module (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...). We wanted to use it to format an epoch time into the user's locale. The only way to call the Intl module from Elm itself is through ports, and the wiring makes the code a lot more complex because you have to send the request out through a port, wait for the response, and then render it. With a custom element it becomes a lot simpler conceptually, we have something like

  DateTime.view posix
We also like to wrap up the custom elements with a type-safe Elm wrapper so that we can control what options are available. We have some feeds that have infinite-scroll on them to load more content as you reach the bottom, it uses a custom element that wraps the IntersectionObserver API and fires events that Elm can listen to, so it makes it really easy to use and understand how it is working, in the code it looks like

      InfiniteScroll.view
        { onScrollIntersect = LoadMore
        , state =
            case feed of
              Done ->
                InfiniteScroll.Done
              Failure ->
                InfiniteScroll.Failure
              Loading ->
                InfiniteScroll.Loading
        }

Anywhere you want to respond to scroll position you can just add that element in and it will work its magic.
antew··on A list of companies using Elm in production
The company I work at (https://halogen.tv) has been using Elm in production for a few years now, we have around 90k LOC in Elm for the front-end, and it has mostly been a pleasure to work in.

The biggest upsides in my view are:

- The compiler is your best friend, the error messages are great, and you can enforce a lot of things with the type system. Have a list that should never been empty? Use a NonEmptyList, need to manage a selection? Use a Zipper/SelectList. Forgot to handle a possibility in a case statement? The compiler will catch it for you.

- Refactoring, even large scale refactors, are tractable and actually fun. Change the architecture in whatever way you want and follow the compiler errors, when you fix the last compiler error things usually work like you want!

- (Almost) No runtime errors. There are still a few rough edges where you can get a runtime exception, but they are uncommon.

It is not to say it is all roses, there are negatives as well:

- Lack of a roadmap or timeline, there is zero visibility into what is being worked on and when things may happen. This has been a deliberate choice by the core team I think because when they had a roadmap and parts of it didn't fit into the next release people were angry.

- Bugs can take a long time to be fixed, even if there is a PR that fixes it, it is unlikely to be merged.

- Experimentation is discouraged. The 0.19 update removed the undocumented, unsupported, here-be-dragons hooks that allowed writing effect managers except for repos in the elm or elm-explorations organizations on github. I agree with not allowing those modules to be published to the elm package site, but intentionally blocking people experimenting on their own is unnecessary in my opinion. Of course you can always fork the compiler and remove the restrictions.

- Ports are a pain. We generally use custom elements in place of ports where it makes sense, but they are really a hack around some of Elm's pain points, if I could do it all nicely in Elm I would.

antew··on Ask HN: Anyone Using Elm in Production?
We've been using Elm in production for https://halogen.tv and has been a great experience overall.

The codebase is around 60k LOC for the front-end and we've settled on a few patterns that help with reusability and managing complexity.

- We have moved to a very flat architecture where most things are at the top level of the state tree

- We use web components to wrap up things that are a pain in Elm (like exit animations, fancy text editors, interop with various JS libraries)

- Our reusable components take Configs so that the components are not tied to one Msg type, different pages have to provide hookups for those messages but it allows us to reuse components on different pages pretty easily.

Refactoring with confidence is possible! I have worked on large React/Angular apps where it was nigh impossible to refactor something without breaking a bunch of others things (often without a way to know they are broken aside from a full regression test). Typescript has improved things quite a bit, but it can't give you the same guarantees as Elm can.

As for difficulties we've run into:

- The virtual dom diffing slows down as the number of nodes grows, for our live chat we can have thousands of people chatting at once and diffing between the previous/next set of nodes can easily exceed the time we have for the next frame. We've taken to reducing the scrollback available in chat, virtualizing the list is another option.

- The time-travelling debugger is cool to show off but has some limitations that make it less useful in practice. If the Msg is long it gets cut off and there's no way to see the whole thing. There's no way to exclude or filter messages, if you have timer running the message list quickly fills up and it is difficult to find the Msg you want.

- When we were on 0.18 compile times were a large source of frustration, we ended up using a forked version of the compiler to improve things a bit, I wrote about it here https://medium.com/@antewcode/faster-elm-builds-e0669580ee67.

- There is little published information on what is coming down the pipeline, timelines for bug fixes, features, etc

This final one hasn't been a big problem in practice, but the prohibition on effect managers and native code in the community leads to teams all over the place reimplementing the same thing (e.g. interfacing with LocalStorage). It has never been possible to publish code using ports or native code to Elm's package manager, which I think is a good thing, but 0.19 also removed the ability to compile them locally without forking the compiler. I think I am in a very small minority in the community that thinks that effect managers are not evil and can be used for good.

antew··on Vim Is Saving Me Hours of Work When Writing Books and Courses
No, but you can use the Vim plugin for IntelliJ and get it that way! There are Vim plug-ins for every IDE I've used.
antew··on Small Assets without the Headache in Elm 0.19
I'm so glad to see this, congrats to Evan and everyone who helped get 0.19 out the door!

I've been working in Elm for about a year now and it is a joy to work with, moving from vanilla JS/Angular/React to Elm has been a boon to productivity and I actually have confidence that when I refactor something and have fixed any compiler errors that it is going to work.