Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
The melting pot of JavaScript (2017) (increment.com)
153 points by lewisflude on Jan 7, 2019 | hide | past | favorite | 194 comments


I really like the kind of sanity that TypeScript brings to JS, super well designed and usually a pleasure to work with. That said, I've worked in many languages and I can't see any reason you would willing write your backend in JS or TypeScript.

Java, C#, Rails, and to some extent Python are much saner choices. The massive churn of the JS ecosystem bleeds through to the backend, hard.

JS could use a little more of the cruft and process that makes Java and C# especially so "uninteresting".

Java especially is kind of a joy to work in if you ignore the cruft. Everything is generally well documented, the libraries are mostly very solid, code is almost always backwards compatible, there isn't a zillion ways to do everything, frameworks tend to live for a decade or so.

And it's faster than JS, and uses way less memory, and mostly solved dependency hell and bloat over a decade ago.

Java feels like it was designed, not grown. Everything follows similar convention so it's easy to pick up new libraries. The advantages are many. The drawbacks are few as long as you use things like Lombok and code generation liberally. By the way; code generation using agents, annotation processors, and bytecode manipulation is pretty much standard and a godsend for doing interesting things (and getting around the cruft) .

In java, I can write code on the fly at runtime, or even during compile time using standard tools. Js barely even supports reflection. This is a huge underrated shortcoming of js if you're doing anything complicated


> Js barely even supports reflection. This is a huge underrated shortcoming of js if you're doing anything complicated

Can you explain what Java offers with regard to reflection that JS doesn't?

My feeling is that reflection is almost moot in JS since you can inspect/mutate objects at runtime however you like. But maybe I'm missing the point of reflection.

There is a Reflect object with a bunch of static methods on it in ES6. It mostly just replicates functonality that already exists in the language, and my suspicion is that it's mainly there so it can be extended at a later date without breaking backwards compatiblity.


> Can you explain what Java offers with regard to reflection that JS doesn't?

Among hundreds of other things, getting the return type of a method and getting the input parameter names (+ types) in a way that doesn't revolve around literally parsing the functions toString() representation.

Oh, and typeof checking that isn't disgustingly broken.


> getting the return type of a method and getting the input parameter names (+ types)

Type information literally doesn't exist at runtime, though. Isn't it kind of ridiculous to compare languages like that?


When you're comparing the relative power of reflection within the language, absolutely not.


But what would you use that information for, given that the language has no types? A JS function has no guarantees of what type a function returns anyway. It's like taking issue with the fact that a car doesn't come equipped with skis.


It's like taking issue with the fact that a car doesn't come equipped with skis.

To draw out that analogy... we live in Greenland. Cars with skis are surprisingly useful.


> Type information literally doesn't exist at runtime, though.

Correct if I'm wrong, not all types get erased in Java. Doesn't type erasure only happen for generics? Say I have a non generic, plain Java class and want to inspect one of it's method's return types at runtime to see if it returns class A or class B. I can do that, right?


Yes, you are correct. There are also a number of circumstances in which you can get generic type info - it isn't erased, for example, if you create a concrete subclass of a generic type.


I was talking about JavaScript. In JavaScript there are no typed functions or arguments, so that information doesn't exist period.


Right, so I guess I'm not understanding your point about why comparing two languages like this is ridiculous. Java has a full blown runtime reflection system (it's "types exist at runtime"). JS doesn't. So Java wins in the reflection category.


But in JS, reflection is pretty much not needed... I don't need to use reflection to see if an object has a quack method, or that I call it with the right types... I just call instance.quack() ... It's up to you as the developer to keep your interfaces and composition in line.

It's actually WAY easier than with C# or Java. Since the use-case of reflection itself is largely unnecessary.


Calling a method and seeing what happens is not a substitute for reflection. You can do that in Java too btw.


> Among hundreds of other things, getting the return type of a method and getting the input parameter names (+ types) in a way that doesn't revolve around literally parsing the functions toString() representation.

Ah, that's quite cool.


You can do almost anything with Java reflection, JS really pales in comparison.

Which in some ways is a good thing as you can do a lot more optimizations.


Typeof is a good one, but holy crap I had no idea return type and param support was that horrific


Java uses reflection and annotations to support all kinds of language extensions. Js has a lot of nasty issues with the "prototype chain" and annotation support is still experimental. For example, in java, scanning your classes and their annotations to generate code for them at compile time is a standardized feature.

Maybe I'm just complaining that JS is too dynamic, but being able to generate code at compile time with reflection and know it will generally work (type checked) is nice.


Do you have any concrete example for "For example, in java, scanning your classes and their annotations to generate code for them at compile time is a standardized feature"?

Tip: in JS, I don't want OOP class. If you really want class, could you show me the intention behind it?


In general this what java annotation processors are all about. As a specific example, Dagger, a compile time, type safe dependency injection framework. https://google.github.io/dagger/


Java only works in classes :) . They're actually the compilation unit as well so no way around it. (Files are compiled a .class file at a time from single source files)

Adding another example, JPA MetaModel generator that allows you to make strongly typed calls in ORM.

Basically, it let's you generate code at compile time that's seamlessly integrated into the existing code. So it's generated code that still gives you IDE autocomplete support etc.


Every popular ORM uses reflection to determine how to map fields to columns. For example, what type of date or money object to use.

I automagically map some postgres JSONB columns to a parsed object form. Looks just like a regular typed nested object.


That's a solution looking for a problem in JS. You're thinking in types instead of in terms of a dynamic language.

You basically HAVE to do this in Java otherwise your program won't work. In JS, you can look everything over at runtime and dispatch from there (made much easier because first-class functions and closures are a thing).


you can look everything over at runtime

Correct, that's what you have to do in dynamic languages - look at what came in from the database and manually validate+convert it into the format you actually want. Also with pretty much every other form of input (JSON bodies, form posts, queue messages, etc). It's a lot of tedium.

When working with node/python/ruby, I often find myself wishing I could just declare a type and be assured that "the system" will get it right instead of me having to code it out myself. You know, like Java.

Well-written Java programs are generally more concise and less verbose than well-written JS/Python/Ruby programs. Which is to say, when programmers actually validate input instead of (ahem node) crashing the process and dropping all inflight connections when someone submits a json body missing an expected field.

BTW absolutely nothing prevents you from building Java apps by declaring everything as Map<String, Object>. Nobody does that because it's a horrible way to program.


> Well-written Java programs are generally more concise and less verbose than well-written JS/Python/Ruby programs.

This isn't at all true. I can say this from experience using statically typed Python extensively, in an average code base, 80% of your functions, if not more, are already statically correct in Python, one just need add an annotation. Then you're just as "well written" as the Java.

With or without the annotations, the code is still just as "correct".

> BTW absolutely nothing prevents you from building Java apps by declaring everything as Map<String, Object>. Nobody does that because it's a horrible way to program

Yes, but only because you'd need to explicitly cast things everywhere and write out declarations everywhere. If you could always elide casts and type defs, it becomes a lot less horrible.

> Correct, that's what you have to do in dynamic languages - look at what came in from the database and manually validate+convert it into the format you actually want.

You still have to do this in static languages. Maybe a library does it for you, and it gives your an error or something you know is a DbRecordFieldStream or whatever, but dynamic languages can do the same thing. Orms validate input in dynamic languages too. Rails and Django can validate request formats. Protobufs work in every language.


> This isn't at all true.

