15 ms·
A set of best practices for JavaScript projects
- drinchev 9y ago> Organize your files around product features / pages / components, not Roles: Oh really? Can someone explain why is this a good thing and what's the benefit? [1] : https://github.com/wearehive/project-guidelines#6-structure-and-naming- https://github.com/wearehive/project-guidelines#6-structure-...
- gumoro 9y agoHigher cohesion and modularity. I'm glad to see this in an article for JavaScript projects. Here are a few articles for Java projects, that go in more details (I think the concepts still mostly apply to JavaScript projects): http://www.javapractices.com/topic/TopicAction.do?Id=205 http://www.javapractices.com/topic/TopicAction.do?Id=205 http://www.codingthearchitecture.com/2015/03/08/package_by_component_and_architecturally_aligned_testing.html http://www.codingthearchitecture.com/2015/03/08/package_by_c...
- Softcadbury 9y agoI think this kind of structure is really useful for frameworks based on components (like React), you can just copy/paste the content of these folders in other projects and it will work.
- rsj_hn 9y agoYes, when your project is just a single functional layer -- e.g react -- you can then subdivide your code along feature lines. But the entire codebase will include server side code, DB code, and lots of other code that cuts across functional areas and for which you are going to have a hard time organizing it according to features. Do you put bits of the DB schema definition files/SQL code in there as well? Back end server code? What if it's a completely different team working on that code? What happens when you decide you want a permissions engine or data access layer and need to couple your UI logic to those layers? When you add a replication engine to synch state across different instances, or a dedicated code handling session management, etc. Over time, the code is going to reflect team structure and functional roles rather than features, and you can really organize by features only when there is one functional area -- e.g. a react app.
- lhnz 9y agoIt helps the case in which you want every feature/section of your application to be a smaller self-contained application which can be modularised and loaded into other applications and environments. I think this is the first time I saw the approach: https://github.com/erikras/ducks-modular-redux https://github.com/erikras/ducks-modular-redux
- jrimbault 9y agoUnix tools in general fit this approach ? Do only one thing and do it well, offer an interface to other tools and users.
- underwater 9y agoI'm not so sure that's a good idea. A component is one possible interface to the business logic, but there isn't necessarily a 1:1 mapping. Colocating data logic together makes it easier to build a data model that is logical and consistent, rather than one that is coupled to UI decisions.
- Illniyar 9y agoIt's not a black and white thing, you can have a feature structure for your UI and services, and one folder with just the data models. Sometimes your frameworks kinda force it on you too.
- nickthemagicman 9y agoWow. Came here to make this comment. It seems like the whole point of a model layer is to decouple it from the UI and the Controllers.
- andreasklinger 9y agoyou want to slice your abstractions by domain logic boundaries essentially by "what it does, not by how it does it" eg let's say you want to do notifications for your site. you want to have everything related to notifications within one folder and have the outside connect to it via one api (eg component) in backends this would enable you to easily scale in performance (eg move to microservice or separately hosted instance) or team size (isolation in code, less awareness of the overall codebase "needed") imo the next big web framework after rails will have this setup as a default `app/services` instead of `app/controllers, app/models, app/decorators, app/workers, app/assets, app/views, etc`
- whatnotests 9y agoInteresting point. app/services/signup app/services/signin app/services/newsletter_subscribe app/services/create_report ...etc In larger Rails projects I've been on, we often start with a monolith but then break it into different services to scale out. Starting with different services at the beginning may cause some other problems: what if the boundaries between services was wrong?
- andreasklinger 9y agoif the abstraction was wrong you have the same issues. no matter if you colocate files or not. most likely it is just less of a mess
- saltedmd5 9y agoIn addition to notes in other comments, vertical slicing helps to avoid a tendency for rigid layers to emerge (think the rigid and doomed-to-be-messy Controller -> Service -> Repository "pattern"), which ultimately helps lead to looser, more naturally composed component structures. You can still have files and folders that cut horizontally across those modules (e.g. for things like logging, sending an email, etc. etc.) - in fact, organizing your hierarchy in vertical slices helps to _promote_ good isolation of those cross-cutting concerns.
- Illniyar 9y agocreating or updating a component is usually cross-concern, so if you want to change some functionality in a component you'll have to update it's controller,view,model etc... If they are in the same folder, it makes moving between the relevant files for a feature easier (especially if you have a lot of components and finding the right file in your "controllers" folder means searching through a few dozen files). It also makes reasoning about a certain feature easier - since all the relevant files are grouped next to eachother you can easily move between a feature's controller and it's view. It also makes moving a feature easier- instead of renaming each file separately you can simply move the folder to anywhere else in the structure (for instance if you move a feature from a specific page to something more generic/shared)
- maaaats 9y agoWe always try to think that one folder ideally should be able to be copied to its own project and live on as its own npm module.
- Azeralthefallen 9y agoCan someone please explain to me the rational for shoving your tests in the same place as your code? I have seen this before, and every time i have tried it on anything beyond a simple project it has ended up becoming a nightmare. Often times you have numerous test specific helper functions, and tons of other test oriented cruft, where do all these things go? The root of the project? Also where do tests that encapsulate logic between multiple components go?
- arethuza 9y agoThat's a problem I always have with these kinds of things - when someone says "Place your test files next to the implementation" I always find myself thinking what the reasoning is behind the rule. For that particular recommendation I can see arguments both ways - mind you I keep tests separate myself but I'd be interested in reasons for keeping them together.
- awjr 9y agoI suspect it's an audit trail. You see the set of tests there. One issue is that I think this conflicts with the recommended Component/index.js or Component.js not Component/Component.js I find you do want to find components through your editor (e.g. <cmd>+p in vs code) Finding lots of index.js doesn't help. You will in effect create a Component/Component.js but also use Component/index.js to export the Component.js Also if you use Jest this sort of falls apart.
- baseonmars 9y agoFor me (and the teams I work with) it's to encourage modular thinking - everything is a candidate module that can be extracted, put in source control and shared. For tests that go beyond small (unit/spec) level we have a project level tests folder because these tests make use of multiple modules and it wouldn't make sense to place them closer to the code. Someone else in comments mentioned cohesion - that's another way of thinking about it.
- lhnz 9y ago> Can someone please explain to me the rational for shoving > your tests in the same place as your code? Basically, (1) you are quickly able to see whether a test exists for each file without needing to explore a different directory structure (and therefore it's easy to open the tests for a file), (2) the require/import paths are not like '../../../../../' (which is awkward to reason about) or requiring alias resolver configurations (which are environment-specific and fragile), and (3) you are not maintaining an extra directory structure which could diverge by accident. > Often times you have numerous test specific helper > functions, and tons of other test oriented cruft, > where do all these things go? > The root of the project? Also where do tests > that encapsulate logic between multiple components > go? Modularise and publish any test helpers which are actually general so they can be imported where they are needed. And if they are too specific for this to make sense, why are they being shared? Tests which encapsulate logic between multiple components should be next to the file in which you implemented this logic. If you're still unsure on how this is possible, investigate a large modern JavaScript project [0]. Many of these are successfully implemented in exactly this way. There are always edge-cases that go against what I've said, but in a big enough project you will also be able to see this. [0] https://github.com/facebook/react/blob/master/src/renderers/art/__tests__/ReactART-test.js https://github.com/facebook/react/blob/master/src/renderers/...
- zer0tonin 9y ago> Always use //todo: comments to remind yourself and others about an unfinished job No please don't do this, no one will ever do the todo. The code base I'm currently working on has more than 2000 todos. Instead of this, create a ticket in Jira, Asana or whatever issue tracker you prefer. This way it can be easily taken in account when doing a sprint planning and even if no one opens the problematic file ever again, the issue will still be visible.
- lhnz 9y agoOn the other hand, if you are using `TODO` comments within your code, a good idea is to place something like the `fixme` CLI [0] into a prepush hook [1] so that it is always highly visible. The length of this output then acts as an intuitive measure of accrued technical debt and can be leveraged within a team to get time to fix the underlying problems. [0] https://github.com/JohnPostlethwait/fixme https://github.com/JohnPostlethwait/fixme [1] https://github.com/typicode/husky https://github.com/typicode/husky
- underwater 9y agoA variant I've seen is //TODO(#7362) where the number is a ticket and is enforced by a lint rule.
- marksomnian 9y agoThis is a really good idea.
- sturmen 9y agothis guy gets it
- vahidpg 9y agoThat's a great idea
- CTrom 9y agoThis is what I have found to be a great compromise for my team. Some like todos, others want tickets, so we enforce/support both.
- cottsak 9y ago_facepalm_ ugh! Gitflow again! Get on board with Github Flow people - it's going to save you so much pain
- larzang 9y agoAssuming you have a CD pipeline, sure, but many of us are still stuck with companies following a traditional structured release model, in which case Gitflow still makes a lot more sense.
- yoz-y 9y agoFirst time I hear about the Github Flow but from the presentation page it does not address any of the basic needs like having several concurrent branches, releasing versions, their maintenance... Is this only adapted to webservices?
- okket 9y agoAnd this is why I like opinionated frameworks like Ember.js so much. Most of the best practices are baked in. Plus you usually do not encounter a random subset of 'best practices' with added personal preferences/exceptions in other peoples projects, making collaboration much easier.
- rsj_hn 9y agoThis is a mishmash of coding standards (at ABC CO we use tabs!) randomly sprinkled with best practices. It's important to standardize on things without one way necessarily being better than another. The organization also seems a bit rushed. For example, not exposing the DB schema in a URL shouldn't really go into the section on encoding. Moreover, SQL injection is almost never fixed by using an escaping function, as by far the most common problem with SQL injection is letting the client specify field and column names, or things that aren't quoted (e.g. numerical id's) and so don't benefit from escaping. I don't want to discourage any company from setting and documenting coding standards, but this particular document feels a bit rushed and could use adherence to best practices of its own. For example, 1. If making an opinionated mandate, provide a link to an explanation 2. Consistently provide links to examples 3. Maybe do some spell-checking: "Hallo"? 4. Try to maintain a uniform level of specificity E.g. in the section on URL security, there is this vague comment: "Attackers can tamper with any part of an HTTP request, including the URL, query string," Which, while a true, doesn't describe what the programmer should or shouldn't do. It's just hanging there. Compare with the weird specificity of listing git commands in section 1. That tells me the author knew a lot about checking stuff into git, but was a bit out of his/her league when it came to Security, so they just made generic security statements while giving precise instructions for using git.
- th4dv 9y agoA lot of companies these days create "Best practices" guidelines just to boost their online recognition. Very often I find these guidelines useless or even harming.
- magic_beans 9y agoWhat in this document do you find useless or harming?
- camus2 9y ago> What in this document do you find useless or harming? The use of TC39 proposals IN PRODUCTION. The authors of that document aren't serious.
- znpy 9y ago"Tools, not policies". I must say, this page reminds me of how lightyears ahead Perl was/is in terms of tooling. For example: are you coding a package? Before even starting brainstorming, just boostrap your package with ExtUtils::MakeMaker. Long story short, that package will boostrap a mostly blank (but customizable via various command-line switches) Perl package with most things you will need for development and distribution: a directory structure, a Makefile (for building and installing), some pre-set comments, mostly blank test files etc etc. This is something that, for example, the Go programming language team has rightfully picked up in terms of directory structure conventions and tooling (gofmt).
- mattacular 9y agoIt is a shame you have to adopt one of the larger frameworks like Angular, React, or Ember to get some tooling like this. And certainly "gofmt" is sorely missed in every other language I've used since!
- grenoire 9y agoJS ecosystem tries to do that by having bootstrapping repositories. Although I will have to say that it is nowhere near as high-quality and convenient as Go has it. Standardising best practices most often seem too restrictive to programmers, but Go has done an excellent job at drawing that line and staying behind it.
- lol768 9y ago> I must say, this page reminds me of how lightyears ahead Perl was/is in terms of tooling. When Perl has such a mess of a syntax that its meaning is ambiguous to any static parser, I find it difficult to believe Perl has such amazing tooling - JetBrains for one refuse to implement any official support for it (see https://youtrack.jetbrains.com/issueMobile/IDEA-87976# https://youtrack.jetbrains.com/issueMobile/IDEA-87976#).
- Afton 9y agoThis seems like an unrelated dig on Perl. There are many things that Perl did better than any contemporaneous language, all while having an ambiguous static parser.
- sAbakumoff 9y agoA set of best practices? It rather looks like a set of random thoughts.
- ricardobeat 9y agoHow do you collaborate on a branch using this workflow? The constant rebasing means you can't have multiple devs pushing to the same branch.
- saltedmd5 9y agoThe ironic thing about this is that the link they post as a justification for rebasing feature branches onto develop is actually a very explicit reason _not_ to be rebasing in this situation. The section reads like the author thinks that the problem with rebasing public branches is merge conflicts (it isn't; it's rewritten/diverging histories) and that interactively rebasing somehow resolves this problem (it doesn't). This smacks of something that I come across all the time: strong opinions on how to use Git held by people who don't actually understand Git.
- rockostrich 9y agoCreate a feature branch. All collaborators branch off the feature branch and PR into the feature branch. When the feature branch is ready, make a PR into develop. The problem with this workflow is that it prevents rebasing unless someone rebases the feature branch manually. You would have to make a merge commit to follow this workflow safely.
- camus2 9y ago> Place your test files next to the implementation. ok. > A resource always should be plural in the URL. Keeping verbs out of your resource URLs. What does it have to do with Javascript projects? > Avoid js alerts in production alert is a DOM API, it doesn't have anything to do with Javascript. - Barely anybody pointed out the fact that this "guide" mixes up things that have nothing to do with each others. How is file organisation related to how one name "subresources" in a rest API or browser alerts ? it isn't. This isn't a serious document. It was hastly put together with no real considerations whatsoever and named "best practices" without any sources or links to give weight to these opinions. Finally, as I said multiple times, coding style guides, "best practices" that cannot be validated automatically on a CI server are worthless and a waste of time in an business environment.
- sAbakumoff 9y ago> 9.2 Operating on resources Sure, let's pretend that GraphQL is not a thing. Yep.
- weego 9y agoOther than for a proverbial handful of people in the world, it isn't
- sAbakumoff 9y agoI am a little bit more optimistic about it..I mean GitHub has recently introduced the GraphQL API..I guess that other SaaS's will follow - twitter, reddit, HN(or probably not) and so on.
- vahidpg 9y agoWe haven't developed anything with GraphQL yet. I wasn't even sure if there are best practices out there. If you have a link that lists them, I'd happily put it in the doc. You're more than welcome to make a pull request as well.
- always_good 9y agoSarcasm is the laziest way to present an idea. Why not just say what you mean?
- sAbakumoff 9y agoOn the other hand sarcasm is the gentlest way to criticize an idea :-)
- a_humean 9y ago"Use stage-1 and higher JavaScript (modern) syntax for new projects. For old project stay consistent with existing syntax unless you intend to modernise the project." That seems doesn't seem like a good idea. I can understand recommending Stage-2 and/or Stage-3, but stage-1 seems premature. Stage-1 in the TC39 process is still proposal stage that is flagged for expecting "Major" changes in the spec and possibly the syntax of the feature. Being stage-1 also is a poor guarantee that it will progress to future stages or become part of the spec. Stage-2 at least signals that the committee think its likely to eventually become part of the spec with only minor revisions.
- vahidpg 9y agoYou're actually right. I will change that to stage-2. Thanks for feedback.
- vahidpg 9y agoHi guys, I published this document. Here at http://www.wearehive.co.uk http://www.wearehive.co.uk we work with different developers with various levels of experience. We had to come up with a set of rules to bring some consistency to what we produce and make it easier for others to pick up and maintain it. It does look random and it's not perfect, that's why we decided to make it public and receive some feedback. I've already made notes from some of these comments. If you think something is wrong and shouldn't be there, make a pull request, or just let me know if you're too busy to do that.
- YCode 9y agoOne issue that is sort of addressed in this that I've been trying to find a solid answer on is how do you strongly ensure a given NPM package and its dependencies are safe to use? So far the only real solution I've come up with is to do a signals review (github? issues? downloads/day/ etc...) and then review the code block by block carefully examining any complex or potentially dangerous code. It works, and you learn a lot about the packages and why they depend on each other, but at the same time this process is exhausting. What would be a godsend is some major security brand who can vouch (even at cost) for a given version of major packages including their dependency tree.
- joshrivers 9y agoAre you looking for something like https://snyk.io https://snyk.io ?
- jroseattle 9y ago"While developing a new project is like rolling on a green field for you, maintaining it is a potential dark twisted nightmare for someone else." There is nothing about this list of best practices that makes any applicable project more maintainable without understanding the practices being followed. As long as these practices are well-known within the company and enforced over the lifecycle of code/product/project/etc., it will succeed. Without that understanding, this list eventually becomes untrusted. Good on the folks at hive for following what appears to be solid practices in their JS projects.
- vahidpg 9y agoThanks, for your comment. I do agree that "best practices" isn't the best word. I probably should have said, "Hive common practices". Most developers have understanding of the process but just have a different taste and styles, we just tried to make things more consistent. We thought having such a document is better than not having it, and even if a developer doesn't understand the practices being followed this document brings an opportunity to learn them. I know it's not perfect and looks abit random, that's why we made it public to get some feedback.
- jroseattle 9y agoYep and understood -- it's what works best for your team. And yes, consistency is where the value lies. I've found these efforts to be successful as long as those guidelines are socialized among the team and it's treated in a consistent manner. Looks like a great list thus far!
- mattkenefick 9y agoThese practices aren't even good.
- baron816 9y agoI can't say if these are the BEST practices for JS, or if even such practices could exist. But I do think that every company should have a standard set of written out practices/guidelines and publish them. They should probably even include them in their job listings. I hope people will comment on the potential pitfalls of doing so, but a benefit would be that new and prospective engineers would have a clearer idea of what writing code for the company would be like.
- quotha 9y agoThe very idea of rebasing in git, it just gives me the creeps
- wry_discontent 9y agoWell that's fine, cause I think merging without rebasing is gross. I want to commit when component x technically works, when I've improved it, when I've renamed crap, all the time. I only need those to be 1 commit and after that I can write a nice message that covers what it did. My process for developing the code should be separate from the organization used to store it historically for others to see.
- Spivak 9y agoIt seems like you're talking about squashing, not rebasing.
- flavio81 9y ago> "Only use nouns in your resource URLs, avoid endpoints like /addNewUser or /updateUser . Also avoid sending resource operations as a parameter. Instead explain the functionalities using HTTP methods: GET Used to retrieve a representation of a resource. POST Used to create new new resources and sub-resources PUT Used to update existing resources PATCH Used to update existing resources. PATCH only updates the fields that were supplied, leaving the others alone DELETE Used to delete existing resources" This used to be hip and cool and "look ma, i'm modern, i'm doing it REST-style!", but i don't think the fad holds anymore. In real life, you are going to do much more "operations" to a "resource" than just "retrieve", "create", "update", or "delete", and thus you need to use operation names. It makes more sense to always send the operation name and to standarize on operation names. Also operation names can be more explicit and unambiguous. It is, for me, a very bad idea to mix up your business model semantics (actions performed on the business model) with the semantics that belong to the OSI-model application layer (HTTP methods: GET, POST, PUT, PATCH...).
- partycoder 9y ago(Removed this comment as it was incorrect)
- yes_or_gnome 9y agoNo. HEAD is the same as GET, but the server should not return a response body. The response code and headers should all be the same. This is to guarantee that a path is serviceable, response body size, and for verifying the client's cache.
- partycoder 9y agoYou are correct, sorry about that. Removed my comment to not spread incorrect information.
- HatchedLake721 9y agoDo both together. Use GET/POST/PATCH/DELETE for the simple CRUD on the resource. Then, put your actions under POST /resource/{id}/actions/{action}, e.g. `/repositories/1/actions/archive`, `/users/1/actions/ban`, `/customers/1/actions/credit-score-with-bank-of-xyz`, etc
- deadwisdom 9y ago"Keep README.md updated as project evolves" Sure man.
- pdog 9y agoIf you want a single best practice for working on maintainable JavaScript projects, here it is: Use TypeScript.
- Spivak 9y agoI don't think the author would disagree. Using a compile-to-JS language with stronger correctness guarantees is valuable for large projects.
- tieTYT 9y ago> Place your test files next to the implementation. Java background is probably biasing me, but I don't like this. It interferes with my ability to find code because the file list in every directory is twice as large. What are the benefits of putting it together?
- jaywunder 9y agoAs a node developer I agree with you, I think the benefit with nice might be that relative paths are shorter in node imports?
- epicide 9y agoKeeps things that are coupled closer together. This is beneficial for several reasons: a) forces parity between your code structure and test structure. b) restructuring takes potentially half the time. c) easily see and navigate to tests for a file. d) less named things in your project since you aren't duplicating your structure. If your directories are getting too lengthy to look at with tests in them, you should restructure them. Edit: formatting and additional reason.
- dntrkv 9y agoIf you are creating a separate directory for each "module" then it would just be one more file in each directory. Component - index.js - Component.js - component.scss - Component.spec.js This structure has worked really well for me, you have everything you need in a single directory so you don't have to jump around to another directory to find the test or styling or whatever.
- BinaryIdiot 9y agoPutting them together is AMAZING. So when I used to do Java development I thought the organization was great but every time I had to find a unit test I had to dig through a folder structure. Then I tried GO. GO puts them together. I was amazed at how such a simple concept could keep my code so much better organized. I could immediately open both the code and the unit tests for said code. Just don't put a ton of files in any one directory (if you have a lot of files in a directory you're actively coding it I'd argue your file structure is not optimal). Now when I do JavaScript development I have adopted 3 extensions: - .aspec.js is for unit tests that should work in all environments - .nspec.js is for unit tests that only work in node.js - .cspec.js is for unit tests that only work on a client like a web browser If you're board you can poke at some of my open source projects that use this pattern https://github.com/KrisSiegel/msngr.js https://github.com/KrisSiegel/msngr.js
- nscalf 9y agoWell this is definitely one way to do things... The reality of it is if you're making a project, and everyone is on board with the standards of how to do things and it's not making it unnecessarily confusing, you're practicing good coding. For example, if you have your tests isolated to a testing folder vs in a product/feature folder and everyone is on board, then it doesn't make any difference. I'll just look in the test folder for the tests rather than the feature folder. Honestly, I don't get the obsession and combativeness around "best practices". Best practices are whatever your team uses effectively to get shit done.
- Principe 9y agoI hadn't noticed before but... Please do not recommend that people use "stage-1 features". Maybe if it is your own money, but not if you do it with other people's money.