7 ms·
I notice this time and time again: projects start with a flexible scripting language and a promise that the performance will be sufficient. I mean, JS is pretty
by zoogeny 2y ago
I notice this time and time again: projects start with a flexible scripting language and a promise that the performance will be sufficient. I mean, JS is pretty performant as scripting languages go and it is hard to think of any language runtimes that get more attention than the browser VMs. And generally, 90% of the things people do will run sufficiently fast in that VM.
Yet projects inevitably get to the stage where a more native representation wins out. I mean, I can't think of a time a high profile project written in a lower level representation got ported to a higher level language.
It makes me think I should be starting any project I have in the lowest level representation that allows me some ergonomics. Maybe more reason to lean into Zig? I don't mean for places where something like Rust would be appropriate. I mean for anything I would consider using a "good enough" scripting language.
It honestly has me questioning my default assumption to use JS runtimes on the server (e.g. Node, deno, bun). I mean, the benefit of using the same code on the server/client has rarely if ever been a significant contributor to project maintainability for me. And it isn't that hard these days to spin up a web server with simple routing, database connectivity, etc. in pretty much any language including Zig or Go. And with LLMs and language servers, there is decreasing utility in familiarity with a language to be productive.
It feels like the advantages of scripting languages are being eroded away. If I am planning a career "vibe coding" or prompt engineering my way into the future, I wonder how reasonable it would be to assume I'll be doing it to generate lower level code rather than scripts.
- sapiogram 2y ago> I mean, I can't think of a time a high profile project written in a lower level representation got ported to a higher level language. Software never gets rewritten in a higher level language, but software is constantly replaced by alternatives. First example that comes to mind is Discord, an Electron app that immediately and permanently killed every other voice client on the market when it launched.
- wrs 2y agoIt’s a little more nuanced though — I doubt the audio processing in Discord is written in JavaScript. (But I haven’t looked!)
- timeon 2y agoIsn't most of Discord backend Rust and Go?
- JustSkyfall 2y agoThey mostly use Elixir on the backend, with Rust for a few services like Go Live. IIRC they don’t use Go anymore
- wrs 2y agoGiven the mention of Electron, I was talking about the client side.
- zoogeny 2y agoYes, scripting replacements often usurp existing ossified alternatives. And there is some truth that a higher level language gave some leverage to the developers. That is why I mentioned the advent of LLM based coding assistants and how this may level the playing field. If we assume that coding assistants continue to improve as they have been and we also assume that they are able to generate lower level code on par with higher level code, then it seems the leverage shifts away from "easy to implement features" languages to "fast in most contexts" languages. Only time will tell, of course. But I wonder if we will see a new wave of replacements from Electron based apps to LLM assisted native apps.
- colonelspace 2y ago> Discord ... immediately and permanently killed every other voice client on the market Do you mean voice clients like FaceTime, Zoom, Teams, and Slack?
- xandrius 2y agoI don't think the success of Discord is due to it being written in Electron. Or is it?
- jonathanlydall 2y agoI game very little these days, but have run mumble, ventrillo and teamspeak in the past and the problem was always the friction in onboarding people onto them, you’d have to exchange host, port, password at best, or worse, explain how to download, install and use. Discord can run from a browser, making onboarding super easy. The installable app being in Electron makes for minimal (if any) difference between it and the website. In summary, running in the web browser helps a lot, and Electron makes it very easy for them to keep the browser version first class. As an added bonus, they can support Linux, Windows and macOS equally well. I would say it helps as without Electron, serving all the above with equal feature parity just would have been too expensive or slow and perhaps it just wouldn’t have been as frictionless for all types of new users like it is.
- Cthulhu_ 2y agoI do believe it's a factor; web apps have the most freedom when it comes to visual design (and the vast majority of developers for it), and it makes it a crossplatform application. Electron and web applications are the market leader in front-end / client side applications by a very wide margin. I mean I don't like it but that's how it is.
- timeon 2y agoSure but that comment was mostly about backend. If Discord used js/ts for backend they wouldn't replace anyone.
- throwitaway1123 2y ago> I mean, I can't think of a time a high profile project written in a lower level representation got ported to a higher level language. Prisma is currently being rewritten from Rust to TypeScript: https://www.prisma.io/blog/rust-to-typescript-update-boosting-prisma-orm-performance https://www.prisma.io/blog/rust-to-typescript-update-boostin... > Yet projects inevitably get to the stage where a more native representation wins out. I would be careful about extrapolating the performance gains achieved by the Go TypeScript port to non-compiler use cases. A compiler is perhaps the worst use case for a language like JS, because it is both (as Anders Hejlsberg refers to it) an "embarassingly parallel task" (because each source file can be parsed independently), but also requires the results of the parsing step to be aggregated and shared across multiple threads (which requires shared memory multithreading of AST objects). Over half of the performance gains can be attributed to being able to spin up a separate goroutine to parse each source file. Anders explains it perfectly here: https://www.youtube.com/watch?v=ZlGza4oIleY&t=2027s https://www.youtube.com/watch?v=ZlGza4oIleY&t=2027s We might eventually get shared memory multithreading (beyond Array Buffers) in JS via the Structs proposal [1], but that remains to be seen. [1] https://github.com/tc39/proposal-structs?tab=readme-ov-file https://github.com/tc39/proposal-structs?tab=readme-ov-file
- zoogeny 2y agoI think the Prisma case is a bit of a red herring. First, they are using WASM which itself is a a low-level representation. Second, the performance gains appear primarily in avoiding the marshalling of data from JavaScript into Rust (and back again I presume). Basically, if the majority of your application is already in JavaScript and expects primarily to interact with other code written in JavaScript, it usually doesn't make sense to serialize your data, pass it to another runtime for some processing, then pass the result back. As for the "compilers are special" reasoning, I don't ascribe to it. I suppose because it implies the opposite: something (other than a compiler) is especially suited to run well in a scripting language. But the former doesn't imply the later in reality and so the case should be made independently. The Prisma case is one: you are already dealing with JavaScript objects so it is wise to stay in JavaScript. The old cases I would choose the scripting language (familiarity, speed of adding new features, ability to hire a team quickly) seem to be eroding in the face of LLMs.
- Tadpole9181 2y agoThe JS `tsc` type checks the entire 1.5 million line VS Code source in 77s (non-incremental). 7s is a lot better and will certainly imrpove DX - which is their goal - but I don't see how that's "insufficient". The trade-off is that the team will have to start dealing with a lot of separate issues... How do tools like ESLint TS talk to TSC now? How to run this in playground? How to distribute the binaries? And they also lose out on the TS type system, which makes their Go version rely a little more on developer prowess. This is an easy choice for one of the most fundamental tools underlaying a whole ecosystem, maintained by Microsoft and one of the developers of C# itself, full-time. Other businesses probably want to focus on actually making money by leading their domain and easing long-term maintenance.
- melbourne_mat 2y agoI think it's smart to start with a high level language which should reduce development time, prove the worth of the application, then switch to a lower level language later. What was that saying again? Premature optimisation is the root of all evil
- vacuity 2y agohttps://news.ycombinator.com/item?id=29228427 https://news.ycombinator.com/item?id=29228427 A thread going into what Knuth meant by that quote that is usually shortened to "premature optimization is the root of all evil". Or, to rephrase it: don't tire yourself out climbing for the high fruit, but do not ignore the low-hanging fruit. But really I don't even see why "scripting languages" are the particular "high level" languages of choice. Compilers nowadays are good. No one is asking you to drop down to C or C++.
- Cthulhu_ 2y agoI think (personal opinion / belief) Go hits that sweet spot; it's an "easy" language, but compiles down to a binary instead of e.g. Java, C#, JS etc. Mind you I'm sure there were similar attempts at a language with those goals, but they didn't have the backing of Google.
- Byamarro 2y agoI think that early in development you should be able to spam a lot of hypothesis and quickly test them and check how people interact with your software. Whether your software makes sense is more important than whether it's fast. People are also highly unpredictable, so it is usually a matter of trial and error, very often their feedback may completely erase wide sets of assumptions you were building your product around. It's borderline impossible to do it on mature product, but rewriting mature product to something faster is not borderline impossible - it's just very hard. Note that it doesn't apply if you just program something in accordance from an rfc where everything is predefined.
- jerf 2y agoI think a lot of people are running on facts that are between 10 to 25 years out of date. There was a time when the scripting languages had a very, very large step up in prototyping capability, because the static languages of the time were frankly terrible. But the static languages have changed, a lot, for the better since then. I now find that when I'm greenfielding something, if I have even a clue how I want to structure it overall, that static languages end up being faster somewhere around a week into the development process. Dynamic languages are superficially easier to refactor, but the refactorings tend to take the form of creating functions that take more and more possible inputs and this corrodes the design over time. Static programs stay working the whole time, and I can easily transform the entire program to take some parameter differently or something and get assurance I'm not missing a code path. I personally actively avoid dynamic languages for initial development now, for anything that is going to be over a week in size. The false economies are already biting by that point and it gets progressively and generally monotonically worse over time. This comes from someone who was almost 100% dynamic scripting language in the first 15 years of my career. It's not from lack of understanding of dynamic scripting languages, used at scale.
- ironmagma 2y agoInevitably? Well, the promise of using something less efficient in terms of performance is that it will be more efficient in terms of development. Many times projects fail because they optimize too early and never built the features they needed to or couldn’t iterate fast enough to prove value and die. So if the native version is better but failed, it’s not so inevitable that it will get to that stage.
- zoogeny 2y agoRight, which is my point about LLM code assistants. If you did have two cases in the past: native but slow to add features so the project eventually dies vs. scripted but performance is bad enough it eventually needs to be rewritten. (Of course, this is a false dichotomy but I'm playing into your scenario). Now we may have a new case: native but fast to add features using a code assist LLM. If that new case is a true reflection of the near future (only time will tell) then it makes the case against the scripted solution. If (and only if) you could use a code assist LLM to match the feature efficiency of a scripting language while using a native language, it would seem reasonable to choose that as the starting point.
- ironmagma 2y agoThat’s an interesting idea. It’s amazing how far we’ve come without essentially any objective data on how much these various methodologies (e.g. using a scripting language) improve or worsen development time. The adoption of AI Code Assistance I am sure will be driven similarly anecdotally, because who has the time or money to actually measure productivity techniques when you can just build a personal set of superstitions that work for you (personally) and sell it? Or put another way, what manager actually would spend money on basic science?
- pier25 2y ago> It honestly has me questioning my default assumption to use JS runtimes on the server (e.g. Node, deno, bun). The JS runtimes are fine for the majority of use cases but the ecosystem is really the issue IMO. > the benefit of using the same code on the server/client has rarely if ever been a significant contributor to project maintainability for me I agree and now with OpenAPI this is even less of an argument.
- timewizard 2y ago> the lowest level representation that allows me some ergonomics The ergonomics of compiling your code for every combination of architecture and platform you plan to deploy to? It's not fun. I promise. > my default assumption to use JS runtimes on the server AWS Lambda has a minimum billing interval of 1ms. To do anything interesting you have to call other APIs which usually have a minimum latency of 5 to 30ms. You aren't buying much of anything in any scalable environment. > there is decreasing utility in familiarity with a language to be productive. I hope you aren't planning on making money from this code. Either way, have fun debugging that! > the advantages of scripting languages are being eroded away. As long as scripting languages have interfaces which let them access C libraries either directly or through compiled modules they will have strong advantages. Just having a CLI where you can test out ideas and check performance is massively powerful and I hate not having it in any compiled project. Go has particularly bad ergonomics here as writing test cases are easy but exploring ideas is not due to it's strictness down to even the code styling level.
- zoogeny 2y ago> compiling your code for every combination of architecture and platform you plan to deploy to I mean, on the one hand you are arguing for C FFI and on the other worrying about compiling for every combination of architecture. Those positions seem to be contradictory. Although I guess you're assuming that other people who write the C libraries for you did that work. I guess you better hope libraries exist for every possible performance issue you come across in your cross platform scripting library. And why limit your runtime to AWS Lambda? That is a constraint you are placing on yourself. Nowadays with docker you can have pretty much any Linux you want as an image. But why not just implement on top of cgroups from scratch? I guess we live a world where that is unthinkable to many. Probably just better to pay AWS. But if you do use docker, all of a sudden worrying about compiling for all of those architectures seems like less of an issue. And you can use ECS, so you can still pay AWS! As for tooling issues, and there are definitely tooling issues with every language, it is a pick your poison kind of thing. I remember really liking Pascal tooling way back in the day. Smalltalk images have some nifty features. Who doesn't like Lisp, the language that taught us all REPL. Not sure I'd choose them for a project today though. As LLMs get better, I just assume what constitutes "developer experience" is going to change. Will I even care about how unergonomic writing test cases in Go can be if I can just say "LLM, write a test that covers X, Y, Z case". As long as I can read the resultant output and verify it meets my expectations, I don't care how many characters of code or boilerplate that will force the LLM to generate. edit: I misread your point about Go test cases but I'll leave my mistake standing. My overall point was the stuff I find annoying to do myself I can just farm out to the LLM. If the cost of writing an experiment is "LLM, give this a try" and if it works great and if not `git checkout`, then I will be ok with something less optimal.
- winwang 2y ago"A sufficient smart compiler..."
- bartvk 2y ago> And it isn't that hard these days to spin up a web server with simple routing, database connectivity, etc. in pretty much any language including Zig or Go Just two years ago, a friend of mine described it as quite a hassle to get a RESTful backend running in Go. He got it working but it was more work than usual. Was he an outlier or have things been getting better in the framework department?
- whattidywhat 2y agoNot sure when your friend tried Go but for the last 5-10 years or so go has been really easy to make REST services. It's practically baked into the language but if you want it even easier there are several extremely popular libraries for it. Go tends to have more boiler plate than other languages. So more typing work, less thinking work, less maintenance work once completed.
- pjmlp 2y agoAI tooling is the new wave of Assembly => Compilers transition. It won't happen tomorrow, but I am quite certain eventually it will be in a position where executables are generated directly, and we will enter into a new computation model. Like you can nowadays still inspect the generated Assembly, and eventually fine tune it, our AI tools of the future might provide a similar approach.
- zoogeny 2y agoI suspect this will be the case. And people arguing about dynamic interpreted scripting language vs. static compiled binary language will be like people arguing over flavors of assembly. Just like being familiar with assembly is extremely useful in certain circumstances (I spent a lot of time looking at assembly while working in the games industry. In fact, I was part of a small group that found a bug in the MS C++ compiler which we discovered by inspecting the output assembly) it will be extremely useful for programmers to be competent in the low level representations. At least for a good long while (probably years) we'll review almost all of the code generated before shipping it. But it won't be long until we just "trust" the output of the AI tooling. And by "trust" I mean we will have engineering practices in place to validate the software before release. Unit testing, integration testing, functional testing, static analysis, etc. At some point the volume of code generated by the AIs will be so much that it won't be practical to consider every single line of code. Just like the volume of assembly created by the C compiler is so much that for the most part we just assume it is fine. Only in special cases do we narrowly focus on a hot loop or some other part of the code. This might happen slowly, over decades, or quickly over the next two years.
- physicsguy 2y agoStarting any project in the lowest level representation might make it take twice as long and stymie adoption though. It's a hard trade off when you start a project.
- mpweiher 2y agoYes, I think the promises of the "we can JIT all the overhead away"-camp were always overblown, and never materialized in practice. This is another very strong datapoint for that hypothesis[1]. However, it is important not to conflate "scripting language" and "dynamic language" and "interpreted". While there is some correlation there, it is not a necessary one. Objective-C is an example of a fast AOT-compiled pretty dynamic language, and WebScript was an interpreted scripting language with pretty much identical syntax and semantics.[2] What do I mean with fast? In my experience, Objective-C can be extremely fast [3], though it can also be used very much like a scripting language and can also be used in ways that are as slow or even slower than popular scripting languages. That range is very interesting. So I don't actually think the tradeoff you describe between low-level unergonomic fast and high-level ergonomic slow is a necessary one, and one of the goals of Objective-S is to prove that point.[4] So far, it's looking very good. Basically, the richer ways of connecting components appear to allow fairly simple "scripted" connections to achieve reasonably high performance [5]. However, I now have a very simple AOT compiler (no optimizations whatsoever!) and that gives another factor 2.6 [6]. Steve Sinowsky wrote: "Does developer convenience really trump correctness, scalability, performance, separation of concerns, extensibility, and accidental complexity?"[7]. I am saying: how about we not have to choose? And I'd much rather debug/modify semantically rich, high-level code that my LLM generated. [1] https://blog.metaobject.com/2015/10/jitterdammerung.html https://blog.metaobject.com/2015/10/jitterdammerung.html [2] https://blog.metaobject.com/2019/12/the-4-stages-of-objective-smalltalk.html https://blog.metaobject.com/2019/12/the-4-stages-of-objectiv... [3] https://www.amazon.com/gp/product/0321842847/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321842847&linkCode=as2&tag=metaobject-20&linkId=4f7c355096938fece9d7c880e6916ce8 https://www.amazon.com/gp/product/0321842847/ref=as_li_tl?ie... [4] https://objective.st https://objective.st [5] https://blog.metaobject.com/2021/07/deleting-code-to-double-performance-of.html https://blog.metaobject.com/2021/07/deleting-code-to-double-... [6] https://dl.acm.org/doi/10.1145/3689492.3690052 https://dl.acm.org/doi/10.1145/3689492.3690052 [7] https://darkcoding.net/research/IEEE-Convenience_Over_Correctness.pdf https://darkcoding.net/research/IEEE-Convenience_Over_Correc...
- zoogeny 2y agoYeah, "scripting" language isn't a good word choice on my part. I did mean dynamic/interpreted. But even nowadays that line is blurry with bytecode VMs. > And I'd much rather debug/modify semantically rich, high-level code that my LLM generated. This I agree with. In fact, we may find that the natural fit for use with LLMs is a language not popular amongst humans. The main issue, in my opinion, is we end up with native code executables, complete control over memory layout and direct access to system calls. Those properties just happen to align with languages like Rust, Go, Zig, C/C++, etc. but they aren't limited to them.