Best practices for front-end teams

Nick Ribal, September 2020

Delivering fast and high quality modern apps

Nick Ribal

image/svg+xml

Front-end & web consultant, architect, engineer, mentor

Family man

Digital nomad

Opinionated guy

"Team amplifier"

My background

  • Over 10 years of web development, mostly front-end

  • ​Variety of
    • Targets: web, mobile, native
    • Products: websites, apps, 3rd party widgets
    • Company sizes: small to big, start-ups to corporates
    • Company biz types: product, projects, consulting
    • Technologies: each client/company is different
    • Roles: IC, team leader, tech lead, consultant, architect, on-site and remote

I've seen some 💩

Recent few years

  1. ​Technological (easy)

    • Architect, choose & implement technologies

    • Lay a solid foundation, which won't need to be rewritten

  2. Cultural (hard)

    • Improve individual and organizational development speed and quality

    • Explore the complex interactions between code, people, culture and organizations using tooling, rules, conventions and conversations

I lead teams in two dimensions:

  • Senior developers

  • Team leaders

Target audience

But titles are dumb, so:

  • Tech leads

  • Architects

Anyone who cares and thinks about how people, code and organizations interact

You should care about

  • Pull Requests

  • Code reviews

  • Maintainability

  • Development speed

  1. Mindset and guiding principles

  2. Cultivating team & organizational culture

  3. Tools and methodology

Topics we'll cover

Some points contradict each other 😅

A lot of it is obvious, but

sometimes stating the obvious is necessary

1. Mindset and guiding principles

  • Avoid:

    • monolithic

    • opinionated

    • hard to replace parts

Do one thing, do it well. Compose.

  • Don't reinvent the wheel:

    • You can probably reuse 90% of others' work

    • Do your research

    • Only write glue code and your unique core product

    • Roll your own as last resort

  • Prefer:

    • small

    • single purpose

    • modular

Knowing the building blocks allows to:

  • Meaningfully understand abstractions
  • Manage their trade-offs (instead of blindly following hype)

Sad example:

Not knowing CSS/HTML beyond a very basic level results in problems which shouldn't exist:

"div soup", bad a11y, CSS specificity/z-index wars

Learn the basics

  • Don't adopt everything new and shiny
  • See whether something gains real world traction
  • Give new tech time to mature
  • Have it battle tested and polished at someone else's expense

Examples:

  • CSS-in-JS took YEARS to mature from concept to a great implementation
  • WC/Polymer aren't usable even after many years

Avoid hype

  • A sad truth: most developers blindly copy others :(
  • Don't do that - apply critical thinking
  • Use tech which solves YOUR problem

Popularity != quality

  • Tech which doesn't solve YOUR problem is complexity
  • If you don't conciously choose tech but blindly copy, how can you know when is it redundant?
  • A good late abstraction > a bad early one

Avoid "industry standards", overengineering, poor abstractions

I actively avoided Angular1 and Redux, even when absolutely everyone was using them

You think something sucks? Don't use it!

Much later, many acknowledged the same problems I had identified years ago

Follow your gut instinct

When you're wrong: "Better late than never"

  • YOUR business domain
  • YOUR constraints

Be opinionated!

Always re-evaluate your opinions

It is OK to make mistakes

  • YOUR core product
  • YOUR biz/tech priorities

Do not ignore them and change your mind

as long as you

Guide your desicions based on:

  • What's bad today may mature tomorrow
  • What's good today
    • may become unmaintained
    • will be replaced by something better
  • Apply critical thinking and constantly revisit your decisions

Examples of my own mistakes:

  • Didn't like JSX at first
  • Adopted TypeScript late & changed my mind about it

Don't get attached

  • TypeScript
  • eslint
  • stylelint
  • Spell checker

Set standards and enforce via static analysis tools

  • Dependency graph analysis
  • editorconfig
  • Many others

But never limit or dictate which editor/IDE to use

  • Prettier: focus on biz logic, not formatting
  • Linters: find possible bugs
  • Tests: refactor fearlessly, catch mistakes early
  • Languages: TypeScript, GraphQL and others

Reduce cognitive load

Context switching is expensive

Having a short feedback loop to detect mistakes in real time - as you type - is crucial

But how?

  • Policing: annoying and people won't like you
  • Checklists & protocols: people are genuinely busy
  • Requiring everyone to use YOUR favorite tools
  • "fixing the world" 1M LoC commit

Don't fight people

  • CLI based, regardless of editor/IDE preferences
  • No manual setup or configuration, ever
  • Incremental: process only changed files
  • Bonus: will work in CI too

Enforce using tools

AUTOMATE ALL THE THINGS

  • npm scripts - "just work" with npm/yarn
    • Part of your dependencies, versioned
    • Single purpose, composable, cross-platform
    • Seamlessly integrates with editors & IDEs
  • husky 🐶 - "git hooks made easy"
    • Installed with your deps
    • Simple: run commands, such as npm scripts
  • lint-staged ⛔💩
    • Runs commands according to globs of git staged files

Enforceable rules, conventions and guidelines are great! They are VERY important. But,

Be flexible

Every rule has exceptions

Engineering is about managing trade-offs.

When a rule doesn't serve you, change it!

  • Ignore where it isn't helpful: line/file/directory
  • Change severity: Error > Warning > Off

// eslint-ignore-next-line

Refactoring, definition:

Restructuring code, without changing external behavior

REFACTOR ALL THE THINGS!

Refactor/adapt as you go

  • Not "special"
  • Shouldn't require planning or tasks
  • An integral part of daily work

Refactoring is the air you breathe to keep moving

Refactoring enables maintainability & sustainability

  • is not special
  • is just code
  • is not set in stone or sacred
  • should serve you
  • should evolve along with what you're building

Architecture

Reafactor architecture just like any other piece of code

  • Invest the time to analyze the problem
  • Try to avoid preferring what you know just because it is familiar and seems easier
  • Choose the best tool for the job, instead of the best tool you know

Examples:

  • Don't use React for a static site
  • Don't use Redux just cause that's "industry standard"

"Weeks of coding can save us hours of planning"

2. Cultivating team & organizational culture

Software development is a team sport!

Invest in people, build trust

People are your greatest and most expensive asset

  • technological freedom
  • real involvement in product
  • true sense of purpose

Encourage exploration, learning, growing and allow making mistakes. Serious mess-up? Bring 🍰!

  • independence
  • challenges
  • perks matter least

Give them constantly

Make them want to stay

Trust creates partnerships

Your expectations, the way you give and receive feedback create, encourage and cultivate work habits, which will make or break your team - and business.

People who feel that their work matters will naturally assume ownership, responsibility and care for their work and your business.

You set the standard

Listen and empower

  • Encourage expressing concerns and opinions
  • Ask for feedback, and listen attentively
  • Allow anyone to challenge any decision
  • Nothing is set in stone, anything can be changed
  • Smart people don't need micromanagement
  • Supervise, observe, learn people's strengths
  • Delegate to those who will do better than you!

Let them do what they ❤️

Mandatory code reviews

For everyone on the team, always - no exceptions!

Coding style, conventions, Prettier, static analysis with git hooks allow people to focus on what matters: biz logic of what the code actually does

Making code reviews meaningful

This is tricky: feedback must be constructive, meaningful and not nit-picking.

Code review rules for people

  • Assume good intent - not ignorance, stupidity or laziness
  • Be nice: how would you feel if someone wrote that to you?

Be constructive

Use a proper tone

  • "How can we improve here?"
  • "Why did you choose... ?"
  • "I would do this..."
  • "We have to..."

Ask & discuss

Suggest or guide

Instruct or command

Early, iterative feedback

Have people submit and review PRs early:

  • Wrong approach to the problem at hand can be caught early
  • Serious bugs or design flaws are caught early
  • Even very partial work should be subject to review
  • Use labels to communicate PR scope & status: POC, WIP, Ready, In review, Refactor, etc.

Goal: minimize wasted time

Async code reviews

Everyone and anyone can - and should - review others' code in their free time, when they are at ease.

Rejected: waste of time

Async code reviews mandate clear documentation, relevant context and prevent time waste for peers

Who?

What?

Why?

Async CRs set a record and clarity in every PR. Anyone is be able to understand, review and test any feature or change - without prior context.

What

Who

Task

Details

Notes

Learn from the best

  • Open Source Software is remote, distributed, asynchronous and public
  • Adopt and practice this workflow in your organization and your developers will know how to contribute to OSS
  • Encourage them to contribute to OSS and they will love you!
  • Appeals to candidates when hiring

Improving as you go

  • See something unclear? Clarify it!
  • Took you too long to find that bug? Why? How can you make it easier for the next person?
  • Go the extra mile. Demand it from your devs.

Code improvements should be in practically every change

Boy scout rule

"Leave your code better than you found it."

In a CR, if I see something I dislike - including unrelated to the PR - I'll ask to fix that. It will be reviewed and QA'd anyways.

But how? Ask this:

"Is now an emergency?"

"Yes" - put out that fire, nothing else matters!

"No" - you can do more than the bare minimum.

Don't tolerate broken windows

Maintain 0 lint errors and warnings and 0 test failures at all cost!

Manage technical debt

  • When delivering quick and dirty, invest the time to pay back the debts and fix the faults
  • Don't let the bad stuff accumulate
  • Don't get to a place where you're only putting out fires
  • "Least amount of chagnes" horror story

Reduce bus factor

  • Avoid single domain owners
  • Having experts and those who know some parts better is OK, but
  • Never get to where you rely on a single person, whose work can't be replaced by others
  • Make every part approachable and easy to understand and maintain
  • Document vital information in VCS alongside code

Actively reduce bus factor

  • Shuffle people and tasks
  • Get everyone involved with all parts of the code
  • Start with easy, simple tasks and expand
  • Set a policy which not only allows, but encourages everyone to review anyone's code
  • Clarify why it matters and allocate time for CRs
  • People learn a LOT from reading others' code

Thank you and keep leading!

Best practices for front-end teams: delivering fast and high quality modern apps at scale, 2020

By Nick Ribal

Best practices for front-end teams: delivering fast and high quality modern apps at scale, 2020

Speed of development usually comes at the cost of quality: "make it right" or "quick and dirty". The business or client wants everything done today, but too much compromise leaves us a mess of technical debt and a maintainability nightmare. I'll share my recipe for success in enabling high quality software development at a fast pace, based on experience and lessons learned over years of programming, consulting and leading multiple diverse front-end projects and teams. Video of the talk: https://www.youtube.com/watch?v=VSGpXk-1ZgA

  • 759