Well I guess we'll just have to disagree there. I spend a lot of time writing code in all of these languages. By the time you've bulletproofed your dynamic code, you've got more code than if you'd just declared a simple static Java type.

I can define this...

    @Data
    public class Thing {
        final String text;
        final Instant when;
    }

    @Path("/thing")
    public class ThingResource {
        @POST
        public void doSomething(final Thing thing) {
            // ...blah
        }
    }
...and stop worrying in my implementation about what was actually passed in, or how a JSON string date got turned into a real date representation. This is mostly-vanilla Java.

Sure you can, with enough extra code and clever libraries, hack together a crude typing system into dynamic languages to automate much of the conversion. At the end of the day you're still declaring types, and it doesn't end up being as elegant as having the type system built into the language.


> This is vanilla Java.

No, its Java EE, which like I said, has an entire library devoted to safe marshalling[1]. Marshmallow does the same thing for you in python. Java EE including a marshalling library has nothing to do with static typing.

This is python + flask + marshmallow (2 very common web libraries)+ a 2 line helper function:

    @dataclass
    class Thing():
        text: str
        when: datetime.datetime

    @app.route('/thing', methods=['POST'])
    def handle():
        thing = unmarshall(Thing, request.form)
        # blah
Or, like I said, use protos, where this would be something like

    from thingproto import Thing, ThingService, ThingResponse

    class ThingServiceHandler(ThingService):
        def HandleThing(request: Thing, response: ThingResponse):
            # blah
and everything is validated.

[1]: https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-...


I'm not quite sure what you're getting at with the "No, it's Java EE" comment. JAX-RS is a Java standard, with several implementations, and you don't need a "Java EE Server" or anything magical like that to use it. And that link to the Custom Marshalling section of the JAX-RS docs is a little weird; my example doesn't require monkeying with low-level stuff like that and most users don't.

Dragging protobufs into this is weird too; you've ignored the IDL and build infrastructure required to set that up, and in any case that's specific to when you're working with protobuf APIs.

I'll go back to my earlier point, which I think you've illustrated fairly well, which is that well-written Java code tends to be more concise and less verbose than Python (and friends). Our two examples are nearly identical in terms of meaningful lines of code, but in the Python example you have to ask for marshaling.

I'll also point out that flask (which I use myself for python webapps) handlers are forced to interact with flask-specific objects and therefore are obnoxious to test; the JAX-RS example is pure program logic and can be tested as vanilla Java code. This is one of the big advantages of moving marshaling "out" of your program code.


>I'll go back to my earlier point, which I think you've illustrated fairly well, which is that well-written Java code tends to be more concise and less verbose than Python (and friends). Our two examples are nearly identical in terms of meaningful lines of code, but in the Python example you have to ask for marshaling.

That's only an API wart. It'd be possible to elide that pretty easily if someone wanted to write a library to do that.

