> React: when you need total control over the architecture and build, but only for webapps built with components. React-ecosystem development takes time and requires a lot of planning beforehand. React pays back plenty, but only if you know what you are doing.
Complete nonsense. React is not any more complicated than Vue and I think it's significantly easier for newbies to grok than Angular (with some non-trivial anecdotal evidence to back this up). I do not understand where this perception comes from. My best guess is that React scales well to complicated applications which makes people think that's what it's geared for. Maybe I'm lucky that I learned React in the "early days" before this perception was common.
I think this sentiment comes from the fact that React is not a complete solution, and for big projects, you will have to make several impactful decision about architecture as it relates to using React.
Angular and Vue don't encounter this as much because they are more broad, and more opinionated.
React is not a complete solution? What are you referring to? It’s a complete solution for describing what you want on the screen and not worrying about how that happens. It comes with build tools. What else do you want?
React is frequently mentioned in the same breath as Angular/Vue/etc. Angular, for example, has most of what you'd want to build a complex web app built. Compared to that, React is not "complete" because if you wanted to build a complex web app you'd need to start using outside libraries or writing a great deal of code yourself.
I agree this does not mean React is "incomplete." It does what it sets out to do very well. But the discussion is often framed as React vs Vue vs Angular, fair or not.
> because if you wanted to build a complex web app you'd need to start using outside libraries or writing a great deal of code yourself.
This is false. The ambiguity in this comment (“outside libraries”) speaks for itself. Yeah you probably want to use something for routing, but you really don’t have to at all. Otherwise nothing else comes to mind in terms of “libraries”. Just weird that people spread FUD/misinformation like this. so weird.
This isn't a weakness in React. I prefer react's approach. But it does mean the developer needs to make more decisions.
Angular comes with stuff like RxJS and a wrapper around XmlHttpRequest. React doesn't. Again, this isn't "correct," it's just a different approach. No one is being combative here (except you), just descriptive.
Neither of those are things that are needed for a javascript project. Fetch is a perfectly fine replacement for XmlHttpRequest and is a standard part of JS. RxJS is nice to have, but is not necessary.
I don't like the "batteries included" metaphor because it implies getting batteries is hard. Yes, Angular ships with routing but thanks to the node ecosystem adding react-router is a one-line command. The hard part is learning the routing API which you have to do either way.
"batteries included" means that the software itself has everything you need to get going. It's not that it's hard to get an individual component, but now you're relying on a third party component and potential issues with random configurations etc. It takes some research and effort to figure out that react-router is the best module among the options for routing.
There's no router, for example. I'm a huge React fan, but it's frustrating that the third party router I chose has been through 3 major paradigm-breaking changes since I started my project.
I have experienced consistent quality from the core React team, but their footprint is limited by design, and I think it's naive to imply that relying on ecosystem projects is the same level of "complete" as being able to rely on core projects.
Seriously? Complete non-sense? React projects are frequently broken down into lots of small components with custom model/controller architectures depending on what third party tools you throw in with it. There are many areas where bloat and technical debt can add up if you do not properly plan before hand. Particularly in scenarios where you may be getting into front-end development for the first time i.e. when creating a MVP for your start-up. In this scenario and others like it React may not pay back plenty.
While these issues exist in other libraries/frameworks they are somewhat mitigated by clearer first-party conventions or front-runners in the third party ecosystem which dictate specific architectures.
- React takes way more configuration to get started than Vue. You can technically use either of them with or without build tools, but without Babel and Webpack, Vue is still reasonably usable and React is laughably obtuse.
- React out of the box may not be any more complicated than Vue, but it also does a whole lot less than Vue does. Chiefly, you don't get tracking of deep state changes without adding a second (state management) framework on top, and the major ones designed for use with React are also designed for scale, and require tons of boilerplate and highbrow programming theory to get up and running with (I'm looking at you, Redux).
- React itself is pretty highbrow, forgoing straightforward OOP concepts for functional-programming ideals. Which isn't a bad thing! But it makes it harder for newcomers who just want to get the text on their page to match up with what's being typed in an input.
React's component-ish nature and such actually makes things easier for me to digest / manage. No painful planning needed and I can move stuff around at will.
I put React on everything (even if only for practice).
It was a bit intimidating at first (like a couple weeks...) but it doesn't take long for for the fundamental React-isms to become second nature / my preferred way of doing the front end.
I had worked quite a bit with Angular 1 (first "real" front-end framework I learned), and some jQuery before that. I found the React/Redux/JSX stack to be really quick and easy to pick up. The simple component API and minimal use of magic helped avoid many of the headaches and quirks Angular 1 was riddled with. React/Redux is the most painless front-end stack I've ever used, makes writing web clients much faster.
My only real complaint against the modern React/Redux stack, is the crazy amount of boilerplate involved, even with a "minimal" project.
FWIW, Angular, Vue, Polymer, Ember, etc. all use the same component-ish pattern; it's the architecture du jour. That's great that you were able to pick up React right off the bat, but the concept of components isn't what sets it apart.
I guess I kinda implied it was a reactism, but that wasn't my intent.
I was just noting how someone else new really doesn't find React as big a hill to climb as the article. The componentisms are just something that make it easy for me.
1. Using x as variable name can sometimes increase readability. For generic functions that are close to mathematics it is not a sin to use such variable names. Though way to often I get pointed out to rename it to something more descriptive. Longer variable names can also leads to worse readability since a linter will now make 1-liner split into a 4-liner.
2. Tests: "With increasing complexity your codebase will become much harder to maintain and control — tests will do it for you." Good intentions here but be careful. Tests can cause people not wanting to refactor/fix because now they have to fix the structure of the tests. Refactor means more than changing the implementation of functions.
3. "Commit daily,... . Give meaningful commit messages." I am starting to see a trend where PRs get squashed into one commit. Thus making such advice not very useful.
1. The number of cases where a one-character variable name is a good choice is small, and those are usually limited to the scope of a single loop, a lambda parameter, etc. A good linter should understand that.
Though naming is hard, and coming up with a descriptive and short name is often not easy. It's a worthy exercise, though, it makes you think about what this thing really is, and can even uncover bugs.
2. Test the public interface. Don't write, rewrite, or remove tests that test specific implementation details, to say nothing of trivial things like getters / setters. In a a good test suite, 20% of tests break during a big refactoring, but the remaining 80% show you that you're still on the right track. Most of the broken tests are often easy to fix mechanically, and those that need thinking, would need thinking anyway. They test the actually changed stuff.
3. Commit more than daily; commit with every change worth looking at, or reverting to. Spend these 15 seconds thinking up a good commit message.
Squashing on development branches is both counter-productive, hostile to code reviewers, and needless. Git can auto-squash commits on a merge for ages. Github has a checkbox for it, so does Bitbucket. Use that.
1. I did say sometimes that single letter variable are okay not always. The example you mentions are good cases. Especially lambda functions. If its not mentioned some will interpret that single letter variables are always bad.
2. My experience says that is too static way of thinking. Maybe I work in too fast paced place, but usually we learn that previous written software is not good today and we need to rewrite the code to make it better. Rarely have I seen that interfaces stays the same forever.
3. Whats the difference here? Squashing on a development branch vs on merge? Btw I do commits daily with good messages, but I am just wondering what I get from this if I loose it later anyway.
If you have to severely rework interfaces very often, your area may indeed be very fast-paced; e.g. so fast where reasonable design and planning is impossible. (I can name a few areas like that, e.g. trading algorithms.)
If you, in your very fast-paced environment, ever do code reviews, you likely noticed that showing the thought process, or separation of concerns, in separate commits helps reviewers wrap their heads around your changes. Adding commits that address feedback also helps the review process. Another feature of multi-commit development is when you notice that e.g. a particular feature won't fit in the next release, and you take only these changes to a different branch.
I guess its subjective/individual what is considered fast-paced. I would consider it normal web-development in agile environment. There is time for design and planning but you also have to be practical and get work done. Good design is preferred but change will happen, otherwise you can end up shoehorning yourself.
We already have practices about keeping PRs small so one could argue having to focus on crafting good individual commits is not that important in the grand scope of things. Especially if those carefully crafted messages will go lost after a merge. Some PRs require heavy reviews, while others just require a quick look through. From my experience people usually look at the changes and not the commit messages (myself including).
> Another feature of multi-commit development is when you notice that e.g. a particular feature won't fit in the next release, and you take only these changes to a different branch.
If your PRs are small you could also just move the changes yourself manually. Or you could do as you say and move each 'WIP' commit if necessary.
Regarding your first point, in side projects, I've started doing things like this:
for c in customers:
return c.first_name + c.last_name
or:
customers.map(c => c.first_name + c.last_name)
I've started doing this because I didn't like having "customers" and "customer", I found this very un-readable. It also makes it simpler to follow what's going on since I have less code to parse.
And because I never use 1-lettered variable names (unless it's a counter like i, j, k), I find it very easy to read when this convention occurs in my code.
Using single char variables is fine and IMHO leads to more concise code without sacrificing readability. When you are looping over a set, it's very common to think about it like `for all x in Xylophones do {...}`. For example in a nested loop, I would much rather prefer `i` and `j` over `iterativeAuxiliaryVariable1` and `iterativeAuxiliaryVariable2`. Never using single character variables as a "best practice" is just bad advice. As with pretty much everything in programming, the real answer is "it depends".
Meaningful commit messages on the feature branch make it easy to compile a list of changes for the PR; in the case of GitHub, the squashed commit's message for the PR lists the individual commits that make it up in the larger text box, which can be nicely formatted into bullet points.
The Clojure world has a set single-letter naming conventions that, since they are widely accepted, greatly improve readability. If you see an argument named `f`, you can be sure it is a function. `m` is a map, while `k` and `v` are used for keys and values, respectively. `x` and `y` are numbers and `n` is always an integer.
I bet the scope of such names is pretty narrow, no more than 3-4 lines? The narrower the scope, the less descriptive your names may be, and such math-like conventions make sense.
In a 50-line function (which you should avoid but sometimes can't because of long lines wrapped for readability), using a name like `f` throughout is a harder sell.
No. It's alive and particularly pragmatic in dynamic languages. The type of sigil, @ or $ or I or Array(space) are all equal to the interpreter. The difference is how offended you might be that type annotations are semantically identical.
> 2. Tests: "With increasing complexity your codebase will become much harder to maintain and control — tests will do it for you." Good intentions here but be careful. Tests can cause people not wanting to refactor/fix because now they have to fix the structure of the tests. Refactor means more than changing the implementation of functions.
Isn't the entire point of tests that you can refactor the code under test without changing the tests themselves? Otherwise how do you ensure that you have not introduced bugs in the code by doing your refactor because you've changed the thing that tested the code in the first place.
A refactor of the tests should be done independently of the code under test.
I agree and I think this is why OP said to be careful -- there are so many engineers out there who do not separate the ideas of code and functionality. When these people write unit tests, they are essentially just checking that the unit behaves exactly as it currently does (white-box style), instead of checking that the unit behaves as desired (black-box style). Every subsequent change to the codebase requires a corresponding change to the tests, even if the external behavior of the unit remains the same.
Yes, ideally. Usually though you have to make changes because something is not working as it should or you found a better way. If you never change the interface the code often times rots. Most of the time we don’t make the correct design decisions from the start. We learn from previous understanding and that might require to do things over.
> Using x as variable name can sometimes increase readability. For generic functions that are close to mathematics it is not a sin to use such variable names. Though way to often I get pointed out to rename it to something more descriptive. Longer variable names can also leads to worse readability since a linter will now make 1-liner split into a 4-liner.
I've rarely seen cases where abstract short variable names have improved readability on their own.
Where it has helped, either there is a comment explaining what the variable is for, or there is a strong convention already in the domain, like using x,y,z in graphics programming to indicate position.
Also... I haven't really encountered linter issues with longer variable names. Do you mean linters that enforce maximum line widths? That seems increasingly rare these days.
> "Commit daily,... . Give meaningful commit messages." I am starting to see a trend where PRs get squashed into one commit. Thus making such advice not very useful.
As a general point of practice, squashes should merge together into semantically meaningful packages, and big multi-purpose commits are the actual no-no. So for example I'll squash together two commits that say "Fixed ABCD issue by doing XYZ" and "Fixed accidental regression caused by XYZ" to just the first message. The fact that I also needed to fix a regression is fine being documented in the bug tracker only, since someone looking at a commit diff will spot the extra XYZ related changes anyway.
> Are you sure its considered a no-no? Gitlab has it integrated as part of the PR interface.
Good point. I was careful to say "big" as well as "multi-purpose", because I think most of us are more comfortable with "big" commits than "multi-purpose" commits, and a commit that is both should send off red flags.
Specifically, it's hard to code review multi-purpose commits because you have to think more extensively about the side effects, risks, regressions, etc. for unrelated changes that are lumped together. If it's a small commit, that tends to not be an issue, but if you're touching several unrelated areas in a big commit, it gets really tough. And as a general best practice, you want your code to be easy to review.
At first I read this and thought "well nobody probably thinks that exact thought, but lots of people think they help you avoid mistakes". Then I scrolled down and read a comment that said:
> A couple of those points could be boiled down to "use a strict linter with most of the rules turned on".
I saw someone else on HN use the word "glib", which I think applies here. It has a kernel of truth and sounds good, but there are very obvious reasons why "it passes the linter" is an insufficient condition for good code.
Always interesting to hear someones distilled opinions about what constitutes best practices. There are mainly 2 things I'd personally add: (1) to keep an eye on 'Time-to-Interactive', it doesn't seem to be of concern at all to the author. Also, (2) Npm is a great resource, but I would not reuse components I might find there without some serious research, dependencies can get totally unmanageable.
I think those points could be applied to most languages. My personal favorite is "Make things embarrassingly obvious." I've been programming for nearly 20 years and I can say without a doubt that's one of the most useful things to keep in mind on large scale projects. Keeping things obvious allows me get through bugs, and get the product to the customer faster.
Perhaps this is aimed at very junior developers, but it pains me that "organize your code into multiple files by functionality" is something that must be separately mentioned.
The last thing I want in a project I am working on is for the main programming language itself to be "an adventure'. Software development is hard enough, I don't need anymore "adventures" from the underlying language or tools.
If you look past the first line, it's all just general software development advice and has pretty much nothing to do with JavaScript. I'm not really sure why it's on HN at all.
The author wasn't suggesting JavaScript being an "adventure" was a good thing. If you build web applications JavaScript is pretty much a fact of life. This article provides pretty reasonable advise on how to make it manageable.
- hosting is cool and can help you arrange code more intuitively
- closures are useful
- knowing the actual language itself and not just frameworks is very good
- use a linter and style checker because the language is too flexible if working with a team
- chrome debugging console mastery is a boon
- code preprocessors like grunt and babel etc are annoying but can be useful
- reading the actual language specs is a very good way to be knowledgeable (i never did, but my coworker who did was super helpful because of this)
- using imports and modular patterns is probably a good idea (they got this one, kudos!)
- its very easy to bloat up a project with npm, making stuff yourself is often totally ok, and often very good
- most people do not know the actual language, and confuse frameworks and patterns with the language
- one of javascripts greatest strengths is its ubiquity, you can run programs on any almost any web connected device almost instantly. you can use this to great effect
i write those because i think this article is mostly making points that are generic and dont apply specifically to js. im sure i forgot alot, just freestyled!
Although unit tests are important, I think it is pretty important to emphasize the importance of a static type checker like flow. It is expensive to invest in test coverage, and static type checking is a good proxy to help capture many regressions. Sure its not perfect, but we should encourage it as a "best practice".
>Focus on making things simple, without a need for documentation or comments.
I had a coworker that would love to make super long underscore chains without any comments. Drove me insane. I still find them here and there and break them apart into line by line commented dead simple code.
When I was in a bootcamp we'd do code golfy type things, taking advantage of the newest ES features to shrink stuff way down. Was cool then, now when I see answers like that on stack overflow I'm tempted to repost them "in English."
JS is probably the language most junior devs are familiar with, these days. And, partially due to that, also probably the one with the worst and hackiest real-world practices.
> Angular / VueJS / Ember: when you need a webapp done quick and reliable,
> in exchange allowing a big black-box instead of an architecture.
Here we have the typical "coder" mindset, It's very clear reading these line that the developer has never experienced with those frameworks as both Angular and Vue has very strong and well designed architecture which are obviously open source.
Unfortunately it's very rare these days to find developers that can argue passed beyond "Google Trends Charts" and "Github Stars" about what makes a good or bad framework and why X is better than Y or why X architecture is more efficient than Y.
> React: when you need total control over the architecture
Could the author be more specific here ? I don't remember "Ruby on Rails" to give much freedom in terms of architecture yet it empowers thousands of large traffic web apps without any problems.
It sounded as very common beginner beliefs which is "It's not possible to do this with [Angular/Vue]".
Hence the majority of the article isn't really specific to JS.
I took the more control to mean React gives you more choice over what libraries you want to include in your architecture, whereas Angular/VueJs. are more opinionated.
HTTP call libraries are a good example. Angular comes with HttpClient in the box, and while it might be possible to use something else, Angular is really going to prefer if you makre your HTTP calls using HttpClient.
As I understand it, React does not have a parallel. React shrugs its shoulders and says "use what you want," whether it's just using fetch or some other JS library.
Total control is maybe an extreme way to put it, but React certainly more "fill in the blank" than the other frameworks.
It's supposed to be a bad thing that React doesn't add yet another way of making HTTP calls? There is already a standard way of doing that (fetch). Why should a web framework add another one?
If you are lucky, the thing you will eventually learn about JavaScript is to use either TypeScript, Flow, Elm, Reason, or PureScript.
If you are unlucky, you might get attached too much to design decisions made by Brendan Eich because he didn't have enough time to design the language, and nobody knew how big the web was going to get. Also because statically typed functional programming was so far marred by lack of good learning material and bad tooling. That has changed. Now is the time to get back to start using scripting languages for scripting, and more sophisticated languages for building more sophisticated things, which rich front-end applications definitely are.
Many writings about programming that get popular are predicated on dynamic languages, and thus about coping with them rather than stretching the limits of what you can make the computer do. "Name your variables", "write comments", "use framework X over Y". These things stop being a worry once you let the compiler become your pair-programmer and tell it through types what you're trying to do, and it'll become your safety harness, and the types your tools of thought. Amazing stuff.
I don't understand your point, or maybe it's just the tone.
You seem to be treating "static typing is better" as a fact of life that people working with dynamic languages eventually learn if they're "lucky".
This is completely at odds with, well, reality: static vs dynamic has been going on for over sixty years, essentially since the first days of computer science. You fall in one camp, all the power to you, but it isn't better and doesn't make you "more lucky".
They have their pros and cons and many a paper and book has been written comparing them.
I should've been better with the tone. My view still holds.
I know programmers who've written large swaths of Haskell and OCaml, who however reach for the eminently dynamic Racket for its metaprogramming. They know the relative strengths of each paradigm better than most of us and have fine judgement. However junior programmers (<10 years) who haven't spent the effort required to learn other paradigms and are religious about whatever language they chose to learn as an accident of history are missing out tremendously.
Most of the static vs dynamic type research has always been about C++ based static types (which combines Simula-67's object system with Pascal's types - more history here: https://twitter.com/jasim_ab/status/991948718508130304) contrasted first against LISP and later with languages like Python, Ruby, and Javascript. Statically typed FP is totally different, and there are papers on either side of the bias to point to. I will recommend the Elm Language as a good starting point for anyone interested in seeing what Typed FP truly can be.
Most of the research in static types occurs in the FP community. Even most of the research about OO static types is not about C++, heck, you won’t find much research on C++’s type system at all. Java would dominate from the late 90s, before that it’s a box, but I’m sure there is much more research on even BETA (a language most people have never heard of) than C++.
C++ has and always will be a pariah in the research community.
Hey Sean, thanks for chiming in. Do you think C++ isn't liked in academia because of any bias against languages that are more practical than formal, or anything in the language's nature itself?
C++ is just super hard in its design: it can’t be parsed easily, so for a long time custom compilers were impossible. It’s support for generics was based on was basically macro expansion, it’s multiple inheritance scheme was poorly thought out. It was just painful to do anything with it as a user of the language or an implementer. OOP people were never much of a formal crowd, and they had plenty of niche languages to base their research around (smalltalk, CLOS, Eiffel, BETA, ...).
And when Java came along, acedemics breathed a sigh of relief: finally they could work on a “practical” language that wasn’t totally insane. And everyone else who really didn’t need to be using C++ in the first place has similar ideas.
Complete nonsense. React is not any more complicated than Vue and I think it's significantly easier for newbies to grok than Angular (with some non-trivial anecdotal evidence to back this up). I do not understand where this perception comes from. My best guess is that React scales well to complicated applications which makes people think that's what it's geared for. Maybe I'm lucky that I learned React in the "early days" before this perception was common.