Ask HN: Why are all of the best back end web frameworks dynamically typed?

9 points by calderwoodra ↗ HN
Ruby on Rails, Django, Node JS all have great developer experience, are highly configurable but easy to use and hit the ground running.

Spring, Gin, anything Rust, .Net, etc all are very difficult to configure properly for even the most simple SaaS products.

Why is that? Are there any good statically typed web frameworks?

34 comments

[ 1.3 ms ] story [ 109 ms ] thread
I would argue Gin/Go isn't really statically typed.

I mean sure you can specify that this var is a int32, but pretty much every tutorial, every code snippet out there, will do.

    myvar := 10
And just let Go guess what the type should be. So yeah, Go CAN be statically typed, but in practice it rarely is.
Aren't go types determined at compile time? That would make it static in my book.

But regardless of that, are you also implying that Gin is as good as nodejs/Django/ror? There are lots of bad dynamically typed web frameworks, but I'm looking for a good one that's statically typed.

What you are observing here is actually called "Type Inference".
But the point is, the name is that type, a property enforced at compile time. If you do ``myvar:=10'', you can't then do ``myvar="fred"'', because the value of myvar must be an integer.
That's type inference, not dynamic typing. The two are distinct language features. Many statically typed languages offer type inference: Haskell, C++, Rust, Java, D, SML, OCaml, C#, F#. Good luck convincing people that those are dynamically typed languages just because they have type inference.
Because development speed and flexibility matter way more than "correctness". Engineer salary is expensive, and there is software to manage running processes that makes errors in software in niche cases not a big deal because it can just restart the failed container or the failed process, publish logs, and then an engineer can implement a patch.
IIUC, you're saying that failures are low stakes, so even if a good framework existed, the idea of using static types is flawed since is only slows you down compared to dynamic types.

I disagree but my position is purely preference/subjective. The main point for me is that static types make reading other teammates code much easier. If I could use statically typed python/Django, that would be amazing.

You probably already know but you can add type hints and then check for consistency with https://github.com/python/mypy in python.

Modern Python with things like https://learnpython.com/blog/python-match-case-statement/ + mypy + Ruff for linting https://github.com/astral-sh/ruff can get pretty good results.

I found typed dataclasses (https://docs.python.org/3/library/dataclasses.html) in python using mypy to give me really high confidence when building data representations.

And there's https://pypi.org/project/django-stubs/ for working with Django.

Things like MyPy and Pyre end up being a pain to setup, in part because of an annoying and unautomated "stub" ecosystem (it was like back in the day when you had to manually install or declare types for every JS package used in a TypeScript project).

It really just doesn't feel as good or useful as using a statically typed language.

Dynamic typing allows more dirty code, in the same way static typing allows for massive inheritance hell with factories and polymorphism.

You can write clean Python without much fuss that is easy and simple to read.

"Correctness" isn't even the draw of static typing; speed and flexibility are. When I make a single business-relevant change, the compiler's error messages guide me to modify what must else accommodate. This is faster (and less error-prone) so I can get onto my next feature sooner.
What kind of business-relevant change are you referring to here?

I don't think the compiler with the error messages makes a difference when the business is pivoting between features, when they ask to add a new field to various forms, to generate new reports or add new emails in various points of the work flow. Or change the emails from one point to another point. Or add password less. Or just switch the external provider of an API from an important flow because there is a better deal elsewhere.

I am not saying static typing does not provide speed or flexibility, but I just wanted to say that business-relevant change has more to do with features than code.

> business-relevant change has more to do with features than code

I cannot comprehend this. It's like saying "Health has more to do with organs than cells." Organs comprise features. Features comprise code. To change the feature, one must change the code.

If the code is not business-relevant, delete it. It's a liability. We are not artists.

If the code is well-written, the compiler errors will echo the business' failings.

Thats the "academic" advantage of static typing.

In practice, it essentially leads to one of 2 things

1. Any time you have to make a change for a prototype, you have to go change a whole bunch of dependencies on your library, even if the change is not used in those explicitly, all because of the prototype.

2. You start introducing dependency hell or duplicate code, to either abstract stuff away so you don't have to do the prototype changes, or you start writing duplicate classes/functions to handle different parameters.

Neither of which is either fast or flexible. Anyone who has worked at Amazon dealing with Java services can attest to this.

Dynamic typing on the other hand is actually flexible and fast. For example in Python when building out something that is changing quite often, its very easy to pass around dict objects.

And yes, dynamic typing, it can lead to more errors, but in practice, most all of these are caught during testing, and are just as straightforward to fix as compiler errors. If you try to access a dict field that is not in the passed dict, its pretty much equivalent to a compiler error.

I don't have an "academic" background, I just enjoy the subjective ergonomic advantages. At the very least, strict types obviate a class of tests that I'd previously considered indispensable.

> dynamic typing, it can lead to more errors, but in practice, most all of these are caught during testing

I think we're practicing such different styles of software design that one another's tools are a hindrance. For example, I don't think that "bugs are caught during testing" because I am testing first. Unless you mean user acceptance testing, which is uncomfortably late in the cycle.

When you compile the code with static types, there is a process of parsing the syntax and executing a state machine that checks all the validity of types.

When running a dynamic type language, these errors are going to be caught at runtime.

What Im saying is that from the perspective of code execution, there is no difference between the two as long as those checks are performed somewhere before you ship your code, whether in tests or in the act of compilation.

> as long as those checks are performed somewhere before you ship your code

Preferably, they're performed before I push to a remote repository. Hopefully they're performed before I alt-tab away from the editor for a single second. Hopefully they're performed before I fuzzy-find a collaborator module to edit.

> When running a dynamic type language, these errors are going to be caught at runtime.

Only if those code paths are exercised in a test suite, or am I doing it the hard way?

What do you mean hard to configure? I use Axum with Rust just fine.
Spring is pretty simple, it works out of the box (spring boot) and the docs are good.
But soon you will run into performance issues because not a single developer in your team ever wrote a plain sql query and simple actions resulting into 1000 queries.
That's not spring though, that's poor developers
I like to think of myself as a pretty good engineer, but I spent countless hours trying to get authentication of any kind working in spring and it was very painful. It's been a few years (2020) since I tried but that was just one of many roadblocks I hit trying to get spring boot to work.
This is just preposterous. Out of all programming languages I've used, never have I seen the bloat of Spring. Innumerable interfaces, abstraction behind layers and more layers to do the most basic of changes, not to mention the bizarre fetish of Java developers to NOT write code and instead relying on "hacks" (Annotations).

Spring boot sure, Spring boot works out of the box by slashing all of the configuration from spring, "convention over configuration" they say, which does not help understanding the underlying magic that Spring does, it just adds more magic upon it, so it's just yet another layer of abstraction to learn. Is that all? No! We need more annotations, so add Lombok on top of the existing @ hell.

Because junior developers don't know how to do Type-Driven Development.
Sadly, I think there's some truth here which is unfortunate because it would do them a world of good to learn!
Clearly a question rooted in grounded science (not).
I don't think Django or most NodeJS frameworks are all that pleasant to use (I especially dislike the monstrocity that is NextJS).

.NET MVC is a very good framework, but I know the devops can be weird and a pain.

Overall, most frameworks get in the way anyways, IMO. I prefer to cobble together several modules that each do one thing well. E.g. use FastAPI for the endpoints, and any unrelated ORM you like for DB stuff, etc.

What are some things you don’t like about Django?
Off the top of my head and non-exhaustive? Not a fan of the lack of real controllers and the way the endpoints are defined, especially when it comes to class based views, mixins, etc; and, while, the ORM is mostly good and useful, I think it has a couple features (like through fields) that obscure too much what is actually happening at the DB level.

I suspect that if I really sat down and tried to more thoroughly write my thoughts on the subject, a lot the things that annoy me with it may just apply to dynamically typed languages in general (and sometimes just Python in general).

Suave is the best web framework I have ever used, and it’s on the extreme end of the strong-static typed spectrum.

I don’t think the dynamically typed ones are better, just better known.

IHP is a batteries-included web framework similar to "ruby on rails" for Haskell, with strong static typing.

The website has lots of information and videos and beginner tutorials.

https://ihp.digitallyinduced.com/

"Move fast and break things" doesn't lend itself to the drudgery and cementing/ossifying nature of the statically-typed languages of 15+ years ago.

They've both improved and the industry has matured.

I found IHP straightforward:

https://ihp.digitallyinduced.com/

despite not remembering much haskell!

This assumes you can get past nix for the install.

I find IHP well-designed. I just wish the licensing scheme were more transparent.

these days the best web framework is net/http.