Skip to content

Build1 publisher3 min readPublished

Fifteen hours per developer, none of it spent on the product

One developer's onboarding diary puts a number on template friction: a README that disagrees with the .nvmrc, three correct auth patterns, and a deep link that cost eight hours.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Photograph accompanying Fifteen hours per developer, none of it spent on the product
Photo: atlassian.com

What happened

  • The author onboarded two junior devs onto a React Native app last week using the same Expo starter template; both had shipped web React apps, neither had touched mobile, and the author kept a diary of every friction point.
  • Total avoidable loss was roughly 15 hours per developer, which the author says was all fixable with docs and one shell script; the first week was dominated by problems the template could have prevented rather than by the problem the app solves.
  • Environment setup was estimated at 2 hours and took about 5 hours per dev.
  • One dev had Node 20 and one had Node 16; the README said "Node 18+" while .nvmrc pinned 18.17. Nothing surfaced the mismatch; things just failed oddly downstream.
  • Missing Xcode command line tools were silent until expo run:ios errored with a message mentioning xcrun and not what to install.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A developer writing on dev.to onboarded two junior devs onto a React Native app last week, both from the same Expo starter template, both with web React experience and no mobile, and kept a diary of every friction point [1]. The tally was roughly 15 hours of avoidable loss per developer, which the author attributes to documentation gaps and one missing shell script rather than to anything the app does [2]. Environment setup was estimated at 2 hours and took about 5 per dev [3]. The first cause is the one worth framing: the README said "Node 18+" while the `.nvmrc` pinned 18.17, one dev arrived with Node 20 and one with 16, and nothing in the toolchain surfaced the mismatch, so things failed oddly downstream [4]. Note what that means in practice. A developer running Node 20 satisfies the README and violates the pin at the same time, and no check in the repo has an opinion about which document wins [1]. The other three followed the same shape: missing Xcode command line tools stayed silent until `expo run:ios` errored with a message naming `xcrun` and not the thing to install [5], a CocoaPods version mismatch stayed silent until `pod install` failed four layers into a trace [6], and a wrong Android SDK path hit both devs as `expo run:android` failing to find `adb`, fixed by setting `ANDROID_HOME` in the shell profile [7]. The author's diagnosis is that in all four cases the failure surfaced far from its cause, and that this is the property that turns a five-minute fix into a two-hour one [8]. A preflight script checking those four things and failing loudly would, on the author's estimate, have saved three hours each [9]. Both devs added a screen without trouble and then got stuck getting a build onto a phone [10]. Neither knew the difference between Expo Go, a development build, and an EAS build, and the README documented only `expo start` [11]. One shipped a build that installed and crashed on launch because the required environment variables were not set in EAS secrets [12]. The author prices the missing page at five minutes to write and three hours to skip [13]. The auth section is the cleanest example of correct code producing wrong outcomes. Route protection existed in the root layout, in individual screens, and in a custom hook, with nothing marking which was canonical [14], so both devs implemented a protected route slightly wrong in different ways, and both readings were defensible [15]. Token refresh ran invisibly through middleware and was undocumented, so one dev spent two hours building a mechanism that was already working [16]. The RLS policies governing the protected data lived in a separate repository neither dev knew about, so a correctly authenticated request returned an empty array with no error anywhere [17]. The proposed fix is one auth architecture page: token flow diagram, one worked example, a pointer to the policies, fifteen minutes to write once [18]. The magic-link deep link cost 6 hours for one dev and 8 for the other against the author's own 90-minute estimate [19], which is 40 to 53 percent of the whole 15-hour loss in a single ticket [2]. Imperative routing required a manual linking config that was not documented [20], dev and production builds carried different bundle identifiers so a link opened one and not the other [21], and testing needed `xcrun simctl openurl` and `adb shell am start`, neither of which either dev had run [22]. This is the one item the author attributes to an architectural choice rather than a documentation gap: file-based routing would have made deep linking work automatically for any route file [23]. Two developers on one template is an anecdote, not a study [1].

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories