HNHacker News
TopNewBestAskShowJobs

ksbrooksjr

263 karma · joined April 11, 2017

Full-stack web developer specializing in TypeScript/JavaScript. Currently working on a Chrome extension called Freezetab. My links and contact info are below.

  Website: https://ksbrooksjr.com/
  Email: hn@ksbrooksjr.com
  Freezetab: https://freezetab.com/
submissionscomments
ksbrooksjr··on Ten Years of TypeScript
I agree that the typescript team should consider using the compiler to extend javascript rather than just supplement it with types. Like you said, there are technically parts of typescript that don't have a direct corollary in js (enums/namespaces), so why not take it a step further and add some of the features that js is missing? The only example where they've really taken that next step is with experimental decorators.

I think in general the js/ts community is starting to realize that if we're going to have all of these build tools, we might as well use them to do more than just format, transpile, and bundle. Svelte has sort of pushed this idea with its abuse of the js label feature (it can detect when a variable is reassigned if you prefix it with the dollar sign label, which is technically not possible with js, even with proxies). There's also React Forget, which is promising to completely rewrite components at compile-time to avoid all of the gotchas that hooks have (and improve performance) [1].

In terms of making all of ts erasable, you can technically just write all your type definitions using js-doc comments, in which case the compiler can just be run with the --noEmit flag, and then the code is fully valid js without any modifications.

[1] https://www.youtube.com/watch?v=lGEMwh32soc

ksbrooksjr··on Ten Years of TypeScript
It can (depending on which features you're using), but the comment that started this thread claimed that the produced code was much slower than handwritten js. I was just pointing out that the examples you gave (enums and namespaces), don't change the performance of your code.
ksbrooksjr··on Ten Years of TypeScript
Const enums get completely erased by the compiler, and modules are a native js feature.

Non-const enums and namespaces are probably the only aspects of typescript that actually have any significance at runtime, but they get compiled into simple objects. The compiler output is very close to what you'd write by hand. Take a look at this compiler output here [1].

Unless you're constantly recreating enums and namespaces inside of a loop (which you'd never do in real life code), I can't imagine there'd be any performance penalty.

[1] https://www.typescriptlang.org/play?target=99#code/HYQwtgpgz...

ksbrooksjr··on Deployment and infrastructure for a bootstrapped webapp with 150k monthly visits
Great write-up. Note that the author is only serving 70 requests per second at peak with 15 thousand registered users and 3 thousand in revenue per month. This just shows that you don't always have to plan to scale to thousands (or millions) of requests per second.

This blue-green deployment workflow reminds me of a similar setup used by the creator of SongRender[1], which I found about via the running in production podcast[2]. One thing to be aware of with smaller VPS providers like Linode, DO, and Vultr is that they charge per hour rather than per second. So if you boot up a new VM every time you deploy you're charged for a full hour each time.

[1] https://jake.nyc/words/bluegreen-deploys-and-immutable-infra...

[2] https://runninginproduction.com/podcast/83-songrender-lets-y...

ksbrooksjr··on Old school Linux administration – my next homelab generation
That's understandable. Not every service needs a perfect uptime record.
ksbrooksjr··on Old school Linux administration – my next homelab generation
Even changing the kernel can often be done without rebooting the system depending on which distro you're using. Quite a few distros now include some sort of kernel livepatching service including Ubuntu, Amazon Linux, and RHEL.
ksbrooksjr··on My VM is lighter (and safer) than your container (2017)
It looks like it still is supported [1]. I noticed while reading the Lima documentation that they're planning on switching from SSHFS to 9P [2].

[1] https://wiki.qemu.org/Documentation/9psetup

[2] https://github.com/lima-vm/lima/blob/3401b97e602083cfc55b34e...

ksbrooksjr··on How SQLite scales read concurrency
My go-to method of inter-process communication in Node without using any third party modules is to just use process.send[1] to a send a message to the main thread, and then have it forward messages to the workers in the cluster, which you can listen for using the message event [2].

[1] https://nodejs.org/api/process.html#processsendmessage-sendh...

[2] https://nodejs.org/api/process.html#event-message

ksbrooksjr··on The future of Nginx: Getting back to our open source roots
Certbot is fine, but it’s nice to have that functionality built directly into the reverse proxy as opposed to having to configure and update multiple tools. I would ideally like to see Nginx integrate a subset of Certbot’s feature set into their code base especially given that offloading SSL is one of the primary use cases of Nginx.
ksbrooksjr··on The future of Nginx: Getting back to our open source roots
Yeah Caddy's developer experience is unrivaled when it comes to setting up SSL. You don't have to run Certbot or manage certificates manually. If you give it a hostname to proxy to, it just handles certificate management seamlessly in the background.

The real killer feature for me is the Cloudflare module. It allows you to use the acme DNS challenge, which means you can test your SSL setup without exposing your server to the public internet.

ksbrooksjr··on Will Bun JavaScript Take Node's Crown
For the simplest benchmarks the performance disparity might come down to the difference between JavaScriptCore (which Bun uses) and V8 (which Node uses), but for anything non-trivial there's a significant amount of overhead introduced by the Node runtime.

Someone wrote a barebones V8 wrapper called Just Js, which is based on V8 just like Node, but it crushed Node in the Techempower benchmarks [1].

[1] https://www.techempower.com/benchmarks/#section=data-r21&tes...

ksbrooksjr··on Astro 1.0 – a web framework for building fast, content-focused websites
Exactly. PHP (like every other modern programming language) has its own dependency management tools. Node is actually better than many in this respect because npm comes bundled with Node — it's not something you have to install separately.

Ironically, Composer actually lists npm as one of its inspirations [1].

> "...Composer is strongly inspired by node's npm and ruby's bundler."

[1] https://getcomposer.org/doc/00-intro.md

ksbrooksjr··on Astro 1.0 – a web framework for building fast, content-focused websites
Well obviously you'll need npm to use a command that begins with npm. If someone gave you a terminal command to run that begins with curl, you'd be expected to have curl installed. This seems like pure pedantry.

Take a look for example at the rust installation steps [1]. They tell you to run the following command in your terminal: "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh". They don't tell you to first make sure you have curl installed (or sh for that matter).

[1] https://www.rust-lang.org/learn/get-started

ksbrooksjr··on Astro 1.0 – a web framework for building fast, content-focused websites
As long as you have npm installed it'll work. Npm create is an alias for the npm init command [1], which will look for a package with the prefix 'create-', install it, and run its bin file. It looks like this is the file that ends up being run: https://github.com/withastro/astro/blob/main/packages/create....

[1] https://docs.npmjs.com/cli/v8/commands/npm-init

ksbrooksjr··on Rsync client-side arbitrary file write vulnerability
Exactly. I'm usually worried about the opposite scenario (the client infecting the server). If you're copying files from a personal computer it might have all sorts of random software running on it that's accumulated over the years. Whereas on a remote server you tend to have a better security posture, and aren't installing random software and apps. Admittedly, that might just be my personal use case though.
ksbrooksjr··on Rsync client-side arbitrary file write vulnerability
It looks like versions prior to 3.2.5 are affected [1]. If you're using the version of rsync bundled with MacOS, then it's affected.

If you're not connecting to random malicious servers then this might not be a part of your threat model though. As long as your private keys are secure, and you've verified the public keys in your known_hosts file, then this exploit would be hard to take advantage of by a man in the middle attack. Basically, all of the normal security rules of the underlying SSH protocol apply here.

[1] https://nvd.nist.gov/vuln/detail/CVE-2022-29154

ksbrooksjr··on Build your own web framework
The fact that googling 'node user login' returns an insecure result is more indicative of the quality of Google's search results than it is of Node. Node has had a built in password hashing function since before it even hit version 1.0 (pbkdf2) [1]. It also has a built in timing safe comparison function for safely comparing values without leaking data via timing attacks [2]. The crypto module is actually pretty extensive.

If you're looking for a traditional web framework (something similar to Flask or Sinatra) I would take a look at Hapi (which has no third party dependencies and is maintained by one of the original authors of the oAuth spec), or you could always try Express (the most popular Node framework), or Fastify (the fastest Node framework).

[1] https://nodejs.org/dist/latest-v18.x/docs/api/crypto.html#cr...

[2] https://nodejs.org/dist/latest-v18.x/docs/api/crypto.html#cr...

ksbrooksjr··on Performance comparison: counting words in Python, C/C++, Awk, Rust, and more
I don't think Swift's performance is due to start up time at all. I actually cloned the repo, and ran the benchmark and found that Swift's execution time scales drastically with the size of the input. The Swift team actually boasts about its quick start up time on the official website [1]. I ran a simple hello world benchmark to gauge Swift's start up time and got an output of 13 milliseconds.

  echo 'print("hello world")' > hello.swift && swiftc hello.swift -O -o hello
  time ./hello
[1] https://www.swift.org/server/
ksbrooksjr··on Ask HN: What are some cool but obscure data structures you know about?
Yeah TC39 has a habit of letting proposals languish at stage 2 for years. I wouldn't give up hope though. The decorators proposal finally made it to stage 3 after spending an eternity at stage 2. According to the slides from the TC39 meeting this month [1][2], it looks like they'll be proposing an advancement to stage 3 in September.

[1]https://github.com/tc39/agendas/blob/main/2022/07.md [2]https://www.dropbox.com/s/g4enjgd4p2npv2s/record_tuple_updat...

ksbrooksjr··on Ask HN: What are some cool but obscure data structures you know about?
If the Record & Tuple proposal advances to stage 3 we'll finally have native immutable data structures in JS [1].

[1] https://github.com/tc39/proposal-record-tuple

ksbrooksjr··on Ask HN: What's your experience with working M1 and M2 Macs?
I definitely get where you're coming from, but I think developers tend to overestimate the complexity of managing servers, and underestimate the complexity of managing a Kubernetes cluster. The last time I looked into Kubernetes even the most minimal setups required 500MB of memory on each machine, and that's assuming you're using a lightweight implementation like k3s or k0s. If you're using a managed service like EKS or GKE you're going to require even more memory and cpu resources. Kubernetes is ostensibly supposed to help you autoscale, but you only end up needing to autoscale because of the memory and cpu that Kubernetes is itself consuming. Most webapps can scrape by with just a single vm. Hacker News itself runs on a single machine [1]. Also if you reserve a vm for long term usage most cloud providers will give you a pretty steep discount [2]. If you need the ability to burst during periods of high traffic, you can just use a burstable instance, which all of the three big cloud providers support (i.e. Azure, GCP, and AWS).

I used to think managing servers introduced unnecessary complexity until I tried it, and realized it's really not as difficult as I thought. With kernel live-patching and unattended upgrades, I never have to manually update anything. Blue-green deployment is as simple as rsyncing files to the server, starting the updated app on a different port, and then updating your reverse proxy's config to point to the new version of the app. Any decent reverse proxy like Caddy or Nginx will support zero downtime config updates. You don't have to build containers, store them in a registry, or update any yaml manifests. Kubernetes manifests have gotten so complex that developers are inventing programming languages like Jsonett and Dhall to generate configuration files.

Also, the skills you learn from managing servers are incredibly portable. Some of the Unix skills that I've gained from playing around with EC2 instances have actually helped me manage my personal Mac (which is of course a member of the BSD family of Unix operating systems). When you learn Cloudformation those skills don't even translate to other cloud providers. The skills that you learn from managing a server are also incredibly stable and stand the test of time. Bash is older than Docker, the programming language (Golang) that Docker was written in, and likely many of the developers using it.

[1] https://news.ycombinator.com/item?id=16076041

[2] https://instances.vantage.sh/?cost_duration=monthly

ksbrooksjr··on Ask HN: What's your experience with working M1 and M2 Macs?
Vagrant has a few advantages compared to Rancher (and Lima[1] which I believe Rancher uses under the hood).

Because of its popularity, there are so many open source Ruby provisioning scripts you can use as a reference when provisioning your own VMs. You can also package up a provisioned VM as what they call a "box" that can be shared with other developers. It also natively integrates with tools like Ansible, Chef, and Puppet which make it a lot easier to manage the provisioning process.

And finally, many of the books and tutorials I've read use Vagrant, so it's much easier to follow along if you have Vagrant installed. For example I was recently reading the book Ansible for Devops by Jeff Geerling, and Vagrant and Virtualbox were used pretty extensively throughout the book.

Also, if you decide to package VMs to use in production it's pretty easy to integrate with Packer, which is another Hashicorp product.

[1] https://github.com/lima-vm/lima

ksbrooksjr··on Ask HN: What's your experience with working M1 and M2 Macs?
The M1 and M2 macs have excellent performance and battery life, but beware of the fact that they don't work with Virtualbox. Virtualbox combined with Vagrant is great for declaratively spinning up a quick vm without using any proprietary software.
ksbrooksjr··on Programming with union, intersection, and negation types
Yeah Typescript is great. It doesn't have a negation type per se, but its pretty easy to derive one using the never type [1]. The author of this essay actually explicitly calls out Typescript several times. Some quotes from the paper's conclusion:

> In this essay I tried to survey the multiple advantages and usages of set-theoretic types in programming.