I could write a library function or flask extension or whatnot that resulted in

    @app.myroute('thing', method=['POST')
    def handle(thing: Thing):
        # work with thing
and the unmarshalling is handled by the decorator and type annotation. Your prime example of java being less verbose is a wash. They're at best equally verbose, and you picked something that java has libraries specifically catered toward.

>I'll also point out that flask (which I use myself for python webapps) handlers are forced to interact with flask-specific objects and therefore are obnoxious to test

Huh? Here's an example of a test from the flask docs[0] that makes a request and checks the result.

    def test_empty_db(client):
        rv = client.get('/')
        assert b'No entries here so far' in rv.data
Its a simple example, but having written tests for flask myself

1. There should be minimal logic in the handler. You should defer most logic to a library function, you can also not use the decorator form and instead declare `app.route('/path')(function)` and just test function itself.

2. Even testing the handlers and doing end to end stuff with a running server isn't that hard. I'm not sure what you're experience was, but my guess is you weren't leveraging existing libraries.

>This is one of the big advantages of moving marshaling "out" of your program code.

Here's the implementation of that:

    def myroute(self, *args, **kwargs):
        def wrapper(f):
            @self.route(*args, **kwargs) 
            def new_route(*args):
                arg, schema  = f.__annotations__.items()
                parsed = schema.load(request.form)
                return f(arg=parsed)
            return new_route
         return wrapper
And now if you've tested that, you no longer need to worry about marshalling in your program code.

Flask however is relatively generic, it can handle things that your java examples can't, like an endpoint where you don't know the schema, which might happen if you're doing something like hosting a user-provided function or something of that nature (I implemented an AWS-lambda style thing in a hackathon with that). Something like

    @route('/user_endpoint')
    def handle():
        return convert_to_html_response(user_function(**request.form))
This was really easy to implement. I doubt it would have been as concise in Java (and note that you are leaving validation to the user here, so none needs to be done by you).

Flask lets you do that. If you want to restrict yourself to schematized requests, you have more information and can make more assumptions, but flask isn't a REST framework, its a generic web framework. If you want to restrict yourself to something with known schemas, you can do that pretty concisely[1], even when dealing with relatively complex marshalling (and you can do it outside of your logical code under test via decorators).

[0]: http://flask.pocoo.org/docs/1.0/testing/

[1]: https://flask-restful.readthedocs.io/en/0.3.6/fields.html


The Java equivalent of your example is probably:

    @POST
    public void doSomething(final Map<String, Object> thing) { ... }
So please stop trying to explain to me all the things that Java can't do concisely.

Also you kinda missed my point about unit tests. Your test requires specialized flask-oriented objects (client, rv). Tests of the Java doSomething() can be written entirely without knowledge of the container; doSomething() is pure program logic. And the methods support refactoring.

you picked something that java has libraries specifically catered toward

I picked a basic REST service. I'd call that a pretty common use case.

There should be minimal logic in the handler. You should defer most logic to a library function

Again illustrating my point that well-written Java is more concise. You don't need to do this! The Java "handlers" I've shown are pure logic. There is no point in wrapping it with another layer.

Sure, you probably could build a webapp framework that makes Python a lot more like Java. But so far nobody's done that. So Python programmers write wordy verbose flask apps with tons of validation and marshaling logic. It's tragic.


> The Java equivalent of your example is probably

More verbose than the Python.

>Sure, you probably could build a webapp framework that makes Python a lot more like Java

Not could, did. Literally just did, in 10 lines of code. Or there's flask-rest, which I linked.

>Again illustrating my point that well-written Java is more concise. You don't need to do this! The Java "handlers" I've shown are pure logic.

And flask-rest does that! If you're writing a restful service the more concise, better specialized tooling is readily available.

Now write the unmarshalling code and tell me Java is still more concise.


Why do I need to manually convert anything? Even then...

    var results = (await sql.query`
      ...
    `).recordsets[0].map(rowToObject);
It's really easy... no need for complicated ORM/ODM tooling at all.

As far as the size... create a docker container from node:10-alpine to run a given node application, and create a similar container with any application running full Java. And compare the final size.


Did a date column get mapped to Date, moment, date-fns, luxon, or any of the dozen other choices that your shop might standardize on?

I've never heard anyone server-side care about the size of a deployable. It's the size of the codebase that's an issue. Tedious conversion code does not work in javascript's favor.


You should have a look at typeorm [1]. Typescript ORM with decorator support.

1: http://typeorm.io/


That's cool, and will keep it in mind for the next time I work on a node project.

Looks like it works by having the typescript compiler generate experimental annotations in the output javascript, and reading it using a polyfill for the proposed ES7 reflection api. On one hand, yeay looks like proper runtime reflection is coming! On the other hand, it doesn't sound fully baked yet... <insert here a general grumble about how everything in the JS ecosystem is in this state>


Retrofit is another example: https://square.github.io/retrofit/


http://immutables.github.io/ makes great use of this feature in Java


One example would be a url router for a web server that turns the url variables into the handler's expected argument type and ignores requests that do not.

    router.get('/users/:id', (id: UUID) => ...)
    router.get('/products/:id', (id: Int) => ...)


That would be relatively easy to do something very similar with middleware for express/koa

    router.get('/users/:id'. skipNonUuid(id => ...))
You simply have a function/middleware that does the check.... or `compose(skipNonUuid, dbo.findUserById, ui.formatView('modelName'))`

You can do function composition that is nearly as simple and far more flexible in general with JS


Just to be clear, Reflect exists to be direct interface to JS's Module Object Protocol (MOP). Every "primitive" operation you can perform on an object in js, (such as adding a property or getting the value of a property), is exposed via Reflect.


There's no easy way to inspect the runtime in js to find all functions or all classes that can be loaded/called.

There's no way to hook into the loading of modules in a standard way - you have to know how the modules are compiled and required.


> Can you explain what Java offers with regard to reflection that JS doesn't?

One thing comes to mind, how to twinkle stuff inside closures?


Sympathies to your valid concerns ...

Though Java was 'designed', it was not 'designed' to be an http/web server.

JS, particularly Node.js has really adapted itself to that well.

And one small but massive difference: JSON is how data is passed and it fits seamlessly into Javascript, and doing JSON in Java is an ugly, ugly thing.

As soon as you compare not JS/Java, but Java/Tomcat vs. JS/NodeJS - then you get a different comparison.

I quite like using Typescript on Node.js over Java - development speed is faster, and this is a really important thing.


JSON is how some data is passed today. It's certainly not the best way and might go out of style just like XML did a while ago.


It is already on its way out, thanks to gRPC and need for performance instead of parsing text all the time.

It is only a matter of browsers getting native support for gRPC.


It's available now! Yay! [1]

With gPRC there's still a lot of binding code, and you need to map all of that in Java, but you do get some validation etc. out of it. It does make the 'data transfer' comparison a little less harsh.

[1] https://github.com/grpc/grpc-web


Not really, I meant as browser builtin API, implemented in native code.


No, that's not on the roadmap and I doubt it ever will be.

It's a very specific technology, and as long as it can be implemented fairly efficiently 'up the stack' in JS, then it mostly belongs there. Aside from HTTP2 (which is a roadblock now, but not soon) it'll be fine in JS.


I was reading something on HN recently and I ended up on this wiki article.

https://en.wikipedia.org/wiki/Billion_laughs_attack

It got me thinking about it. JSON is annoyingly simple at times, yes. But that also protects it from some pretty gnarly stuff seen in XML and YAML. I suspect it's a considerable contributor as to why it's the choice transport format.

I wouldn't toss it in with XML just yet.


> doing JSON in Java is an ugly, ugly thing

Why do you think so? Jackson and Gson work very well. Serialising and deserialising from/to POJO/JSON is trivial with them.


JSON and Javascript data objects are essentially directly interchangeable.

In Java, you have to abstract the document and write a lot of code to access, add, remove things etc. - or - because there is no such thing as an untyped POJO in java, you have to set up a ton of things if you want to use real objects.


Instead of using a typed POJO you can deserialize/serialize a Map<String, Object>.

You could also use a POJO for the fields you know and put a map inside for the fields you don't know.

If that's not enough you can use JsonNode, or ObjectNode where you can freely add and remove json values.


Ok, touché, good point.


I actually like gRPC better than JSON these days so it saves me from that pain, code just gets generated for you.

But yeah json is much nicer in JS generally


JS or anything that compiles well to JS has a backend advantage that can be hard to beat for an early stage startup and that is reducing the amount of context switching you have to do in changing between languages (especially if your code is isomorphic).

At least, that is how I find it, my productivity shoots up when I don't have to be moving between two imperative languages that most likely share a lot of their syntactical DNA with C but each have their own fun little differences.


This advantage is further multiplied with TypeScript, since you can easily share types between backend and frontend. Working with a single set of types that enforce contracts (and supply IDE autocompletion) across the entire stack is amazing. It provides a huge productivity boost and eliminates a whole class of extremely common bugs.


I find it's not an issue as long as you're using a decent "object shipping" layer like gRPC. Really greases up the transition point between different languages.

I guess you could hire less proficient engineers which is a sell for startups, but I don't think it's worth the downsides of the current js ecosystem


It's not about RPC, it's about a way of DRYing code between the backend and frontend, using libraries as your copy-paste engine. You pull in the same library (or extract common code to a library) both on the page and on the server, and assume they're both identical.

I have mixed feelings about this. I don't feel comfortable with assuming that just because I use the same library in backend and frontend, I don't have to ensure consistency and behaviour. But then again, I've used this approach in one ClojureScript project (ClojureScript can transpile a lot of Clojure libraries to JS), and it is convenient.


Needing to copy code around is largely a JS thing IMO. Java has such good standard and third party library support that I don't see what would be that reusable between the front and backend. Except maybe validators, gRPC doesnt support even basic field validation its annoying.


sure that answers part of the isomorphic problem (but not all), but it still leaves me writing code in two languages that often have lots of similarities in how they look but funny little differences in how they behave that either slow me down or cause me to put in bugs because I'm tired because it's a small startup situation.


JS on both backend and frontend is all about reusability, less context switch and unified toolings.

And don't associate less proficient engineers with Javascript dude !


Sorry, it's a stereotype, but in my experience JS is a super common first language devs that know JS and nothing else are less experienced.


Other than form validation, I never wrote the same code for both sides.

And that is only when not using JSF, Spring, Forms, MVC, Liferay, Sitecore, which generate the JavaScript validators automatically from type annotations anyway.

For my projects, the Web layer is only the View part of MVC.


For a few things I've worked on Views can be rendered client side or server side.

Aside from form validation I find I might have a number of utility functions that are used on both layers.

I find there are a few other edge cases, but those are the most common situations where reuse is nice (on the other hand what I often do for personal projects is just build the server side and client side code from a gulp pipeline and not worry about needing 'isomorphic' code reuse, but often teams on paid for projects find this approach confusing)


Since JavaScript is a prototype language, doesn't reflection come in automatically?


Bad/non-existent annotation support prevents you attaching metadata to objects without adding garbage to their structures. Makes reflection a lot less useful


Not for most coders, unfortunately.


I will say that isomorphic [1] JS apps are really fun to write because with well abstracted APIs, the back end and front end don't feel like a discrete API and a discrete front end, but one entity that communicates via asynchronous function calls. For instance, working with firebase functions just feels like working with a local async function. But that's really a minor benefit to the fair criticisms you give.

[1] Whoever came up with isomorphic really liked their fancy math terms. Personally I'd have chosen automorphic, as it's all contained inside JS.


The problem I have with Java is that its a tremendous amount of code to do tiny things. There is a cognitive load that comes from reading. The more code you have to read to perform the equivalent action the more tired you get and the more opportunity you have for errors.

There is something precious to being able to do more with substantially less code, which is why I avoid OOP all together. You can't do that in Java.


While I agree with you, I just started a new project and we need a decent amount of backend work done, and I wanted to do that in Golang, Java, or Rust, but no one else on the team knows Golang, Java or Rust, just Javascript and Typescript so it made sense to go with a language the team was good with. So far I'm liking typescript on the backend, especially because we use it on the frontend. Also my coworkers can give me much better code reviews because they all know the language. But we will see going forward, still very much a green field project.


My $0.02 but that is NOT a reason to use JS on the backend. That is an argument to cross-train or hire someone. It's like saying "We only had an expert on building houses made with straw so we chose straw." Because they know the language doesn't mean for one moment that that will make a good background there are so many concepts, services, paradigms and best practices that the language is probably the least of importance other than it should be something solid, robust, and battle tested which I would argue against with most JS backends although some are fairly well understood.


Yea sure, but removing the language as a thing to learn makes it easier to learn concepts needed for programing on the backend. Besides were using Typescript, have automated tests, code reviews and Manual QA, I'm not worried about the code not being solid or robust.


> Besides were using Typescript, have automated tests, code reviews and Manual QA, I'm not worried about the code not being solid or robust.

Oh god...

Yeah, no. None of this stuff is a substitute for actual code quality. Give me a good engineer that refuses to write tests over a mediocre one that does TDD any day.


What kind of "good engineer" refuses to write tests?


I don't write many tests. I've found with experience and heavy linting you can avoid the vast majority of bugs. Not much point to spending a ton of time on tests if they hardly ever break for nontrivial reasons. My normal setup for java is:

Linters: ErrorProne Checkstyle PMD SpotBugs Nullaway

All with highly customized settings

All warnings enabled on javac

Google-java-format to autoformat everything on build.

For runtime analysis: LeakCanary to find memory leaks

Hibernate with interceptors to find long queries

Rest framework or gRPC with interceptors for long calls

Proxied JDBC connector to find long or N+1 queries

Opentracing/Zipkin integration to make debugging crazy stuff easier

NewRelic for projects where the $ makes sense

And I'm always on the lookout for more of these tools. In the long-run they save enormous amounts of time by preventing buggy code and keeping most shitty hacks out of the codebase.

Unlike tests, they don't break constantly and add more maintenance burden to the codebase. And it's less work, one time setup vs ~50% codebase bloat to add tests.

I see project leads call for more tests all the time to "fix" an unreliable codebase where there's zero linting. It won't save you from everything but I swear it's like 95% bug reduction. You should have most/all of these tools in place before you consider writing the first tests


> I've found with experience and heavy linting you can avoid the vast majority of bugs.

No, you can't.

In fact, I can't even begin to see how "apply this specific standard to the code" (linting) is even remotely related to "know everything about this particular domain so you don't make any mistakes in creating an application for it" or "know everything about this particular system so that a given difference in configuration screws up your application at run time".

You seem to be primarily a java developer so I understand why you prefer avoiding tests (among the many things that Java makes absurdly difficult, writing tests is one of them) but you should still write tests .

Look at any serious open source project, most of them have hundreds, thousands of tests. It's almost presumptuous to think that one knows more than the community.

> I swear it's like 95% bug reduction.

The only situation where linting really causes that much of an impact, that I've seen, is in an application where a huge portion of the code was just connecting or boilerplate that should've been brought from third party libraries anyway, and was written only because of the NIH syndrome.

Mind you, having code style is necessary so that any given developer can quickly get up to speed and more easily review other developer's code, but it doesn't (nor it shouldn't) tell you whether whatever you wrote actually works.

Assuming otherwise is like pretending that a movie featuring state of the art special effects, cinematography, etc, isn't still Transformers or similar garbage.


Linting is about so much more than code style and standards. Since we use auto format I have almost all the style checks off. What it does catch is hundreds of different types of potential bugs. Uninitialized variable. Missing null check. Deprecated or beta marked api used. Improper thread synchronization and double locking. Reassignment of parameters. Conditional check that's always true/false. This list is huge, and in my experience it catches mistakes constantly.

For the average crud app, if you're wrong about the requirements the tests will be wrong anyways. It sounds like you're talking more about TDD which IMO is a cargo cult. And I'm hardly the only one with that opinion. Integration tests are important but that's more about running data through the code all at once than testing each function in isolation.

Also, many open source projects get along with hardly any tests. The Linux kernel is probably the best example, but there's tons of popular projects without good or any tests. Check NPM popular repositories, I'll bet you more than half of the top 500 are under 10% code coverage. Tons of huge apps are doing fine without tests, and many I've worked on with tests are still horrible.

I haven't really noticed any contribution from having lots of tests. IMO what's far more important is linting and maintaining code standards. It's hard to write a function that's horrible to debug when the linter limits you to 300 lines. Or a class that's totally incomprehensibly long when the linter limits you to 1000. All of my debugging nightmare projects have been due to lack of sound OOP principles, huge files of spaghetti. Good linting prevents that from happening.

Besides Java my other big language is TypeScript. Using Mockito in java isn't that bad, and JUnit5 or TestNg are decent. Certainly easier than getting tests working in the garbage fire that is Angular6 + Jasmine + Karma.


I don't see how linting and experience prevents logic errors, missed corner cases, or misunderstandings of the requirements. In my experience integration tests are crucial to robust software.


It does nothing for missed requirements, but in my experience the test will be wrong if the requirements are anyways. I don't disagree with integration tests, which are usually just running the software through the motions in a semi automated way. I just think unit tests are pretty useless with good linting.

You might be surprised how much bad logic static analyzers can catch though.


I don't see how unit testing prevents that stuff either. How do you write a unit test for a corner case if you've missed it? If you're aware of it's existence, why not just update the code to handle it?


Quickcheck like libraries are reasonably good at finding missing corner cases in my code. It also helps if the person writing the test is different from the person writing the code and the person writing the requirement.


That's true. Regression tests are also useful.

But TDD is about neither, it's about test-first approach at the unit test level, which is arguably less useful and leads to design by random walk.


I know a couple that would tell me to go jump if I suggested they aim for 90% code coverage on a CRUD app. They also write very clean, maintainable code and do it very, very quickly.

There's always a trade off.


I'm one of those. Unit tests are a waste of time IMO. It usually takes almost as much code to test logic as it does to write it, so I always wondered why the TDD folks don't just implement the code twice and check the result at the end :)


I'm not writing a CRUD app, I'm writing a program that my company expects to put into production. Writing tests is very much a part of writing production code.


If you're in webdev, CRUD apps is probably 95+% of what gets put into production. CRUD isn't meant as pejorative here, it's just most of the things people do with software fits in the model of Create/Read/Update/Delete access to a DB.


?

CRUD apps generally go into production, unless something goes horribly wrong.


I find that beyond this, not having a cognitive disconnect in working on the frontend/backend is really nice. And depending on your data tier(s), can even go there (Mongo, Plv8, etc).

Compared to when I'd have to use ActionScript, JavaScript, VBScript, VB6, T-SQL daily... that was sometimes painful... then adding C# and VB.Net to the mix was ugly having to switch from one area of code to another.


Seriously, not knowing the language shouldn't be a factor in choosing a language.

Just choose the best programming language, and everyone can learn it; and they'll be happy and grateful in the long run that they chose to learn this new language, rather than use whatever they were familiar with.

Moreover, Java is such a simple and an easy language to pick up. If the cruft is too much to deal with, go with Kotlin. An experienced developer could learn either language (Java or Kotlin) easily over a single weekend.


This isn't always a useful way to look at it. For a startup or small team especially, any time spent learning a new programming language is time spent not working on the core product. Yes, you might be better off in the long run using a more foreign programming language, but then again the business might not survive that long if you aren't actually building anything.

Also, it's easy to learn a language's syntax over a weekend, but it generally takes a lot longer to start being productive and writing idiomatic code in a new language, especially if you're also learning a new platform. That's time that you or your team may not have.


As I said above: hire someone new or invest the time to learn the language. Just because someone knows how to make a cute scarf using duct tape, safety scissors, and Elmers glue doesn't mean they should be building your backend driving the company 95 mph with seatbelts, airbags, and a chassis with crumple-zones.


Hiring someone is very time consuming, and requires paying another salary, benefits, etc. Also learning a new language takes time, yes a person can learn the basics of a language in a day or two, but it will be a long time before they are equally proficient with that new language.


You said nothing that wasn't painfully obvious. My point is to build the backend right so you don't have to rewrite it again later. The time investment in the beginning will pay dividends as you scale (unless you are just mocking up or making an MVP)


You never really learn javascript, you learn frameworks. I was a js developer about 7-8 years ago and dabbled with jQuery , dojo and the likes and then moved over to backend and mobile development. I tried getting back into javascript again and realized that I just could not get in and start coding. There are a lot more frameworks now that I have to learn to get started and I'm sure that a few years down the line, these will become obsolete too.


Highly recommend vanilla JavaScript. With vanilla JavaScript you do not need any build tools. Instead of buying many different kitchen cutting and slicing tools - learn to use a knife.


I am quite decent at vanilla javascript, but building a website in vanilla javascript is like building a REST API in vanilla C. It's possible but will take a long time.


Highly recommend TypeScript. It brings so much method to the madness. Build tools are another clusterfuck but at least with TS you have a decently structured language with "standard" ways of doing things


I can't speak for anyone else... but I learned javascript and even liked it for most of the reasons outlined before the Good Parts book came out.

Since ES6 it's even better.


> Java, C#, Rails, and to some extent Python are much saner choices.

Python not as scalable, Rails is stagnating, the ecosystem doesn't evolve anymore/dying, doesn't play well with SPAs, C# weak to none ecosystem outside of Windows and devs earn a fraction, Java verbose and dev productivity subpar (there was a reason people came up with Scala), Java devs also suffer lower salaries


> Python not as scalable

Not scalable in what way? Every aspect of scalable that I can think of is in no way limited by choosing python as your language.


> I can think of

Mayne that is your problem. Try new stuff. V8 is still one of the fastest and most optimized VMs.


That has absolutely no relationship to backend scalability whatsoever.


I agree about critiques for most of those languages but not java.

If you reach out to the Java ecosystem you can find libraries, frameworks, and language extensions that make it relatively easy to code in. For example, with Lombok you don't have to write any getters and setters, or catch checked exceptions. Java 11 also makes good improvements to lamdas making method chaining a lot nicer. The Java I write at work is barely more verbose than the TypeScript, maybe 15% more code to do the same thing.

Java devs also get paid really well honestly, pretty sure it's better than the pay for JS and Python actually.


Python maybe but JS not. React devs are paud higher than any Java coder.


"Rails... ...doesn't play well with SPAs"

Huh? Rails ships with built-in, no-config webpack support (https://github.com/rails/webpacker#installation) as well as install tasks for the most-popular front-end solutions (https://github.com/rails/webpacker#integrations)


Dan Abramov wrote a brilliant post here, IMO. So much here. Unix Philosophy, yes please. Considering the cognitive load of tool options and configuration knobs, and the impact of the JS ecosystem for beginners. "A tool should work with (almost) no configuration." Amen. "Mind your output" from tools (errors must be helpful and sort the important from the unimportant); I've felt this pain and have abandoned tools at the start because of incomprehensible errors. Love the idea of toolboxes w/r/t dependencies. Read the post for the details. Great work Dan!


> cognitive load of tool options

First time I hear options are bad. Many options and competition lead to best products. There are enough posts and people who tell you what you should use.

Or just use npmtrends or npmcharts. 1 second later you know what is going on and what module you should pick.

Why are people criticizing something they have never used?


My point here on this one is simply that it's investing to think about this factor. For beginners (which I am not), too many options can be confusing. That said, setting reasonable defaults for detail options so things work well without needing to configure then to start is a nice way around this. Deep options exist and can be adjusted as needed but a solid default configuration is set out of the box. "There are enough posts and people who tell you what you should use." -- sure but what if opinions very widely? There's the cognitive load or put another way friction-to-first-use.


who said that JS is for beginners?


Just to be clear - you don't think the author has ever used a tool with too many configuration options?


Very nice points here. I've always been struck at how the JavaScript community never really adopted the Rails ideas of convention over configuration and optimizing for developer happiness. While it's easy to roll one's eyes at the marketing lingo, these principles do truly make Rails a charm to use. Right now, even setting up the most simple Webpack-Babel-Node config requires writing a whole lot of config and set up for very little gain.


Rails (or Python or Java) doesn't really fit into the problem set that JS has to go through. Most softwares written in those tech stay in the server with no need of transpiling, no need of code splitting when built, no need to be sent over the wire, etc.

While I agree the package management in JS could have been better, most other too-much-config problem is just because of the variety of problems and the variety of potential solutions.


I'm not so sure about that. While there are a lot of complicated situations for JS dev, there's also a lot of similar patterns. I'm not saying we need to ignore the various complexities involved in JS dev, but we should make the general patterns easier to solve. Yes, of course transpilation can have all these different edge cases. But we should be able to have some preset modes that can do 90% of the work automatically. Like it baffles the mind that I still need to tell webpack that JSX files should be loaded by babel.

And anyways, there's the entire backend JS ecosystem, which is extremely behind Rails in developer ergonomics. I can spin up a REST API in Rails in half the time it takes to connect Node to a database.


Ember is exactly that. I love it and use it on my day job and on my side-project. But overall it doesn't have much adoption and no perspective to grow anymore.


I've wanted to use Ember, but I've never bothered to sit down and learn it. What ever happened to Glimmer? I remember it being hyped up as a crazy fast virtual DOM, but I haven't heard anything recently.


It is super easy to pick up, you can understand the whole concept quite quickly. Follow one the tutorial and you will be ready to deploy new apps in days. One of my fav free tutorial: https://www.yoember.com


Thank you for the link! For some reason it gives a "Your connection is not secure" error on Firefox, but I managed to find the tutorial via Google. I'll give it a shot sometime


yep, without www: https://yoember.com


It was incorporated as the UI engine for Ember for some versions already for now.

Nothing revolutionary, but a good UI lib


In JS there is a lot of convention but on a micro level. The times of monolithic Rails apps which have strict conventions are over and it's good: Too much magic and strict conventions often forced devs into patterns which didn't match the use case. Even experienced Rails devs tried to solve every problem the same way.

You also confusing matters. You need Webpack, Babel etc for the frontend not the backend. And even in the frontend it got abstracted away by things like creat-react-app. So you shouldn't them see them too often.


First, Webpack and Babel are totally used for backend. If you look at a lot of Node libraries, they use ES6 modules in their [docs](https://github.com/graphql/graphql-js). While you could use mjs for this, it's still experimental.

I do think create-react-app is a good innovation in the JS world. However, I've never found a good equivalent on the back end. Setting up even the most basic CRUD REST API requires a whole lot of typing for very little reward.

As for convention, I think JS could do with more of it. I find that when I talk about adding more convention, people take it quite literally as "we need to reinvent Rails in JS". That's not at all what I mean. Convention can be something as simple as Rack, which is a consistent, useful interface between servers. Convention does not and is not tied to monoliths or MVC or any other aspect of Rails.


> I do think create-react-app is a good innovation in the JS world. However, I've never found a good equivalent on the back end. Setting up even the most basic CRUD REST API requires a whole lot of typing for very little reward.

This is where services like Google Firebase Functions become useful.

I went from having never written a REST API in my life, to up and running in under 20 minutes.

First time I went to create some endpoints on my own server, wow, that was a pain.


Firebase is a dream. It's almost a shame they got bought by Google because it's such a fantastic idea. All of the things I used to dread setting up (auth, deployment, serverless) are automated and dead easy. The documentation is clear and caters to the common usecases. I managed to set up a Sendgrid email that sends on database writes within an hour or two.


> The documentation is clear and caters to the common usecases.

I wouldn't quite say that, but I'll agree with your other points. :)

(More than once the docs have been out of date, or just flat out wrong, costing me many hours of development time...)


JS is so good for APIS because of its dynamic JS objects. If you then take also a document storage you don't need any ORM anymore and write your entire API in 5 mins. Rails was a nightmare compared. JS lets you do stuff yourself. You don't any framework holding your hand. Maybe that's your problem.


In what world you think the usability of a language is determined by being able to get a Restful API up in 5 minutes?

Yeah, document storage for business-critical data. I'll pass. There's a reason important data gets stored in Postgres.


Simply not true. Rails continues to be the choice for many companies who don't base tech choices on what the latest bandwagon is.

JS is mess.


Rails is so much into its own world I hate it. Glad JS is developing in different ways. Try parcel bundled, it's zero config yet it doesn't invent its own world to freak newcomers.


Gatsby is pretty much a superior version of ruby on rails in my experience. I don't remember the last time I had to touch webpack.


I personally think that the JavaScript community is doing a great job with its tooling and approach. Compared to other language environments I’ve worked with (C, C++, Python), most common JS tools work in predictable, user-friendly ways...also they frequently have good documentation and “getting started” tutorials.

It is good to see that the community is open to introspecting and improving even further


Ten years ago, JavaScript was my go to when I wanted to expose others to coding. It still is today, but now that comes with the caveat that the most popular libraries and framework require a significant amount of prior knowledge to understand and to start using.

I haven't done this exercise in a long while, but the last time I tried to start a project from the "most current and stable releases and recommendations", I ended up not being able to get anything running. In the end, I had several hundred megabytes of libraries downloaded, a complicated configuration, and a non-working application.

Today, there are toolsets to get you started with everything and produce a running application, but it's almost totally opaque. I'm afraid to use them because the first time something breaks, I don't know if I would be able to resolve the issue.

I would still rather have a decent understanding of how things connect.


That was my biggest eyeopener when I started using React - the piece I know just the tippy top of the iceberg. While that's true with a lot of languages (it's not as though I know what's going on with the whole .NET stack) it seemed especially egregious. I had a site up and running quickly, but it pretty much entirely magic.

Do you teach JavaScript first just because of how fast it is to get it up and running (ie. "Just open your web browser")? If I remember correctly it was much more vexing than a lot of compiled / strongly typed languages as the errors in those languages came sooner. In JavaScript there have been times where it loads and runs, but nothing happens, and I had no idea why, which proved frustrating.


JavaScript is still what I use to introduce programming to new people, because for people who haven't done their dues learning how to use a command-line, the hardest part of getting started with programming is getting your computer set up to do it at all. And since everyone already has a browser, getting started with coding only requires showing them how to open the developer console.


Installing stacks like Rust, Erlang/Elixir, Go and maybe OCaml is so fast these days that you likely will not have halved your coffee by the time it's done.

I agree getting to the browser dev console is instant gratification but I don't view 5 minutes of installation as a punishment from Hell either.


Fair, but most stacks including the previous infamous ones are two or three lightweight installs away. The VSCode/Atom/Sublime generation of IDE replacements made that possible.

I come from an environment (.NET) where setup was a day or two of work but now is a matter of 10 or less minutes).


10 minutes is still two orders of magnitude longer than "<ctrl-shift-c>."


And? Is 10 minutes so damning?


I disagree. Assume you are an average coder, you should have a clue of basic JS:

1 week to learn JS latest language features

1 week to grok node, npm and the power of the JS object

1 week for React, basic stuff not redux

1 more week to dabble around

4 weeks and you should be able to be productive JS with its most important flavors. Tell me any other ecosystem where you are that fast.


>also they frequently have good documentation and “getting started” tutorials.

I tried making a TypeScript react app around Christmas, I found a tutorial, the commands did not work, I do not remember the details but it was using some bundler and probably the tutorial was a bit old and packages updated in npm. I found a different tutorial, to use create_react_app,

I seen it uses npx(not sure when this tool appeared) it also used tons of dependencies, in the end I created my app from scratch using only the TS compiler package and the react client library, no extra tools, magic, 1 month old tutorials that are outdated already, no install latest tool of the month etc.


> I found a tutorial, the commands did not work

That’s hardly unique to Javascript. Back before the internet even existed I’d seen out of date make files which did nothing but spit out linker errors due to API changes in libraries.


What's unique to JS is how short the shelf life of documentation is compared to the past. 15 years ago if you found a tutorial and it didn't work, it meant it was either many years old or you could install one java (etc) version prior and it'd work again. It seems like a lot of JS docs go obsolete within months if not weeks.


JS has a lot more churn than pretty much any other mainstream language or ecosystem.


But it is way more common in JS. It got to the point that I do not trust tutorials that are not “official”.


Honestly, this is even a problem in "official" tutorials. I set out to learn some basic node a while back. The official docs then were out of date enough to not work to install node (nor were they off a trivial amount). I finally figured it out and PR'd a doc fix, but you shouldn't have to do that to try out a platform.


npx create-react-app my-ts-app --typescript takes about 30 seconds from command to running app.

Maybe the issue people have is there is no 'js-lang.org' with one tutorial site and getting started. It's a huge community, so of course random blog posts will be a mixed bag of quality.


It takes about 30 seconds since last week 'till the end of the next month. If you read older tutorials, you won't figure it out. By March, current tutorials will probably be out of date.

That's my issue (one of many) with the JS ecosystem. Things move so fast that just keeping up feels like a full-time job. I remember giving up on my first approach to React after I followed Swizec's tutorials and quickly hit into some issue with Babel (of all things) that was a week old and transitively screwed up a few months old React/D3 guide.

And, as 'simion314 said, there's way too much magic. create-react-app is a useful spell that (most of the time) makes you a working React app, but I'm not fond of a culture that encourages casting it instead of understanding what's going on and how to actually set up a React project.


This is why I refuse to use create-react-app. I can appreciate the convenience and have learned a few things from reading its source, but I need to understand the entire application I'm building from the ground up.


There are more issues

1 the right tutorial, instruction may not be on top on my search engine, a few months old instructions are too old

2 the create app thing uses tons of "magic", it encourage people not to understand how things work, all is fine until something breaks... here is an issue we hit at work

We have a project that uses gulp(the project is old, I did not started it so don't blame me if gulp is not the state of the art today). One dev added an uglify step to gulp and now the gulp watch t process entered in an infinite loop, I as the one with the most experience I worked on figuring it out, since the uglify step causes the issue I investigate this(I discover that some gulp modules the project uses are obsoleted because a cooler/better one was created but I did not started on upgrading the tools), I read on uglify, it's dependencies, I read on watch it's dependencies, read how it is implemented under the hood and in the end I realize that uhe uglify hstep had the side effect of making the process longer (I suspected that some temp files would be created or other things) but this extra seconds triggered an existing issue in our configuration file, the watch task was watching the output min files but it never triggered before because of a timeout it has(or something similar). In the end I ended up looking under the hood of this magic tools because a dev setup a .json config file wrong but the issue did not manifest until years later.

Conclusion is that magic tools work fine until they do not , then you have to look under the hood or try the reboot,update,change the tool and maybe it is fixed

For tomorrow I need to investigate why npm install package fails to install a package dependencies on a CentOS server, I read that there were some bugs and probably the fixes were not backported and I will have to mess around and understand what is the problem and fix it somehow.


I welcome the slow transformation of Javascript into Ruby. Every single thing in there is already a thing in the Ruby ecosystem. Convention over configuration. The careful, but automatic dependency management. Principle of least surprise.

All things I didn't know how much I relied on until I moved to NodeJS and found them non-existent.


What you said could be true of Java or any other modern server languagae.


I just wrote a proposal for my team today as to how the front-end tooling has changed recently and why we'd need to adopt them in our workflow.

https://writer.zoho.com/writer/open/0y4wx08838bdbcf954b1398c...

With confidential details masked, it's still a pretty good read for the rest of the Internet. Outlines why JS fatigue is not really bad but just improvements and what exactly is stopping us from adopting those improvements.

Resonates a lot with Dan's write-up. Excellent piece by Dan. A much needed one. I'd probably link this along in my proposal.

Note: We've built a pretty fat browser app with plain vanilla JS, strictly ES5 only, crude bash scripts for building a bundled js & all such ancient methods.


Really curious what is actually wrong with "crude bash scripts for building"?

I had experience with both types of projects - the ones with home made crude build tools (in Python, not bash), and the ones with modern javascript build pipelines. The first build never broke. The second build would break every couple of months for no obvious reason without us touching the project structure.


There's nothing wrong with handwritten scripts. The lack of problems are exactly why the current dev workflow has scaled and I'm saying this as of 2019, which I find interesting!

The problem is opportunity cost. The rest of the tools in the market (Webpack, Rollup) are offering heavier benefits like automatic code splitting, dead code elimination and such things.


Maintenance. Because seems they are usually written/owned/optimized by some build brainiac that becomes a bottleneck or leaves at some point.


The equivalent "modern" workflow is written, owned and optimized by build brainiacs with turnover on the order of weeks. I'd say that maintenance of "crude shell scripts" is much less difficult and expensive than keeping up with the latest webdev "standard practice".


You'd be wrong. I'm not arguing that Webpack is a deeply confusing system, but there are tens of thousands of people out there figuring it out too. Almost any question has an answer a Google search away.

Your bespoke bash script has no such community.


But my bespoke bash script has longer shelf life, which is the entire point here.


On the other hand, most developers speak at least enough bash to read bash scripts, and bash's backwards compatibility is pretty good.


At Blockvue we have also had a lot of success going back to basics with vanilla js. Doing a large SPA in vanilla js is actually a charm these days and the result is extremely lightweight and fast. The SPA concept is sort of new, but if you really commit to not doing any server side page generation the result is so easy to manage. This also allows us to focus on having a fast crystal-based API backend to power our SPA and other services. We use a script to minify and deploy directly to s3/cloudfront, and then use lambda and some microservices for API endpoints. The turning point for me on this issue was when I realized that Google has been indexing dynamic js content since 2012 (I had no idea).


I'm still firmly of the opinion that nobody wants a SPA apart from the developers of that app.

I'd bet any of us could find a ton of weird and unintuitive things your app does, as well as it probably being slow to load, hard to use and brittle, in that you'll regularly put out an update that inexplicably breaks something for a day or two.

Add on top that massive extra expense of doing a pure SPA compared to the ease and simplicity of developing a mixed server/front side app, I have no idea why anyone sane ever signs off on a SPA.

And that's before we even get onto the vastly better tooling and development environments that server-side languages have.


I've architected Web Application that runs as in a) connected as in b) occasionally disconnected mode (LocalStorage + sync when online).

For #b SPA is the only option.


Nobody is saying that SPAs using modern web technologies -- like offline mode -- do not have any use.

The problem is that SPAs are shoehorned on many places where they are absolutely not necessary and only complicate things.


To me SPA = no server side page generation + an API server. Maybe I use the term too generally.


It could be that our app is uniquely situated to avoid these issues, but we have had the opposite experience. Our API is versioned so things never get out of sync, the frontend code has no external dependencies so its as unbrittle as one could imagine, and we use aws API gateway to fake server side endpoints, so we dont have to do some weird url scheme. This could never work with a CRM though.


>Note: We've built a pretty fat browser app with plain vanilla JS, strictly ES5 only, crude bash scripts for building a bundled js & all such ancient methods.

Jeez, man, I'm all for minimal tooling too. But ES6 is the lowest hanging fruit there is, I beg you to consider adding a transpile step to your build on your next project so you can use it!


The problem though was Webpack was generating massive bundles (probably something to do with the polyfills needed for different browsers). We were able to achieve much smaller bundles by just sticking to ES5 features supported by the browsers we support.

Oh, and code splitting was out of the question. Most modules were attaching themselves to the global namespace (note: a large portion of the app was built even before requireJS was a thing). Which means code-splitting is a developer discipline category, not an automated one.

We have slowly started improving these things though. As I've mentioned in the document, the benefits are beginning to far outweigh the cost now, so yeah we'll move to ES6 soon.


Es5 only? Jeez that would be an immediate dealbreaker for me with any potential employers.


Well, for those of us from the 2000s era of web dev ES5 wasn't such a deal breaker. It isn't very concise, but ES5 isn't so bad either.

ES5 to ES6 isn't what Java is to Python. It's more like what Python 2 is to Python 3.


This is interesting. Today, when people say ES6, I feel like they actually mean esnext, as once you accept a transpile step from TypeScript or Babel, you might as well get the benefits of new language features in your codebase. I wonder how many people mean es2018 when they say es6, complete with some pretty dramatic code style shifts, including a tendency towards classes, async/await, and composition-first nameless but concise arrow functions.

There are some coding styles that are popular in esnext that just aren’t practical in es5 because they would be too verbose and not “read” very well.


Relatedly, I'm increasingly surprised how many people still think they need a transpiler for ES2015-ES2018. Browser adoption for them has been much faster than the once problematic ES3 to ES5 upgrade.

Especially for those that use the common suggestion for Babel of "last 2 versions of major browsers" presets, the amount of transpiled code has gotten extremely small, and increasingly so.

For example:

Arrow functions: https://caniuse.com/#feat=arrow-functions

ES2015 classes: https://caniuse.com/#feat=es6-class

Async/await: https://caniuse.com/#feat=async-functions

ES2015 modules: https://caniuse.com/#feat=es6-module

«There are some coding styles that are popular in esnext that just aren’t practical in es5 because they would be too verbose and not “read” very well.»

I like to check my code after downleveling in Typescript to ES5 from time to time. There isn't anything in ES2015-ES2018 that downlevels to "unreadable" in Typescript. The "worst" you get is async/await transpiles to ES2015 generators of promises (function*) which then transpiles to ES5 switch/case state machines, but even with all of that downlevel work I think you'd be surprised at how readable it stays.


> just aren’t practical in es5 because they would be too verbose

This is why coffeescript was a godsend. It produced very efficient code too, simpler and faster at runtime than the ES6 replacements.


JavaScript was designed to be a glue language - to connect output of one native function with input of other native function. And do all of this in UI event handlers.

And it was almost perfect (modulo hoisting, semicolon omission) for that.

The trouble has started when Web, as a platform, has failed to provide safe alternative to JS aimed for extendable way of delivering and running high-performant code on the client.

Ideally we should have something like <script type="binary/bytecode"> with something close to JavaVM and HTML DOM exposed to it. At least 15 years ago. So we would have a lot of compilers, static compilation and code analysis.

Instead we have tons of weirdest possible solutions: Web "threads" with code that need to be downloaded and compiled before running, that ugly WebAsm, transpilers-of-something-into-JS. C++ code "transpiled" into JS, in whose nightmare that bright idea was born?

Yet we have crowds of talented people wasting time of writing about how to really HACK the platform that was not meant to be used this way.

Create bunch of problems to ourselves just to overcome them heroically. Far from being productive.


> something close to JavaVM and HTML DOM exposed to it

> ugly WebAsm

WASM isn't fully functional as a standalone alternative to JS in the browser, yet, but you can essentially use it that way with things like wasm-bindgen in the Rust ecosystem. And it performs essentially what you're describing, being a VM running bytecode in a sandbox.


> but you can essentially use it that way

"Essentially" is a nice word. You can use it for example as JavaScript is a programming language, essentially, yeah.

W3C DOM was defined initially in terms of Java interfaces.

Where we would be now if we were allowed to run Java bytecodes in browser directly from the very beginning?

<script type="binary/web-bytecode" src="myapp.class">

Today we might discuss -strip-dead-code option in your favorite compiler of XYZ language. Instead of fighting with would-be-linker npm.


> Where we would be now if we were allowed to run Java bytecodes in browser directly from the very beginning?

We'd be ranting at JVM for not having the features necessary to compile high-perf C code into it, for one.

Which is why Wasm is fundamentally a better approach. It's that one case where it makes sense to go as low level as possible (while retaining cross-platform support), to allow as many future possibilities building on this foundation as possible.


Are you not forgetting something? Java is to this day several times faster than JS and sources for that abound on the net (including [0]).

No, we wouldn't fight for how to compile C in it. We would very likely fight to make the payloads and bootstrap times smaller.

[0]https://benchmarksgame-team.pages.debian.net/benchmarksgame/...


Faster than JS doesn't make it fast enough. Look at how it fares versus C in those same tests.


Fair, but do we really need C levels of performance on the web? That's madness. They are mostly CRUD apps for God's sake. They don't have to be able to run liquid simulations at 200FPS.

IMO the level of Java / Erlang performance is, and should always be, plenty enough for the web.


For CRUD apps, JavaScript is plenty perf-wise already. The reason why there have been many attempts to push things further is precisely because people are trying to build web apps that need more (including 3D games even).


I never got the idea of nodejs or javascript for backend, tried it a few times and eventually returned to python and java. It's much easier for python/java to add event-loop and/or restful framework than making javascript looks like python/java one day as far as backend goes.

In 2019 I still have 0 interest in javascript/TS for backend, the thousands of modules under node_modules alone is enough for me, and not all real world product need async/promise/callback/SPA, javascript is over-heated too much, not fun at all.


You don't get to just add an event loop and start writing async code in Python or Java. It opens up its own can of worms now that you're straddling the sync and async worlds. Compare working with Netty (async) to Jetty (sync). It's certainly not trivial.

That Javascript is async-everything is one of its best and often overlooked features in these comparisons.

I think this snippet encapsulates a lot of why Javascript is actually very pleasant on the server:

    const results = await Promise.map(urls, (url) => process(url), { concurrency: 8 })
        .then((results) => postprocess(results))


I don't think it is overlooked. JavaScript doesn't scale, both in terms of code complexity (callback hell) and across cores, and the "gold standard" these days is microservices, which has a ton of issues.

If you want to look at bolt-on async working, check out C# or Rust. They've basically taken JavaScript's new async/await and added threading (at least Rust has, not sure about C#). You can write an async app and have it run in a thread pool without much fuss.

I don't know what the story is for Java, but seeing as C# is effectively the same thing, it's not hard to imagine adding async being easier than adding threads or performance to JavaScript.


FYI, async/await (a promise type + async function decoration + await expressions) was actually invented by C#. It was designed to operate seamlessly with .NET's concurrency framework, the TPL, which uses a thread pool. So it was actually the case that Javascript took async/await and removed threading.


JS is not your daddy's JS anymore.


Is it unfair to say that some of these problems are caused by a lack of awareness (or an unwillingness) to learn from other communities (like, Ruby, Java etc) that have solved these some of these problems already?


No. And that is also why JS is successful. Newbies with little oversight create new tools. Of thousands of them, one or two become popular because of non-functional reasons (right blog post, right fit, easy use, ..).

Welcome to the mess :)


Tech pop-culture... Navigating these technology growth explosions is like searching for solid reference architecture in a booming shantytown. Some parts of these settlements eventually get things like running water, working sewage, urban planning.


Do not disagree to that. My comment is not a compliment to JS just a brutal analysis.


Let's say you'd like to write front-end code in a language that hides as much of the problems with JS as possible, preferably one that comes with a standard library, has elegant (or at least ergonomic) JS to <lang> interop and bridging, simplifies async code, and has a simple, integrated toolchain for targeting JS (all these amongst other things), what would you suggest? Basically what's the best language to write Javascript in : )

Dart? Elm? Clojurescript? Objective-J?


ReasonML


Oh I forgot about Reason. Does it have a standard library that obviates the need for pulling in things like lodash, etc?


Unpopular opinion time: I understand why people prefer TypeScript/CoffeeScript but for me personally it just destroys the incentive of a scripting language and I am a fan of keeping deployment as simple as possible and to me transpiling is equivalent to compiling. Packaging is bad as it is.

True, maybe everything is different in large scale applications but I hate it if I find something interesting implemented in TypeScript and in 95% of cases I will just move on.

Javascript is not a beauty and any superset just seems like a facelift. The result looks like old and used car tires.

disclaimer: I am no web dev but somehow come in contact with JS frequently.


You never really learn javascript, you learn frameworks. I was a js developer about 7-8 years ago and dabbled with jQuery , dojo and the likes and then moved over to backend and mobile development. I tried getting back into javascript again and realized that I just could not get in and start coding. There are a lot more frameworks now that I have to learn to get started and I'm sure that a few years down the line, these will become obsolete too.


Interesting. I stopped touching frameworks on my second year in. It's the same problem I have with trying to develop within the constraints of someone else's work: I find it confusing and anxiety-inducing.

I'd rather write my own stuff, unless I'm woefully unequipped to to begin with. (Cryptography, authentification, credit card handling...) I feel like I'd learned quite a bit of JavaScript, specifically – especially with the help of someone like Angus Croll [https://javascriptweblog.wordpress.com/].

I'm not that clever a JS developer – or a programmer, for that matter – so his `compose()` and `curry()` sound magical to me.


save




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: