a hundred things i learned working on the react team @threadapalooza
1. every few years your audience changes. new users don’t appreciate problems of the past bc never seen them. old users burn out or lose excitement. new users have different reference frame, learned in diff ways, you might be their first programming env. plan accordingly.
2. when you fix a problem you better really really understand the problem you’re fixing. take a few steps back and reintegrate new knowledge into the design. should it change the design? it’s like fighting a hydra: solving a problem in the wrong spot spawns 10 new problems.
3. most PRs create more work than solve. even when the project’s internals are well-documented (which for us was brief), significant contributions are rare. this is not so much because of difficulties writing code but due to months worth of context needed to make decisions.
4. for libraries, make sure your PR descriptions are great (they become squashed commit messages). for apps, include product videos before/after and urls you were testing in PR descriptor. someone (me) will thank you eight years later when diagnosing a bug or planning a change.
5. a couple of trolls, even well-intentioned, can poison an entire discussion space.
6. write tests against public API instead of unit tests for internal implementation modules. then you can fearlessly rewrite the implementation using tests for verification and guidance. you can even keep both implementation versions at the same time and run tests against both.
7. long-running branches suck. merge into main and keep it behind a feature flag. invest time into a good feature flag mechanism that cuts out dead code and/or lets you deploy feature flag changes for % of uses in prod experiments.
8. if a change shows up red in metrics, maybe you made it slower. but maybe you introduced a bug which broke some interaction for %. or maybe you changed how metric is logged. or maybe you fixed a bug and metric was overreported before. metrics are hard.
9. many people want to score a PR in a popular project so that it appears on their gh. somebody will convert if-else to early return. next day somebody else will send a PR to convert it back. it doesn’t hurt to merge until you miss a mistake in the middle of a “stylistic” change.
10. if you fix something, add a test that fails. if you don’t add one, you’re tacitly agreeing that someone else (including you) will break it again.
11. your writing in project blog/docs will be copy pasted verbatim, rephrased, adapted, and then posted on content farms, other people’s personal blogs and slides. in a way that’s actually kind of cool because this means your writing worked
12. some projects have wide surface area and decisions can be decentralized. other projects have narrow surface area and decisions need to be centralized. both styles are ok, just don’t get confused why techniques that work for one type of project may be disastrous for another
13. keeping github clean is nice but for each individual person on the team there’s almost always something higher-value to do. that’s ok and you don’t need to feel bad about it. it’s much more important that your software works well. if it becomes dire you’ll know
14. nevertheless it’s invaluable to do occasional github issue sweep and read/triage every thread. you’ll get a window into the pain points and confusion that is hard to build up otherwise. that alone is worth the time and effort
15. with some PRs it feels like the person really knows what they’re doing. reach out to them. they might be your future teammate
16. if you don’t explain the story about what you’re doing and why, someone else will do it for you (and you might not like it)
17. be careful with what other projects you recommend and endorse, they might be the very thing that holds the entire ecosystem back in a few years
18. if there is harsh feedback, it is better to hear it from a kind person. unfortunately a kind person will often keep it to themselves, while a troll would shout about it. making it tempting to dismiss. validate harsh feedback with kind people and keep the door open for it
19. don’t DM with a troll. it’s a waste of time. don’t get dragged into twitter feuds. not enough space for nuance. redirect discussion to a technical long-form space. keep DMs for friends and people you trust
20. don’t throw inside DEV-only code. this makes some branches reachable in production but unreachable in DEV. so you might actually have *worse* problems than crashing in prod, like a privacy compromise, and none of the developers experienced it on their machines due to throw
21. when you write a tutorial, sit down with someone from your target audience and have them walk through it. they’ll stumble in five different places than you expected. you’ll tear your hair out and make the tutorial 5x better
22. some for the nicest, kindest and most amazing people you’ll meet and hang out with will be the people working on the competing projects
23. when you deprecate an api, don’t put a tombstone in your slides. this is tempting and might be funny to you as an author but categorically a wrong move
24. big rewrites can work if you know what you’re doing. make sure you know what you’re doing though
25. lock down introspection APIs and keep first-class tooling that uses them colocated. this ensures you’re not locked out of major internal changes by a long tail of tooling that assumes something about internal data structures and has become unmaintained or is incompatible
26. a crunch with a few weeks of overworking can be emotionally fulfilling when the team is in the flow state. a perfect work/life balance while team morale is low and dynamics are thorny can feel like a piece of your soul is flushed down the sink every day
27. innovation is not linear. sometimes you need to make it worse to make it better.
28. expanding on that, when you replace a system, you usually need to go incrementally. otherwise it’s too much risk for stakeholders to go all-in. but that means you won’t reap the benefits of *replacing* it until the end. you’re *adding* so likely regressing. set expectations.
29. let users try a new thing one piece at a time. even if you want them to use it everywhere, let that be *their* idea
30. if you can’t prove out a migration strategy with a small team on a big codebase, you don’t have a migration strategy. start again
31. the most important principle in API design is that it composes well. that means that if two people create two things, they need to still work well together combined. it also means you can delete one of them later without breaking the other. or copy and paste it to isolate it.
32. you will see the most bizarre feature requests. don’t dismiss them outright but ask why they’re trying to do this. a lot of use cases are actually legit and food for thought. eventually you run out of new ones — you’ve covered the entire problem space. consider solutions
33. if something doesn’t make sense, no amount of documentation or explanations will make it make sense.
34. people will copy and paste every code snippet you write. even the ones marked with “don’t copy paste, this is the bad example, the good one is below”
35. your personal social media account shouldn’t be a primary source of truth for news in a mature project. people will get FOMO plus it’s legitimately hard to track. you can repost but keep news in official sources (like GH)
36. even if someone is a great developer or a good friend, it still doesn’t mean they’ll necessarily succeed on your team. this can be gut-wrenching for all parties when it doesn’t work out.
37. if you accept and merge every individually reasonable clarification that someone sends as a PR to your docs, they will become a sorry unreadable mess
38. people *love* to hit the Accept button on someone’s PR even if they never contributed to the project and never left a single comment on it. it’s just a thing people do
39. occasionally, it’s good to take the minified code, run it though Prettier, and quickly read through it. you might spot things that shouldn’t be there, things that could be minified better, or get ideas on how to reduce the size
40. if you’re trying to introduce a new workflow (eg different task tracking tool) to the team, it’s on you to get people to feel good about it and try it out (“i know you prefer keeping tasks in a doc, let me sync that doc for you for a bit and we’ll see how it goes”)
41. taking ownership over something unowned (but that everybody cares about) is one of the most valuable things you can do on a team. try not to drop it though (i’m guilty of that)
42. when the code serves a particular purpose that’s too high-level to be seen from the code, write it down as a comment. long-ass ten line comments are good if they add context to the code (rather than describe what it’s doing)
43. re-running a test you’re actively iterating on after a file change shouldn’t take more than a second
44. write a script to do releases for you. get the CI to create automatic prereleases from main so you can always test the latest main in codesandbox (and other libs can run tests against nightlies). a stable release should patch+promote a CI version, not build locally
45. your teammates can literally move mountains
46. when you work on your messaging, run it by people. use it many times in narrower circles and widen slowly. close the gaps using feedback so that by the time you have final messaging, it’s the parts that resonate, are easy to understand, are easy to quote, and (!) make sense
47. if your technical vision is sound in theory, and you chip away at the practical obstacles with perseverance, organisational support, pragmatic compromises, and optimism, eventually the theory wins
48. if you have one scary bug after another, write regression tests but also use this as a signal. something in the model might be broken. complex code isn’t bad, but code built around a flawed model is very bad, complex or not
49. all people are irreplaceable. every iteration of a team is a new team in some sense. in some ways this is poignant, in others this is exciting
50. naming is one of the most important decisions you will be doing. it’s not just bikeshedding. give it appropriate time and effort. you will mess it up anyway though.
51. you keep hearing complaints about an API. the fix is simple, like flipping a switch. fine!! you change it. suddenly, the other half, previously quiet, comes frustrated. oops. turns out both options were equally disliked. congrats, you’ve just churned your users for no reason
52. semver is “just” a social contract. yes it’s important to communicate intent. breaking changes shouldn’t go into minors/patches. but even fixing a bug is a breaking change for someone relying on the buggy behavior. semver is first and foremost a human communication tool
53. you are not your project. it also seems unwise to pretend that it isn’t in some way a significant part of your life. not “work hustle 4 da boss” capitalism thing but more like “regardless of power structures i’ve put a lot into this and i have reasons to care”. that’s valid
54. most things don’t stick around long enough. you’ll now read most of the “announcing X, a new way to Y” with a 2-3 year flash-forward “X is legacy” in mind. be gentle or people will read this as being cynical. also some things *will* stick around, either in a good or a bad way
55. edge cases are your bread and butter. they’re more common than you think (with enough usage anything happens) and they are a first-class part of your design. you should have satisfactory (if not satisfying) answers to how the system behaves even (especially) when it’s wonky
56. it’s better when issues reproduce consistently. but if some bug caused by API misuse in product code is non-deterministic and happens less often than random typical existing bugs in the product code, it’s below the threshold of rethinking the design
57. thought experiments are your main tool as an API designer. “imagine a tabbed view…” “imagine a combobox…” “suppose we have a feed and a profile…” is how many breakthroughs begin. you start with a situation, think through ideal behavior — from user and system point of view
58. that clever optimization? probably unnecessary and will cost you a few weeks of bug hunting. oh, and good luck ripping it out
59. introduce some slight inefficiency in a hot path, and clicking every button becomes 10% slower. do that several more times and you’re 100% slower
60. constraints and edge cases drive your design. constraints exclude 99% of possible designs. edge cases accentuate the remaining choices and help you pick which one sucks the least (or least surprisingly). then if the common case makes sense you’re golden
61. if you’re not sure between recommending two approaches, wait it out. it might be because you don’t know all the constraints yet. it’s like solving nonogram puzzles. as you solve problems, they fill out the constraints for other problems. at some point only few options work
62. it’s unwise to put all effort into optimizing a fixed cost of library code if the cost of user code is unbounded. ignore benchmarks that focus on how fast the 5% of a realistic app runs, and focus on making 95% you don’t own faster. this doesn’t justify being sloppy though
63. if you go on a panel with a competing library maintainer and talk about an upcoming feature in your release a few months away, there’s a high chance they will ship a similar feature next week. that’s only fair
64. you will build for people who are excited to use your project. everyone’s jazzed. then you’ll notice a flood of people who hate it. this is because the people who were excited to use it are now forcing other people to use it (oh no) also now there’s a job market, congrats
65. your goal isn’t to make every app use your library. it’s to make other libraries copy the ideas you value the most. then your work won’t be lost because it’s upstreamed to the global programming consciousness. the failure case is good ideas dying with your code
66. look out for inspiration outside of your direct competitors. your direct competitors are looking at you too so at some point there’s a deadlock for fresh ideas
67. innovation looks like synthesis of existing ideas with a novel twist. it doesn’t happen often and it’s easy to miss if you’re not paying attention
68. people like to optimize something that they know how to optimize and where there’s obvious progress. there will never be a shortage of people excited about replacing a 5 KB library with a 2 KB library
69. designing is not so much creating as it is uncovering what already should be there. like math or archeology. it’s exploiting the properties of the system and making them shine
70. “how it scales” matters for technology adoption by small shops too. this is because if it doesn’t scale to big shops, there’ll be a competitor that scales *and also* works well enough for small shops. the solution that’s good enough for most people will wipe out yours
71. invoking “simple vs easy” as an argument in an API discussion works great if you have the design sensibilities of rich hickey. otherwise it’s just a sparkling HN comment
72. people have opinions on everything. even if you’re unable to handle the volume or respond individually, it helps to provide a void to shout into so that people feel heard, the discussion is consolidate, and doesn’t spill out into random platforms. then you can revisit it
73. much of Programming Discourse is shaped by people who aren’t shipping production code and have lost touch with the reality. get used to it and carry on. oh by the way… you are one of those people now
74. people arguing about applying abstract code patterns on Twitter means you’re failing. the wise API designer would empty their users’ minds, fill their bellies, weaken their wishes, strengthen their bones…
75. “no” is the correct answer to most feature requests. no matter who they’re coming from. try your best to help people though and bring the pain points back to the table. this is developer advocacy
76. “try harder” sounds too harsh as a motto and can be misused. i’d say, “peek around the corner”. it’s okay to stop when you’re stuck. but make sure you didn’t just give up on the last few steps to the solution because you ran out of hope
77. there are few forms of communication more powerful than a tech talk. it’s like carving out a meme out of stone. use this medium thoughtfully.
78. experimental/research work and content should be branded separately from the stuff people need to know and can use today.
79. eager vs lazy: both suck. eager sucks because you do more blocking work upfront that may not be used. lazy sucks because you start work too late. “eager non-blocking” is best. start optional work asap but you can drop it midway or downprioritize it if it’s not needed anymore
80. it’s often more valuable to have someone who “gets it” in partner teams than having that person on your own team
81. don’t compromise on core principles and properties of the system for the sake of convenience. convenience helps narrowly, but core principles will keep on giving for years in ways you didn’t expect. it’s nice when you can have both though
82. “i don’t know” and “i don’t understand this part” and “can you say this again” are phrases you should expect to say (and hear) in productive meetings
83. you need to create space for design discussions that isn’t crammed into a regular sync meetings. most enlightening discussions i’ve seen are free-flowing, didn’t have a predetermined agenda, went into rabbit holes, and needed a few hours to get to a conclusion. write it down!
84. failing is ok but you want some lesson carried away from it. so that the next person who tries has a chance to mitigate the same issue proactively. failing comes with a cost: it’s harder to justify doing same project again. better to wait out than to try at a wrong time.
85. the best features are vertically integrated. that means that they don’t just work at a particular level of the stack but pierce through the whole stack and give you some leverage at every level, low and high. they’re also integrated together: they all compose as you’d expect.
86. don’t cut a stable release or deploy the website on Friday unless you’re doing this intentionally. for example if there’s a big codemod and you need to land it while nobody else is pushing conflicts
87. global configuration like React.setOptions() is a bad idea. this is because components on npm written assuming one set of options wouldn’t wotk with the other set of options. so global configuration breaks composition.
88. people can handle bad news but people hate surprises
89. the way each person thinks makes a lasting contribution to the team. “what would X do” is not only a useful question that X can answer but also a way to nudge our own thinking for years going forward
90. an autocomplete has one chance to reorder per keystroke. if you got it wrong and you have a better ordering a bit later you must “swallow the sadness” (as per the original author of this wisdom) but never change already dispalyed items
91. if you have two similar APIs and you’re worried people will overuse A instead of B (which is actually better), give A a clunky name and make B nice and short
92. if you plan to change the paradigm, do it in a minor release
93. sometimes your thing sucks but you don’t know the solution and don’t have anything that helps move it forward. you have to learn to get comfortable with something badly sucking for years. just make sure a workaround exists
94. re-read every release post imagining that you’re drunk and your attention span is zero. if the message still lands you’re good
95. carrying messaging directly from a small team to the community doesn’t scale if the messaging is complex and nuanced. instead it is helpful to have a buffer of trusted folks who can learn the ins and outs, become experts, and participate in those panels
96. the best task management system for a release is long-ass quip doc (or gh issue) with a freeform checklist. we call these “umbrellas”
97. never assume you know others’ emotional states. if you don’t ask, you might not hear some critical information until it’s too late
98. it’s all about the people. if relationships are frail and people don’t trust each other, projects fail. technical wiring directly reflects which teams trust each other. poor communication produces broken systems. screw the org chart and go talk to the ICs directly
99. newer people on the team won’t know the norms if you don’t tell them. if reviews are slow in general they might think they specifically are being ghosted. be explicit about everything and always follow-up on how they feel and what’s concerning them
100. it is incredibly rewarding to learn directly from people whose expertise and experience vastly eclipses yours. i am thankful to @sebmarkbage@sophiebits@tomocchino and many others who i’ve learned all of these things from!
on this note, i’m sad that i won’t randomly run into @sebmarkbage the next time i visit the Meta office but i am excited about his renewed focus on the React ecosystem in his role at Vercel. this is a big deal and i hope it strengthens the case for multi-company work on React!
i feel bittersweet sharing i’m leaving my job at meta in a few weeks. working in the react org at meta has been an honor. i am thankful to my past and present colleagues for taking me in, letting me make mistakes, helping me see my strengths, being kind, and sharing their time.
for the past three years, i kept saying i’d leave “in a year or so” but the moment never felt right. i wanted to (1) finish the new docs and (2) see a broadly usable Suspense data fetching integration shipping. after years of work from the team, both have shipped this spring.
i felt hesitant leaving earlier because not too long ago, leaving meta used to mean leaving the react team. that would feel too sad for me. but it is not true anymore. react has become a multi-company project, and there are several independent engineers on the team too.
fwiw i expected the article to be clickbait (and the title is) but it’s actually pretty balanced. imo it gets a few things wrong so i’ll provide an alternative perspective (tiny thread)
the framing of “existing features like useState / react-query / CSS-in-JS don’t work” is misleading at best.
to understand why, consider that here is the React you already know…
… in the RSC paradigm, all of these things keep working! we are not *replacing* that layer — we are adding a *new* layer that can run at the build or request time. that’s Server Components. the only thing they can do is pass data to the “React you already know”…
yeah i thought this was nice. idk if “spatial computing” will catch on or will stay as an apple-esque “we’re too good to use the industry terms” thing, but i thought it’s funny that this launch simultaneously validated meta’s bet *and* made meta’s branding feel instantly obsolete
mark’s meta announcement felt corny because they had to come up with a vision of mainstream aesthetics for a medium that has no mainstream community yet. of course it’s not believable! apple stuck with floating 2d stuff in the presentation because it feels familiar.
i think this is great news for meta too. i imagine it will be easier to motivate sweating the details and making them cohesive after apple resets the expectations of what this medium is supposed to feel like.
curious what the actual apple vision (not pro) looks like
vision is such a dope name for a product. focuses it on the human (what function does it serve you) rather than on the place you’re supposedly in (whatever reality). “apple vision” also kinda says “this is *the* thing we’re working on”
i mean i sorta get the point but also if a ballpen wrote stuff by itself and contained much of humanity’s collective knowledge within, maybe people would have a point being a bit more concerned about ballpens too? it’s more like a phone line with an alien made out of our voices
which is maybe fine, who knows! the internet is pretty good imo and it sure sounds a lot more dangerous than a ballpen. but like idk it’s just such a freaky vibes piece of technology, both natural and freaky like golems or acid. you don’t see language itself reanimated every day.
the closest positive emotional reference i can think of is something like talking to ancestor spirits. and even those stories typically have preexisting oracles instead of groups of people competing to discover and create them. it’s freaky
real talk. modern frameworks like Next.js and Gatsby have sort of an “SPA mode”. the main difference is with classical SPAs is that they produce several entry HTML files (per route). this means a purely static (not Node!) deploy needs a tiny URL -> path config. this trips people.
we need to get past this hurdle collectively. it is ridiculous if this is the reason we’re delaying adoption of better tools. SPAs with multiple HTML entry files are much better SPAs! we just need some standard way to deploy these across providers.
ideas welcome. i know there are scripts that generate config eg for nginx and apache. cool. i also know some providers infer these paths by default for next and gatsby. also cool. but can we have one obvious way to do it across the ecosystem? so that every single shop knows how.