> ...the need of set-theoretic types naturally arises when trying to fit type-systems on dynamic languages

> The development of languages such as Flow, TypeScript, and Typed Racket is the latest witness of this fact.

[1] https://catchts.com/type-negation

ksbrooksjr··on UIs are not pure functions of the model (2018)
I agree. Another thing to consider is that React makes it frictionless to import custom components, instead of attempting to re-write common UI patterns from scratch.

If a React dev leans on an accessible UI framework like Chakra, or Headless UI, or React-Aria, they're probably better off from an accessibility perspective than a dev that tries to implement WAI guidelines from scratch.

ksbrooksjr··on Angular without SSR is faster than Next.js with SSR
I agree that there's room for a language that runs on the BEAM and also compiles to JS. Gleam looks great, and it's one of the up and coming languages that I'm rooting for. In addition to having a Javascript compile target, it's statically typed which is a prerequisite for me when it comes to productivity and correctness.

There was actually a developer working on a subset of Elixir that compiles to JS called Elixirscript[1], but development seems to have stalled. Another functional statically typed compile-to-js language which targets the BEAM vm is Purescript through the Purerl project [2].

If you're going to compile to JS though, there's an argument to be made that you might not want to target the BEAM at all. You could potentially run your entire backend on something like Cloudflare Workers, which has over 200 points of presence around the world, so latency is about as low as possible. The other CDNs have their own competing worker runtimes as well (e.g. Cloudfront functions, Netlify functions, etc.). These edge worker runtimes also have the benefit of not charging for each individual region in which you operate. You can also run any language which compiles to WASM like Rust, Assemblyscript, or Grain [3] on these edge runtimes. The only missing piece for me is a distributed database, but it looks like Cloudflare at least is working on that [4].

[1] https://github.com/elixirscript/elixirscript

[2] https://github.com/purerl/purerl

[3] https://grain-lang.org/docs/

[4] https://blog.cloudflare.com/introducing-d1/

ksbrooksjr··on The new wave of React state management
The commenter I was replying to wasn't inquiring about why people choose third-party state management libraries in lieu of the standard context api. In fact, he's not even a web developer.

He seemed to be wondering why you need a state management solution in the first place. If he had asked why people prefer Zustand, or Redux, or Recoil over React's built in context api then I would have replied accordingly.

I was largely expounding upon the linked article's first list item under the heading "The problems global state management libraries need to solve". The first item in that list begins with:

> Ability to read stored state from anywhere in the component tree. This is the most basic function of a state management library. It allows developers to persist their state in memory, and avoid the issues prop drilling has at scale.

I would argue that the primary function of state management libraries is still sharing state between components. Third-party libraries might expose a more performant, simpler, or more intuitive api, but that's still their primary purpose. Analogously, if a non-compiler developer asked why programming languages need memory management, you wouldn't delve into the differences between reference counting and tracing garbage collection.

ksbrooksjr··on The new wave of React state management
Most state management libraries help you deal with the problem of sharing state between multiple components. In modern React, most components are just functions, so this boils down to passing state through deep call stacks.

If you have a component A, which renders component B, which in turn renders component C, without a state management library you'd have to pass state from A to B to C (this is often called prop drilling). The longer the call stack, the more irritating this becomes.

State management libraries allow component C and component A to modify, and subscribe to a shared state store. Redux et al. are effectively the reactive version of global variables.

ksbrooksjr··on Angular without SSR is faster than Next.js with SSR
Yeah you can definitely pull in Alpine for UI updates that don't require any server side interaction, but then your app's logic is fragmented between different frameworks (Alpine and LiveView).

It's definitely doable, and I know the PETAL stack (Phoenix Elixir Tailwind Alpine) is super popular, but it's nice (and perhaps less error prone) to have all of your UI logic handled by a single framework. This consolidation of UI code under a single framework was one of the killer features of SPAs initially. Prior to that lots of sites were built with a server side templating framework with jquery sprinkled in for client side UI updates.

ksbrooksjr··on Angular without SSR is faster than Next.js with SSR
The obvious downside to Liveview is that all of the UI state resides on the server. Every UI update therefore requires a full roundtrip request to the server, and so reducing latency is of paramount importance. That's why fly.io is so heavily invested in the Phoneix ecosystem, because their service is predicated on the idea of distributing your app globally to reduce latency. A React/Angular/Vue spa on the other hand can make decisions about how to update the UI without contacting the server. In fact, many PWAs these days are actually designed to work completely offline.
← PreviousPage 2 of 3Next →