Hacker News new | ask | show | jobs
by jpgvm 1301 days ago
Startups spend innovation tokens very poorly.

Progamming languages, hosting platforms and non-standard databases aren't ideal places to spend such tokens.

For most apps what you want is JVM or .NET, PostgreSQL or MySQL or SQL Server, k8s or vanilla VMs/containers.

You almost never want different programming languages to these mature stacks, you might think you do, but you don't. Node.js/Python/Ruby etc all promise a fast start but in reality any perceptible velocity benefit is dead within months, usually before anything of value is shipped. Most of it has to with ecosystems (library quality etc, framework maturity) but those also being the 2 most advanced managed runtimes helps a ton.

For databases just standard RDBMS is almost always the way to go, unless you startup is intrinsically a data startup and you know ahead of time you require very special properties you just want one of these.

Keep hosting simple. Don't use any fangdangled "serverless" nonsense. It's not worth it, shipping a week or 2 later because you took the time to setup EKS/GKE/AKS will pay off in spades. k8s reputation for complexity isn't warranted and it's essentially standard now and will remain that way.

So now you have freed up your innovation tokens you can spend them on solutions to your actual business problems instead of on stuff that will only continue to eat your token budget and often yield negative real returns.

5 comments

For my money, at least Node and Python have absolutely reached the point where they can provide self-feeding velocity. I quite like the JVM as well--I've written a lot of Java and a lot of Kotlin--but TypeScript and modern, typed Python are very defensible options. I know more about Node than Python, so that's easier for me to talk about, but for my money tools like Fastify have a really excellent ecosystem around getting shit done in ways that don't buy you too much technical debt in the future.

Databases, fully agreed. "Use Postgres unless you have a reason not to." When you need a key-value store for caching or whatever...consider Postgres hstore first, and then spin up a Redis only when you need to.

Hosting...depends. With my product hat on instead of my infra hat, I think there's real value in managed serverless options. The various Heroku descendants--I work at Render, but I'm friends with the Fly folks and they're great too--can, if you are in a low-devops environment, provide some real benefits. Or, for a more stripped-down option, AWS Fargate/GCP Cloud Run, but to bootstrap that you're going to be doing somewhere between the work necessary between a Heroku++ option and "run a server somewhere and keep it patched".

Curious to hear more about your experience with Node/TypeScript. Is it really comparable to the maturity of JVM or the .Net ecosystems? I've experienced some problems such as: 1. It's still running JavaScript on server-side 2. Debugging becomes a pain because stacktraces will contain .js files and line numbers 3. Multi threading is still complex.
Main issues (non-exhaustive) with Typescript are:

1. Type checking is slow (this problem scales with the size of your project also which sucks) 2. Lack of proper build system ecosystem (as compared to Maven/Gradle/etc) 3. Ecosystem is poor 4. Packaging and module systems are poor (import side effects, gross)

If you tackle 2. you can also work around 1. Best way to do this at this time is to use the new Bazel rules_js/rules_ts ecosystem. This will result in lowering the amount of time you spend type checking and transpiling things making it tolerable.

3. and 4. however are just things you have to live with if you go with Node.js.

I've worked in pretty large codebases and #1 and #2 have not been problems I've encountered. #1 used to be a problem, but TypeScript incremental compilation has significantly improved things. #2 doesn't parse at all as a problem if you're working in a monorepo, and if you're not you've created other problems that "use Bazel" doesn't fix--and, to be honest, "use Bazel" would be a failure case that would encourage me to use literally anything else that didn't use it anyway.

#3 is also a pretty wild take, in my experience. Maybe you have some pretty particular needs, but I very rarely find that I don't have what I need in Node.

#4, I'll give you--but if you're going to stan for the JVM, I hope you've never run into a static class initializer with side effects, because I've seen them about as often as I've seen side-effecting imports (which is to say, not often). I gather that they used to be a lot more common in Node, but I cannot think of a library in my usual stack, or even that I've used recently, that has side effects in that way (modulo development-environment stuff which leverages that kind of cursedness intentionally).

My experience is that it's fine(tm). "JavaScript on server-side" does not bother me; V8 is fine. It's not as fast as HotSpot, but also, I don't care. If I ever wrote something at extragalactic scale, yeah, sure, whatever, I'd rewrite hot paths in something else. But I absolutely don't care about that until then.

None of my debugging output includes JS lines because I pack source maps, which TypeScript happily includes.

