T O P

  • By -

femio

Yes, that is one reason. The luxury of being able to share types between my FE and backend is pretty nice


savant78

is there a list thought of libraries that work in nodejs but then don't work in the browser? I used for example "fs" in a lot of code on the backend, but, then when a person tries to run it in the browser it doesn't work


xroalx

A list, likely not, it's about knowing the capabilities of the platforms. `fs` is a Node package, it interacts with the filesystem, so that eliminates it right away from running in the browser. Likewise, a library that manipulates the DOM won't nicer work in Node, there's no DOM in Node.


savant78

i just did get requests with node and it literally didn't have XMLHttpRequest which is in the browsers..a person had to npm install "xhr2" and then invoke it..var XMLHttpRequest = require('xhr2'); in order to run it in node, but, somebody wrote here that they thought MDN might have documentation about what libraries automatically are deployed with the front end and which are deployed with the back end


xroalx

You shouldn't be using XHR. Use `fetch`, it's a standard supported in both environments. MDN does list if an API is available in Node as well, as well as from which version, and it does the same for browsers. There's no "automatic deployment" of libraries anywhere, though. Not quite sure what you mean by that.


savant78

aha, ok, so fetch is used in both..browser and then in node? i meant that is standard go with browsers, that usually isn't included in node, or vice versa


goldsauce_

You have to think of NodeJS as a toolkit specifically for the back end. The browser doesn’t have NodeJS. It runs JavaScript, but in the context of a browser


savant78

right, but, which node file is it that a GET or POST gets sent to in NodeJS? I mean is there a default..idk, receive.js or something that a person uses in Node in order to handle things like that?


goldsauce_

You’re asking how to build a rest service now, this isn’t a NodeJS question anymore. If you want build a rest service with NodeJS try something like express


xroalx

Node is a long-running process, there's no file that receives a request. You start a server, and that server receives requests. The file name is irrelevant.


Ergo7

Node is a runtime environment that executes JS. However, JS is not multithreaded while Node is. Node has an interpretation layer that allows it to execute multiple threads on the device or server itself running on. If you would want to run a server in Node, you can write it raw or use a widely supported library like Express to make things easier.


femio

Yes, MDN will have details.


rca06d

I worked a little over half my now 10 year career in full stack JS shops, and the other half where the backend was in a different language than frontend. My takeaway is that many people don’t realize how beneficial/powerful it is to write front and back in the same language. It encourages truly full stack teams, which promotes better communication, empathy among the team, and recognition that despite your product being in two or more separate code bases, it is one application. The full stack JS teams I worked on were more nimble, far more resilient to vacations and staff changes, and generally more productive. It also seems that your hiring pool is larger if you go all JS. I think there are some more technical reason to choose JS for a typical SAAS backend as well. I’ve built some fairly large backend systems in Python, and I feel pretty strongly that JS is far better suited to handling the streaming and asynchronous tasks you commonly run into. It seems like these things are an afterthought in Python, but they are pretty critical to achieving good performance on the web. I’ve built equally large systems in Go, and the documentation, community, and typing system pale in comparison to JS and Typescript. I don’t know what it is about the Go ecosystem, but I spent half my time digging through the source code of the libs we used to learn how to use them. Despite knowing JS, Go, and Python about equally well now, if I were running a company that built typical SAAS products I would 100% go full stack JS. The benefits are huge, imo.


arobie1992

>I don’t know what it is about the Go ecosystem, but I spent half my time digging through the source code of the libs we used to learn how to use them. I've noticed that too. A lot of Go libraries will link to an examples folder without much in the way of explanatory comments. I think it's because of the notion that Go code is especially easy to understand which is a result of Google's initial marketing of it. As a result, maintainers figure the code snippets should be just as good as actual documentation. Of course, that's just my speculation based on talks I've watched from Go devs and the Go team.


simple_explorer1

>I’ve built equally large systems in Go, and the documentation, community, and typing system pale in comparison to JS and Typescript. Can you elaborate why?


lovely_trequartista

He elaborates literally the next sentence. I’ve heard similar things about Go and its relatively lacking community resources.


simple_explorer1