Multi-threading isn't complex, because there isn't multi-threading. There's coprocessing via Promises, and there indeed are a lot of Node developers who think you don't need locking functionality because it's not multi-threaded (there was an absolutely bonkers discussion a few years ago where a JS developer insisted you didn't need locks), but whatever, they think that about other languages too, use async-lock or whatever.

"Maturity" is a word that means different things to different people. There is not a consensus-best-choice framework like Spring Boot in Node. Which leads people to doing things like "I'll use Express!" and now they have interesting problems all their own. But the tools are there and they're excellent. Fastify is perhaps The Best web framework I've ever used (other than perhaps Python's FastAPI, which makes me wish I liked Python enough to write it because that seems like a Right Answer in itself), and it has only gotten better with v4 allowing you to engage with type providers to create an end-to-end, automatically typechecked route declaration framework. It lets you do stuff like this, where you specify a request schema as JSON Schema (encoded via typebox) and it'll statically derive the TypeScript type for you whilst also using it for request schema validation:

https://github.com/fastify/fastify-type-provider-typebox#exa...

The tools are there and you do probably want to invest a little time in understanding what they do and what their tradeoffs are. There's value in that, for the way I write code and the stuff I enjoy building.

Overall, I'll trade some compilation niceties and even some (but to be frank, not much) performance for a vastly more productive environment in day-to-day use. I really like the JVM. I've been using it professionally for twelve years. I also like the CLR. I did Google Summer of Code for the Mono Project in 2008, I've been around. But the day-to-day of writing code in the dominant languages on those platforms for things other than CRUD does frustrate me, and the general-purpose languages on the JVM and CLR present difficulties in using the type system to effectively encode intent makes it much harder for me to write software that can guide other people to not misuse it. So for me it's worse both at library-writing and at getting-things-out-the-door. (I still do gamedev experiments in Java or Kotlin, though, because libgdx is seared into my brain.)

> k8s or vanilla VMs/containers.

Why would you even bother as an early stage startup? Ship your code on a PaaS like fly.io/Render/Vercel/Heroku/etc until cost/scale is an actual issue. Same for using managed DB solutions. Your time (=money) would be much better spent elsewhere.

As for language, I would optimize for what's easy to hire for.

Because the impact on your code by going with a serverless platform.

Generally speaking if it's the platform you have you will shoehorn the shape of your code into a serverless shape bucket even if it has no business looking like that. These architectural shortcomings will inevitably come back to haunt you.

Also most of these platforms amount to cgi-bin v2, meaning things like memory leaks and requests that hang get swept under the rug. Meaning you already have very difficult to diagnose failures and when you do eventually go to migrate you will find your code is full of these smells making it harder to reform into something reasonable.

That is also putting aside the spaghetti nature of intertwined functions of any serverless codebase of scale, the huge IaC overhead if you go with something like AWS Lambda and the massive amount of incidental complexity that serverless advocates try to make you look the other way for (hello API Gateway).

I'm not a fan of serverless/lambdas for this exact reason, I was referring specifically to PaaS solutions, where you can build your services without vendor lock-in, in a way that makes it easy to containerize later on. Things like memory leaks and requests that hang are usually reported by these platforms.
Fair, the ones that let you run containers directly like Cloud Run etc are fairly reasonable and approximate the k8s experience.

I think by going non-k8s you miss out on some of the key benefits though like standardized API and more portability of the surrounding infrastructure like networking and storage that is otherwise proprietary or not available on "simplifed" PaaS platforms.

I guess my argument boils down to cost of using managed k8s is low, low enough it's not worth using non-standard services instead.

Though I would like to address a point in your earlier comment though that is that it implied "k8s is about scale".

K8s has absolutely nothing to do with scale, the fact it can scale horizontally is a side effect of enforcing good separation of concerns and API design in the orchestration layer. You use k8s because the APIs make your applications better, even with they are small. This is the true innovation behind k8s. There were other platforms that made containers accessible (I worked on one called Flynn, Deis, Heroku to an extent, etc) but none of them pushed a better paradigm around orchestration which is why they didn't lead to the same level of success k8s has.

maybe as a compromise, there's some good languages on top of those stacks. F# exists. You get a lot of the good features that people mention about Rust in this thread without the headaches mentioned in the article.

Expressive GC languages within the major ecosystems exist, no need to reach for a systems language for a web app just because you want the modern, high level features.

Yeah Kotlin, F#, etc. These are all acceptable.
I generally agree, but with the ecosystems they have today I think Python and Node are both completely acceptable for a general purpose low-risk tech stack. In fact I would choose either of those before I'd go with a monovendor solution like .NET & SQL Server.
I would add Go to "JVM or .NET"