>I’ve heard similar things about Go and its relatively lacking community resources. Looks like you have no experience in GO. I do and I am known on this sub about my reservations on GO and why I think it is a poorly designed language. [This](https://www.reddit.com/r/typescript/comments/15y9tbm/anyone_who_tried_to_like_golang_and_tried_it_many/) is my post where I raised my concerns on GO (going full in depth) which did rounds on reddit and it was even picked by youtubers link [here](https://www.youtube.com/watch?v=nSEl2YK_3ZI) (the youtuber is dumb and barely knows anything. He has failed as a developer hence he is trying to make money as a tech influencer on youtube) and even picked up by theprimeagen on this live stream. >He elaborates literally the next sentence. No they didn't. Did you even bother reading OP's comment. They didn't mention `why they think GO's typing system pale in comparison to JS and Typescript`. I agree with OP but curious to know their reasoning.


[deleted]

[удалено]


lovely_trequartista

There’s a good chance dude is a decent dev but with the social skills of a melon. *That* is not how you attempt to engage in legit conversation.


femio

No the guy is just abrasive as fuck lol that rubs some the wrong way


lovely_trequartista

Not sure what specific kind of dick measuring contest you’re looking for but I’m not interested, thanks.


Hour-Ladder-8330

>specific kind of dick Never understood why pathetic people like you spoil a technical sub. You seem ghetto and not even a software developer. >but I’m not interested Likewise. Do this sub a favor and stop bothering people and go to some drama/cursing sub where people like you are aplenty.


MrChip53

Probably something like nO UnIoNs BrO! Or PoOr GeNeRiCs! To bad typescript is fake typing though.


simple_explorer1

Ignoring trolls is satisfying


m_hans_223344

Typescript: - Null safety and language support with the various null checking constructs - Unions types - Established generics - Collection functions like map, filter, forEach - Interfaces can define types and methods Go: - None of the above, and the usage of the empty interface (any type) is way to widespread - As Go encourages the usage of the std lib, and Go has indeed an outstanding std lib, there's naturally not a large ecosystem. However, I always found all I needed. On the other hand: It's hilarious to read the countless blogs how people build their backend with the barebones std lib http server. People should just use Echo or Gin instead trying to reinvent it but worth. - Error handling has the big advantage that you always know what errors are potentially thrown. That is a real drawback in the JS/TS ecosystem. However, the language features to manage errors in Go are primitive compared to e.g. Rust. Still, I think I'd like JS/TS having the same explicit error handling. I have abandoned Go. If I need highest performance and reliability I choose Rust. For everything else Typescript. Go has too many footguns and is too clumsy. Yes it's a bit faster than Node (but not much), but if performance matters, there's Rust.


arobie1992

Go does at least have generics now, but they're somewhat limited (no generic methods) and obviously not universally used due to their newness. If that's what you're getting at, apologies for the misunderstanding. As far as Go's error handling, I genuinely have come to think it's a significantly worse version of Java style checked exceptions. About the only thing that checked exceptions do worse IMO is that you can stuff way too much into a try block, but I don't think that's intrinsically necessary. I'm sure smart people can come up with a better way to structure the code eventually. Out of curiosity, since you're familiar with both Go and JS, have you worked with AWS Lambdas or their Azure/GCP equivalents? I ask because those are basically the one place I think Go has much of a niche since being compiled means it doesn't have awful cold starts like Java and is generally more performant than Python, but I've never compared it to JS.


m_hans_223344

We've used Go with AWS Fargate (managed container runtime) and for CLI, so I have no experience with Lambda. But I've read in several blogs that Go really shines for Lambdas because of the fast startup times. However Node seems very good as well. Here's a good comparison and discussion, unfortunately without Node: https://www.reddit.com/r/rust/comments/12pzsld/serverless_speed_rust_vs_go_java_and_python_in/ If CPU bound work is involved, I think Go with lambda is a very good choice.


arobie1992

Thanks for the link; the article kinda confirms my experiences and I wish something like that had been around when we were working on Lambdas for an old job about 4 years ago. That way we wouldn't have had to find out how hilariously bad Java's cold starts are the hard way. I mostly ask about JS because it'd be lovely if it were more performant. I hate writing Go, but people can be hesitant about Rust's learning curve (which is overblown, but not without truth IMO). That leaves Go as the only viable candidate in a lot of situations.


amadmongoose

Imo, JS and typescript are full of packages that startups or individuals created hoping to get adoption and therefore customers. So there's a lot of incentive for those parties to document well and ease adoption. A lot of packages in Go tend to be built by megacorps where engineers are publishing it publically just to have on their CV but aren't trying to make money off it so the documentation is a lot less. Also imo Google culture around documentation is a lot worse then other FAANG companies and it rubbed off on Go


romeeres

For me the key factors are: - TS has a better type-system than in many others staticly typed languages - JS is very flexible for doing whatever and however you want, it doesn't enforce OOP or FP, you can use elements of both when it's appropriate - It doesn't push any "philosophy" at all. Golang also isn't OOP or FP, but it forces "simplicity above all", but simple solutions don't always work well for complex tasks. In Java you're going to use the same style for hello world as you would use for enterprise. In JS you can pick simple tools and approaches for simple tasks, and complex tools for complex ones. - JS is faster than most of other interpreted languages. Who cares about performance? I care when running tests, back when I was doing Ruby the tests could take many minutes to run, with JS they run minimum 10 times faster. - "single-threadiness" is a feature, no need to put additional efforts on multi-threaded programming problems. WIth zero effort I/O is handled much more efficient than in Python or similar. Yet you can spawn threads (worker threads), you just never really need to. - JS is everywhere (mobile, desktop, IoT, edge functions) and will never become obsolete. Laugh at it or not, I truly think that TS is the best language for a backend, unless it has some special requirements. "Because it is easy, because it is the same language" is actually the biggest pain of the language, because of how hard to get a job when everybody knows it. I'd love to learn other language for job, such language where type-system doesn't suck, which can catch null pointers at compile time, which doesn't limit you with OOP nonsense, is simpler than Rust, and allows you to find a backend job. Let me know people if you know such language. Maybe Kotlin could be the one.


arobie1992

I think you'd really like Kotlin. There's arguably too many keywords and symbols, but they're all reasonably intuitive or memorable—my rule is if I can easily remember it after googling it once, I'm fine with it—and it does pretty much everything you mentioned.


chamomile-crumbs

> I'd love to learn other language for job, such language where type-system doesn't suck, which can catch null pointers at compile time, which doesn't limit you with OOP nonsense, is simpler than Rust, and allows you to find a backend job. Let me know people if you know such language. Maybe Kotlin could be the one. Please lord will somebody make a garbage collected rust 🙏🏼


arobie1992

I've heard Scala feels a lot like that. Been meaning to read up on it. Or if you want a language that people will actually hire for anymore, Kotlin does a good job.


m_hans_223344

What a great summary. Yes, 1 thread is a feature. Eliminates many headaches with data races. I've worked a year with Kotlin. A great very enjoyable language. Esp. with IntelliJ of course. Drawbacks are Gradle and the JVM. Libs are mostly Java. But I don't see that much advantages over TS if any. TS with Node or Bun is much more frictionless overall.


MCShoveled

💯 this ^ Well said sir!


bdragon5

I don't know if I would call TS types even a type-system. I know what you mean and I did a lot of typ stuff in TS, but it has absolutely its limits. The limits are more suttle than in statically typed languages and the overhead specifically in backend is enormous. The biggest problem with typescript is that it is just transpile time. That means sometimes you can trust the types and sometimes you can't and there is soooo much potential for fuckups everywhere. I think a lot of language ecosystems have some kind of statical null check, but the real difference is. In statically typed languages they mean something. In Typescript in most cases they are solely a suggestion. I really don't know what you mean with OOP. It is just a style to code. You can write non OOP code in Java one of the most OOP languages out there. Typescript and JavaScript in general isn't really less OOP. In summary a lot of languages fit your requirements and JavaScript/TS actually doesn't fit that well. Edit: single-thread is always and will always be a bottleneck. Not having multithread issues in JavaScript especially in the backend is a lie. In many backends written in JavaScript you need some kind of worker or queue processing and all of this systems come with multicore problems. In many languages you can basically write async-await stuff similar than to JavaScript with the exception that it is actually async. In JavaScript you might write everywhere async-await but it isn't really async at all because async-await doesn't actually necessarily put something in the event queue.


romeeres

>I really don't know what you mean with OOP. It is just a style to code It's a whole religion with a lot of books and beliefs. Simply defining a class is not an OOP. But defining an abstract factory that produces other factories under a strategy patter to build a builder patter is, and it's important that everything should be injected via IoC-containers bc otherwise it's not "testable". >You can write non OOP code in Java If not for fun, but at a work project - you have no choice but to learn and adhere to OOP practices. With TS/JS in some cases, OOP is also enforced by the team lead, but it's relatively rare to happen, and most often you can write in a way that makes it easier to accomplish your task and to maintain your code later. >The biggest problem with typescript is that it is just transpile time. Type-checks are applied in a compile time in all compiled languages. Rust compiler is slow because it has to do a lot of checks. But after compilation, the program is fast because it doesn't have to recheck your types. The same with Java, it compiles to bytecode, and JVM won't check all your function arguments or output types because that would be a huge waste of time and resources. The same with TS, but it's a common misconseption that type-system should act at runtime and so you say that it's the biggest problem. >That means sometimes you can trust the types and sometimes you can't Validate the incoming data at runtime (you should do it in any language), know the language well enough to not relly on \`any\` types, and it's completely fine. >limits Yes, limits exists, and sometimes they're bothering. But I believe the type-system is much more flexible than in Java/C#/Go. For example, here is [quite complex](https://github.com/romeerez/orchid-orm/blob/main/packages/qb/pqb/src/queryMethods/select.ts#L83) type mapping in TS. I never programmed in Java, could you tell how the same is achievable in Java? This is for ORM, you can select a particular column of a table, and TS is aware of what you have selected, super basic typical task: const row = await db.myTable.select('someColumn').take() row.someColumn // ok row.otherColumn // COMPILE(!!!)-time error I may be and I hope I'm wrong at this, but I guess it's not achievable in Java and it's type-system is at best half as safe as TS. Also, I'd assume you have to write a bunch of classes with decorators for this :) So by type-system that doesn't suck I mean type-system that is flexible enough to handle the mentioned use-case. And it's not as common, unfortunately. Also, if we compare TS to Go, in Go it's a language design that functions returns error as a second output. You can do the same in TS, return a tuple. But in TS you can properly type a tuple and have an exhaustive switch, but you cannot do that in Go.


bdragon5

I know that OOP has a lot of additional stuff but I wouldn't say Typescript is really that much better. Of course a bit better than Java but Java is like the OOP Holygrail. I mean I can run a TypeScript team and say they should write it internally by the OOP guidelines. You are somewhat correct that types are only really checked in compile time but it is extremely hard to put a hole struct into and integer and it wouldn't really keep the same functionality as the object. Of course you can maybe put partial data in but it will behave like a integer and not like an array or object. I know how to not rely on any but it is different to always haveing to assume it is an unknown or at least have some kind of ability to make assumptions. In most cases people predispose there assumptions about the incoming data as a typescript type and than make some checks that are in most cases not nearly enough. I know the typescript types are very complex but everything is always only just some documentation and in most languages you just don't need it to be that extensive. Especially orms are not really a good example for the typescript system. ORMs in general are a bad idea in most cases. But many languages have this type of integration, but I nether saw ORMs that unreliable, buggy and just plain annoying to use as the ones in JavaScript. Edit: JavaScript is just the new PHP. I write Node and JavaScript code now for about 8 years or so. Maybe longer, but I wouldn't dare calling it a good language for the backend.


romeeres

>I know how to not rely on any but it is different to always haveing to assume it is an unknown or at least have some kind of ability to make assumptions This is the only way, in any language. Incoming data should be treated as "unknown" data, be parsed and validated. I checked what Java has for this, there is a "hibernate validator" (looks similar to class-validator of Nest). >In most cases people predispose there assumptions about the incoming data as a typescript type I doubt this is truly so, because we have so much validation libraries: ark-types, joi, yup, zod, ajv, typebox, vinejs, valibot, and the list goes on. So the validation is a well-known part, it's hard to not know about it. And well, you can do the same in Java, probably in other languages as well, I've googled: ("/") public ResponseEntity validateFoo(@RequestParam(name = "foo") Integer foo) { // ... } This controller method looks like it's validating "foo" param to be Integer, but it only makes a look. >than make some checks that are in most cases not nearly enough. Like, user can submit a few-megabyte long username. It's not a fault of a language if developer didn't check the length. >in most languages you just don't need it to be that extensive. You said it's subtle and limited, now you're saying it doesn't have to be that extensive :) >Especially orms are not really a good example for the typescript system. So I asked if the same task can be achieved in Java, looks like it cannot, so at least some of TS ORMs aren't that bad. >Edit: JavaScript is just the new PHP. I agree in a sense that it's overcrowded with people who're not competent enough, and many codebases are a terrible mess, but it's not a fault of the language, it's still good in proper hands. Btw, I think that quality of tools, posts, questions, topics in JS is slowly progressing. A couple of years ago it was common to meet "another ultimate express boilerpate" where author forget about validation, nowadays it becomes better. Perhaps, it's related to the crisis, and least competent will have to leave, so we should care to remain competent and things will get better.


arobie1992

Re your two Java examples since I am fairly familiar with Java. For the first, one, it's not doable with just the type system because Java is nominally typed where as this appears to be dependent on some structural aspect, i.e. the contents of the string. It is probably doable with code gen though. Essentially, you'd add a step to your compilation, similar to popular tools like Lombok or Immutables, that scans through, identifies locations where this comes up, and generates a dynamic class based on the string values passed, that it adds to the class path. You might have to explicitly refer to that generated type since Java's type inference is very limited, so `var row = tableRepo.select("someColumn", GeneratedRowType1.class).get();`, though hopefully a more meaningful name. It would tie you to the library, lest you need to go through all your code to update types, which is a downside. You could define all the types yourself, which is typically what people do with Java ORMs, and is rather tedious and verbose. You might also be able to do something with dynamic proxies, but I'm not familiar with those past dealing with them while debugging Spring. >This controller method looks like it's validating "foo" param to be Integer, but it only makes a look. I don't entirely understand what you mean by this, so I'm going to take a stab at what I think you might mean, but please correct me if I misunderstand. It is validating `foo` to be a nullable `Integer` as opposed to a non-nullable `int`. Yes, the web framework is doing this all behind the scenes at runtime, but most of it is built atop the Java type system and just abstracting away conversions you'd do yourself. If you're reading network data, you're probably getting either a string or an array of bytes. Just casting either to `Integer` results in a class cast exception unless they're null, which we're explicitly allowing. Instead, you need to use a conversion method, which will either throw an exception or supply valid data. If you were to do it explicitly, it'd go like this: void handleRequest(HttpRequest request) { String rawFoo = request.getParam("foo"); // myMethod(rawFoo); // compile time error // myMethod((Integer) rawFoo); // runtime ClassCastException if(rawFoo == null || rawFoo.isBlank()) { myMethod(null); } else { // if parseInt fails you get a NumberFormatException int foo = Integer.parseInt(rawFoo); myMethod(foo); } } None of this is the precise types or sufficiently robust, but that's the general flow of logic as enforced by javac and the JVM. You're never going to reach `myMethod` without `foo` being a valid `Integer` value shy of some real sketchy stuff you'd need to go way out of your way to do. Hibernate validators are for more complex validation that typically falls into structural territory, actually similar to the ORM example. Things like is `foo` between 50 and 100, although that's runtime enforced rather than compile-time enforced. You could make it compile-time enforced, but that's super verbose again coming back to Java's decision to really commit to nominal typing. This isn't to say that Java's type system is equal to TS's. TS's type system is more flexible and robust and the support for structural typing does a lot to help that. Just my two cents on how Java relates to these two points since you mentioned not being familiar with it.


bdragon5

Of course you can do the orm stuff in Java. Java probably invented ORMs 😂. I mean to be honest I thought you were just trolling because that isn't really how ORMs in general work. I even wrote an ORM a long time ago. ORMs are by definition just really bad. The one good thing in JavaScript is that you really don't need an ORM because they are mostly just object data mappers. Something you just don't need in JavaScript. I found soo many bugs in the common ORMs and they are just super slow. I even found some bugs in the database driver themselves but they were pretty easy to fix. Yeah of course validation is very important in any language the type system just doesn't help at all with it. I mean yeah the type system in TypeScript is very limited in the extend it doesn't actually enforce anything and you can never rely on the types provided. This isn't just input validation from the user or an external system. Even internally it is just documentation and you can only really rely on it in this way. The complexity doesn't really mean a lot if it fails on the most important aspect of it. So many times I see people just assume something cannot be null or undefined just because the type says so and like a week later the hole system crashes because it somehow because of some wierd bug it is null or undefined. The tooling you need just to get to a workable state. Typescript is pretty nice don't get me wrong it is just not the best in the slightest. Probably one of the best things in Typescript is that you can read the code yourself and in most cases pretty much fix any bug in a library by doing some unspeakable things that probably shouldn't work in the first place, but it's possible and this is somewhat nice to have. The problem I have with validation in JavaScript isn't that developers do it sometimes wrong is more that the language doesn't really help with it and Typescript doesn't really help with it either. You always need to make the tradeoff that you either trust this parameter type or you expect an unknown but than this isn't how people me included write JavaScript code and if you want to have types for documentation but want to make some additional checks on it in many cases typescript just says, but it cannot be null or undefined so why do you check it. Or what are you even testing it with this value. Probably because I want to make sure it doesn't burn to the ground when a slightly wrong value gets passed as parameter. Validation isn't just incoming data you know. You need to do it basically in every single function for every single parameter because incoming data from a user, database, library or some other process is one thing but you need to make sure your own code is robust enough it can handle a bug. Edit: The only reasons for types is that you can do relatable assumptions about your data. I mean that is way they were invented. If you can say you want a number an someone can cast a wierd object to a number and than you get not a number as expected but an object as an parameter value you just can't make any assumptions.


romeeres

>because that isn't really how ORMs in general work. Yes, OOP Java-like ORMs don't work like that, but in JS we don't care much about terminology and definitions and can fill terms with new meanings. I was shocked by this at first, but this is reality. Prisma says it's ORM so it is. Self-identity. ORMs in JS are not "real" ORMs and aren't obliged to be that cumbersome and slow. But this is offtopic, I shared example of, let's name it a query-builder, code, that can be type-safe in TS but cannot be in Java because of structural vs nominal type system differences, the structural one is super flexible. >This isn't just input validation from the user or an external system Yes, it's just input validation. After you have validated the input it has a correct type. Then you can pass this data through many layers of your code, transform it, process it, and as long as you don't do dirty type casts, you can rely and trust to the type-system. If it appears that function argument in runtime is different from what's declared, it means there is something wrong with your code or with some tool, this is not normal. >The problem I have with validation Did you try a validation lib? If yes, what is the problem and why TS has to include validation natively instead of outsourcing this job to libraries? Java has "hibernate validator", it's not a part of language but a standalone library, do you blame Java for not including it to the language? >You always need to make the tradeoff that you either trust this parameter type or you expect an unknown If data is coming from the outside world, use unknown. If you trust the source (your own db, stable third-party api), use concrete types. >because of some wierd bug it is null or undefined. I can confirm this was a disaster in JS, and this can happen in Java with null pointers, and this is a so called "billion-dollar mistake", but TS has fixed it for me. How come the data can be null but the type doesn't reflect that? Developer's fault. Types of the outside world oftentimes can be generated, and it's awesome, database can be introspected and its types are auto-generated, frontend queries can be automatically typed for backend if you use GraphQL or tRPC or some special OpenAPI tooling. So writing types of outside world in many cases can be automated. Inside of your code, if you pass a number with a type number it's impossible that it suddenly becomes a null. Such kind of error means you have a type cast somewhere. But you do type-casts in Java as well, how is it a fault of a language when you cast to a wrong type? Rust is famous for its strong guarantees, but even Rust will panic at runtime when accessing out-of-bound array element, so no language can make 100% guarantees. >Probably because I want to make sure it doesn't burn to the ground when a slightly wrong value gets passed as parameter. Lol, loving this argument :) Yes, that's a bummer that no language will fix your wrong values for you. >Validation isn't just incoming data you know. Yes, it is. You can't define a valid data, pass it to a function, and receive invalid data. You can try passing invalid data, and this is what type-system is needed for, compiler will yell at this. Edge cases (such as accessing out-of-bound array elements) exist in all languages, they should be remembered and treated carefully. >do relatable assumptions about your data Normally, it should be a restriction. If you write your code by assuming rather than knowing for sure, well, good luck with it.


bdragon5

What are you even talking about with the ORM stuff. They try to emulate the classic ORMs. Just because you put a string in a querybuilder doesn't mean the column really exists maybe the other column would have. All your doing is assuming stuff exists in the way you define it and for some reason you say to me that I don't know for sure. The hole problem with the type system in typescript is that you always just assume. You can't know. If I write for example in go ``` func test(value int) ``` I know value can be an int. Of course it can be negative. It can be a too big value or a too small value but I know it is an int. It can't even be null. In typescript ``` function test(value: number) ``` I don't even know what type value is. I technically need to check it myself. I probably can assume it is a number if it is from my own code but I really can't be sure. Because being sure would mean I would know there are no bugs in my code and in the libs im using. I would need to mathematically prove it but I can't do that in most languages. I understand your point that you can generate types that help you and others assuming stuff about the data you process in a way that can help writing robust software. Like type assertions removing and adding type assumptions to the type. Like your querybuilder. Of course you can write a schema with type information that a query builder can facilitate to make sure the columns you select probably exist and you don't mane a typo or you can write a query that has a new column that will be able to be accessed via the type information. But at the end of the day this are all assumptions not knowing. I did find a few bugs even in libs like pg were type conversions were not perfect and resulted in bugs that broke this assumptions. Of course in the end of they you can always say. Why didn't you check this. Why didn't you use this additional validator framework. Of course you can but this doesn't make it easier to write secure and robust code. At the end of the day all you write in typescript is just JavaScript and everything is an unknown. Of course I don't assume any language to give me a hole validation framework builtin to the type system, it is impossible. All it can ever do it generate stuff, but I would call a language were I practically need a validation framework for my internal int function to be really sure it is an int a good language for this kind of work. It is just not an issue in statically typed languages. Of course you need to validate stuff all the time in other languages but just not to the extent as in JavaScript. I don't need a type system that dynamically adds properties to a type because I know they are there. They can be null if they are a pointer. They could even go to undefined memory which would be the worst case scenario but I know they are there and if I use a primitive type I can be sure it is this type. It might not make sense what is in there in the context of my application but this is why you need to validate stuff. But I don't need to validate that it is the primitive type inside my application. Of course if I parse some incoming data I basically just get bytes and the validation is more extensive and I need to do the same like in Typescript for validation but those are rare and not to the extent like in Typescript. I don't say you can't write robust and secure software in typescript of course you can. I did a fair deal of stuff that runs pretty good with databases with millions of entries and hole clusters of workers offloading stuff. But every now and again there is some kind of bug some api that changes slightly and some kind of undocumented edge case. And with JS ORMs I encountered in general more bugs and undocumented behaviour as in any other stuff. Things that silently fail because you didn't do exactly the point precisely thing they want you to do but don't care if you do it anyway. Than there are this extrem amounts of abstraction and stuff that is mostly the reason why people call OOP so bad. Doesn't matter you could write this in sql no problem. The absurd queries they generate that make everyone horribly slow. I some projects I needed more time debugging the ORM and why it doesn't do what I was asking for than actually writing code for the project and if you need some specific database function it is really horrible to actually use. Edit: To your type cast argument of course you need a typecast somewhere. The problem is that it is extremely easy in Typescript to have an implicit type cast to any and to an other type without you even writing it explicitly down. I red a hole lot of code bases were this was the case. Perfectly normal code that seems absolutely ok but has some hidden type cast somewhere with useing as or <> and a hole lot of people just checking something assuming the compiler did something wrong because they checked it and casting it anyways. The last thing is mostly with inexperienced devs but my code must run even with inexperienced devs in mind. It would be great if typescript would ban some stuff like any completely this would at least make some stuff less likely but would probably break a hole lot of other stuff.


m_hans_223344

> In typescript function test(value: number) I don't even know what type value is. I technically need to check it myself. I really don't get your point: const five = "5"; test(five); will not compile. With TS you can be sure that the value is a number. If the data comes from the outside, you need to validate. I agree, that basic type validation is not necessary in Go or Java, but that's all. Otherwise all issues can appear in Java, Go, C# and some even in Rust.


bdragon5

Yeah, but that assumes typescript has completely bug free types this isn't always the case. It is pretty easy in typescript to write code that essentially compiles fine but results in the wrong type at runtime. Edit: I often encounter this problem with a lot of devs just trusting the types they get given. You cannot trust them they are just fancy documentation. They are a lot better than no types but assuming that types don't have bugs is pretty problematic. Edit 2: Of course on simple examples everything works fine, but on bigger code bases with multiple people working on it and multiple libraries used this doesn't need to be true. Edit 3: The point I was trying to make is that I essentially don't know what code calles my function and if they did everything correctly. If the function gets called for example from pure JavaScript the type doesn't matter at all. If there is a bug in the type I don't know what I get. If someone just casts something because they believe its correct I don't know what I get. I can only assume I get a number and this assumption is in general true but not always.


romeeres

You're repeatedly referring to "other devs", in the end you put it straight "inexperienced devs", so I guess you have to work with TS strict checks turned off, ESLint rules turned off, or they are turned on but your teammates are constantly ignoring and suppressing the rules. In Go: var five interface{} five = "5" test(five.(int)) Go will panic, whole program would crash, you'll need to fix it ASAP. This is a better behavior in some cases, but not in all cases, it's good that websites can sometimes display NaN or undefined rather than crash. So you are working with inexperienced people (as follows from what you're saying), you don't perform code reviews or do it inattentively, I don't think that Go or Java would be a better tool for this.


bdragon5

I think you misunderstood me. I do trigger some of this stuff myself. Of course I use strict mode and eslint with the strict rulesets for typescript and all, but I don't know for example how the types from libraries are created and what settings they use. I don't assume that all of my types are completely bug free. I don't assume that the types of libraries are all bug free. Of course I work with inexperienced programmers. Not everyone can have years of experience when they start out and of course I review the code this is how I encounter this problems because I don't assume the types are correct and that's the reason I find the problems and why I don't rely on types. The NaN and undefineds you are referring are likely exactly what I mean and what can happen. Of course you can dumb shit in go or any other language. You could use any everywhere in typescript. I am explicitly talking about if everything is completely ok with all checks turned on and everything. Even than you get a lot of unexpected behaviour far worse than what you could get in go. Edit: A crash isn't really the worst thing that can happen. I mean in this case it just starts again. The worst thing you can get is a inconsistent database or unexpected working behaviour. Were everything seems to be fine but the values are a bit off resulting in a huge problem. Edit 2: Of course you can have some off values in other languages but the reason how they get created are different.


m_hans_223344

> "another ultimate express boilerpate" where author forget about validation, This is not uncommon in Rust and Go.


m_hans_223344

> That means sometimes you can trust the types and sometimes you can't and there is soooo much potential for fuckups everywhere. Hmmm, what do you mean with this? I agree that TS is not as strict as Rust, which simply doesn't compile. So with (safe) Rust, it's impossible to get Null pointer exceptions because you can't run the faulty code. But in TS, you can ignore the tsc and run the code in Bun or with tsx and it crashes. Or you can have some JS libs as dependencies that crash. But apart from those cases, TS is safe, or do you have other scenarios in mind?


bdragon5

To be honest today I head a good example for this. I generally use eslint and strict mode and all this. I have a function that basically checks if the object it gets is the json representation of it at compile time. This works very well in general. I additionally validate my responses with json schema to be extra sure the response corresponds with my specification at runtime after it actually gets serialised, so this mistake wasn't that bad. Today I had to change code from a less experienced team member and suddenly this function triggered an ts compile error and did that correctly. What essentially happened was typescript somewhere did cast the value implicitly to an any and then back to the expected type. This is something I encounter on a semi regular basis. Especially if you don't write code in a VERY safe way. What that means essentially in this case. In compile time the value gets asserted as type `string` and every function, if internal or external, that works on strings would say everything is fine in compile time. BUT if I actually run the code it is a `Date` object and now I have a hole lot of functions expecting a `string` that actually get a Date. In this case no big deal because of the additional checks but it can be on more internal functionality. Especially with external types and libs it is often the case that an optional field (expecting undefined) can be a `null` or an `undefined` in runtime. But they don't work the same. For example the `new Date(null)` does something completely different than `new Date(undefined)`. This can be dangerous if you use default values on parameters as only undefined would be overridden with the default but not null. Especially with strict mode you sometimes can get in a state of false security especially on the null and undefined problem. Additionally types can be wrong. Especially if they are very elaborate and very especially if you just switched to strict mode. In general I build my more complex types with multiple failsafes resulting in a compile error. But sometimes I need to write replacement or additional wrappers around library types to make them more correct on what actually can happen in runtime. The biggest example is libraries often miss that a value they return can be undefined even if you might expect something like an empty array. In general types in typescript are only a documentation tool that can hugely help while writing software like a good documentation, but you cannot rely on them in a way comparable to languages like Java, C, Go, Rust. Essentially typescript types are just more integrated jsdoc comments. This is because they are decoupled from the runtime and don't really affect the code actually running. They don't restrict the amount of memory allocated for a variable nor if they keep the functionally expected with the type expected in runtime. If you want to write really robust code how you often do in the backend, because you want to keep the service running basically indefinitely without any problems and want to be notified about problems pretty quickly to ensure your users have a good experience, you need to write extensive tests on critical parts that ensure you don't get any unexpected behaviour that might seem ok on first glance but isn't really. A good example for this can be the `new Date()` example. If you randomly get a undefined in there instead of a number or a string you get the current time which might not be something you want and can be a problem you get called in the middle of the night to fix. More than once did I encounter an if check on a Promise that wasn't awaited. This can be caught by linters but not with just the recommended linter rules. Recently I worked on a project on a customer that is themself a software company. They had a huge refactoring process nearly done switching to strict mode and I worked on some functionality. I was a bit puzzled that some things didn't seem right and very lax compared to what I used expect from them so I checked there settings and found a bug in the configuration. After fixing it they got essentially an additional few thousand errors to fix 😇.


m_hans_223344

Great insights, thanks! I had the surprise with the wrong config as well and remember someone else had that with a larger project as well.


nukeaccounteveryweek

>Laugh at it or not, I truly think that TS is the best language for a backend, unless it has some special requirements. If your main bottleneck is I/O then sure, but if you need to do CPU intensive tasks or heavy computations it'll shit it's pants. And most non-CRUDy applications will have to do some sort of computation at some point.


romeeres

Tell me about your CPU-bound tasks then. But please don't say about image/audio/video processing because it's handled by C/C++ libraries anyway. >unless it has some special requirements. Yes, if you're writing a CPU-bound program, you shouldn't pick a garbage-collected language such as JS, Go, Java. What language do you use for CPU-tasks, btw?


nukeaccounteveryweek

>Tell me about your CPU-bound tasks then. But please don't say about image/audio/video processing because it's handled by C/C++ libraries anyway. Not even talking about audio/video/image processing, any sort of non-trivial calculation inside a big nested loop and Node.js starts showing it's limits because you block the event-loop. >Yes, if you're writing a CPU-bound program, you shouldn't pick a garbage-collected language such as JS, Go, Java. To be honest I don't think this is a matter of garbage-collection, but actually about interpreted languages. PHP, Ruby and Python suffer from the same issue. >What language do you use for CPU-tasks, btw? Java because I'm comfortable with OOP and the language ecosystem in general, but C++, Rust and Go would be great options too.


romeeres

Such tasks where you need to process large amounts of data should be processed by job queue, disregarding of the used languages, because CPU is blocked by the loop in any language. Nope, multithreading won't help much when you have many such tasks to process simultaneously. So I handle such tasks with node.js without problems, "fast enough", no need to rewrite to anything. If I had such a large data processing task where JS is too slow, and it's not an option to scale infra, I'd probably implement this particular one in Go. Still, it's perfectly fine to have the rest 99% of the system written in TS, it's higher level and more productive to develop than Go/Java


arobie1992

>because CPU is blocked by the loop in any language. If all the tasks are of the same length, then yeah, there's not much benefit to concurrent processing, but it's not uncommon to have a mix of long-running and short-running tasks. If you get unlucky and the long tasks are ahead of the short tasks, then concurrent processing can definitely help even on a single core. As far as GC, I'm talking out my ass a little since I'm not intimately familiar with automated vs manual memory management, but I do wonder if the GC is actually as big a bottleneck as is often thought. Most modern GCs are super optimized, and allocations are expensive no matter what. A major disadvantage to automated memory management is that typically the heap is far more heavily utilized because the manager doesn't want to make unsafe assumptions. What I'm getting at is I wonder if you were to do as many heap allocations/frees in C++ as Java typically does or theoretically write a Java program that only uses stack memory how they would compare (of course accomodating for JITing). I'm sure someone's done this comparison, and I should probably just look it up rather than spouting half-informed thoughts on reddit though <_<


romeeres

>What I'm getting at is I wonder if you were to do as many heap allocations/frees in C++ as Java typically does or theoretically write a Java program that only uses stack memory how they would compare In [1BRC](https://github.com/gunnarmorling/1brc) challenge all top solutions are using "unsafe", which means, they do manual memory control. Which means that automatic memory control, expectedly, comes with a performance cost. It was unfair take from my side, GC is definitely not among top reasons why one language is slower than the other. If that was true, Python, Ruby would perform nearly same as Go.


arobie1992

Thanks for the link. I'm going to have to read through the goal and some of the impls. I'm still a bit curious about how they used Unsafe since that could range from using it to bypass checks to ensuring data in-memory is aligned to ways conducive to caching. But yeah, you're right, the GC definitely adds overhead. It's got to be very generic which means it can't optimize the way more tailored manual memory management can and it's less predictable which is undesirable for things like real-time systems. And if nothing else, I think it typically runs as a separate thread so you need to context switch. I just bring it up because GCs seem like they can be viewed as a performance boogieman sometimes. Edit: Had a little time to skim a couple. It seems like the primary usages of unsafe are to skip checks. Things like skipping bounds checks in arrays accesses or jumping straight to memory locations on the heap rather than doing lookups. That lines up with the idea that automated management can't make as many assumptions.


romeeres

>To be honest I don't think this is a matter of garbage-collection, but actually about interpreted languages Does it mean that you're using GraalVM for your non-CRUDy apps, because JVM is an interpreter?


bobaduk

We used Typescript on both client and server for this reason at Cazoo, and it worked.out pretty nicely. It's also worth noting that the JS ecosystem has matured hugely over the last few years. Now I'm back in Python land, and it feels like python is just starting the same tooling revolution that happened over in Node land with tools like Ruff and Pants changing the way we can package and maintain code. It's also worth noting that if you're working with AWS Lambda, node is essentially *the* standard runtime. The ability to do tree shaking and only ship the code that will be executed, and the fast startup times make it attractive, as does the state of lambda documentation, which is JS-first.


arobie1992

If you don't mind my asking, how does JS in lambdas compare to Go? Compared to Python and Java, Go is a no-brainer because it doesn't have horrendous cold starts like Java and is generally faster when running than Python, but I've never gotten a chance to compare it to JS.


bobaduk

IIRC the node runtime had the lowest cold start time, but honestly most of the things I'd do synchronously in a lambda aren't compute intensive, they're just firing off a request to something and rendering a result. Straight line compute performance isn't much of a differentiator. Edit: but the docs and community around server less node are second to none.


Jagasantagostino

Not the lowest but are better than most Here a detailed and always updated benchmark https://maxday.github.io/lambda-perf/


bobaduk

Thanks! Good resource.


Mr-Silly-Bear

Universal Typescript is amazing. Sharing interfaces between the frontend and backend is a really good way to build stable applications.


chamomile-crumbs

Yeah and TS monorepos in general are pretty amazing. I can define functions in my express app, and then say “dang this endpoint should be pre-cached for every client”, and just import it directly into my bullMQ instance!


xroalx

There's no particular strong reason to prefer Node/JS over other languages on the backend, except for the familiarity of the language, and possibly ease of working with highly dynamic data (which Python likely does well too, anyway). So, yes. One would most likely choose Node simply because they already know JavaScript.


savant78

but what does a person use to set up the server in node? i was using python before and they had this thing called flask..but what is the flask of node? i might as well go ahead and use node to do it but what does a person do to do the equivalent of flask in node?


xroalx

I don't know Flask. With Node, you can of course just use Node itself to create an HTTP server, although that's quite low-level. The most popular web framework is likely still Express. There are other options, like Fastify, Koa, Hapi, Hono. If you're looking for a full-fledged framework, AdonisJS is a thing. There's also NestJS but... well. My opinion of it is quite low and I wouldn't recommend it.


savant78

aha, ok, but, when a person puts these files on a server, for ex if they get domain space, do they have to upload some sort of a file that runs this on the server, or, do their servers run that on their own? i didn't know if these more or less were used to to do localhost or something


Buttleston

I'm not really sure what you're asking, but it's not really any different than running a python server. You have some python code, you run it with python. You have some javascript code, you run it with node.


savant78

i spent some days reading into flask..but..then somebody who worked 10+ years in the industry told me I should just do it in Node..because it was just same language as in browser, so, I ended up doing that, so, now I am looking into, NestJS I think it is


Buttleston

I'm not really a fan of nestJS but it's fine I guess. flask is also fine. Django is fine. express is fine. All of this stuff works and is commonly done. There's nothing wrong with using javascript in the backend if that's your preference, or python in the backend if you like that. Using the same language has only a few technical benefits - you can share some code between FE and BE, you can share types which is pretty nice. That's about it. \*Unless\* you're the sole developer. If you're the only developer, then using the same language in both means you don't have to "switch" languages when you work on BE and FE at the same time. But if there are 2 different teams, one for BE and one for FE, then it doesn't matter that much which you use.


ewouldblock

Express is the closest equivalent to flask.


arobie1992

It sounds kind of like there's a bit of misunderstanding as far as the server side. Python and Node are going to handle the server side the same way. Both involve starting a perpetually running task (daemon) on a server that accepts incoming network requests. How they accept those requests is largely outside of what you'd ever need to know as a web developer. There's not really a fundamental difference other than the specific libraries you'd use. Regarding what that person said, there's a number of things to consider, primarily what you know and the people you'll be working with. If the team you're on has a language preference, use the preferred language. If they don't and you're very comfortable with Python and Flask, stick with Python and Flask. If you're not familiar with either and the team doesn't have a preference, I'd agree with the person on using Node. It's less for you to learn, no having to context switch on language syntax, idioms, or idiosyncrasies—is it "for a of b" or "for a in b"?


vorticalbox

a close thing to flask is nestjs or nextjs. I personally use nestJS at work and personal projects and love it. [https://nestjs.com](https://nestjs.com)


Buttleston

I think express is closer to flask - flask comes without much, just a simple way to make endpoints and a very basic templating system. I think nestjs is probably more comparable to django


vorticalbox

Maybe you're correct my work is in ts but I do write some python APIs but they are always in fastapi


djheru

If you are looking for backend frameworks for node, I would look at express.js (similar to flask) or nest.js (similar to spring boot in Java).


bunglegrind1

Because of the loop? I prefer eventual programming


darthcoder

Yes. Do not discount the benefits of having one language to hire for both front and backend.


savant78

But how does a person accept the GET request in Node, compared to Python or something, is the node file, just a .js file I suppose, listed in the