Adam L Barrett PRO
Adam L Barrett is a JavaScript and Front-End consultant, a contributor to open source, and avid bike-shedder.
Adam L Barrett
Some of the challenges that come along with working across multiple teams on one product or shared components
β
Some of the challenges that come along with working across multiple teams on one product or shared components
ββ
Create a common language to aid communication
Set out some patterns and rules which will
Use tools to help us stick to those patterns and prevent human mistakes
Many strategies simply move the complexity around, one of the only true ways to reduce complexity is abstraction, or black-boxing
Black Box Abstraction
Let's Review what we said so far...
β
VS
Domain
Components
UI
Components
const Documents = ({ userId }) => {
const [
{ documents },
{ create, update, destroy }
] = useDocuments({ userId });
return (
<ItemList
items={documents}
onCreate={() => create({ documentData: {} })}
onUpdate={data => update({ documentData: data })}
onDelete={document => destroy(document.id)}
/>
);
};
const ItemList = ({ items, onCreate, onUpdate, onDelete }) => {
return (
<>
{items.map(item => {
<div key={item.id}>
<Item
name={item.name}
onChange={data => onUpdate(data)}
/>
<button onClick={() => onDelete(item)}>X</button>
</div>;
})}
<AddButton onClick={() => onCreate()} />
</>
);
};
const PaymentsLayout = ({ children }) => {
const nodes = React.Children.toArray(children);
return (
<Grid padded>
<Grid.Row columns="2">
<Grid.Column>{nodes[0]}</Grid.Column>
<Grid.Column>{nodes[1]}</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column>{children.slice(3)}</Grid.Column>
</Grid.Row>
</Grid>
);
};
const Payments = ({ loan }) => (
<PaymentsLayout>
<NextPaymentsTable loan={loan} />
<>
<NumberOfPaymentsTable loan={loan} />
<PartialPaymentTable loan={loan} />
</>
<PastDueTable loan={loan} />
</PaymentsLayout>
);
UI: UI Components (React Components)
Adapter: Domain components (also React Components)
Domain Logic/State: Stores
Adapter: Services (Class instances, functions orΒ simple objects)
Storage: APIs and PlatformΒ (REST + GraphQL endpoints, etc)
UI ComponentsΒ - Function Components, Hooks, Styled Components
Domain componentsΒ - Custom Hooks / Providers
StoresΒ - RxJS BehaviorSubjects (or Redux + Redux-Observable)
ServicesΒ - Simple classes that return promises or RxJS observables
APIs and PlatformΒ - GraphQL and localForage
const AlarmClock = ({ title, state, onSnooze, onDismiss }) => (
<>
<h3>{title}</h3>
<div className="display">{state}</div>
<button className="snooze" onClick={onSnooze}>
Snooze
</button>
<button className="dismiss" onClick={onDismiss}>
Dismiss
</button>
</>
);
export const CreditCardForm = () => {
const [{ values, errors, status } = {}, dispatch] = useStore(CreditCardStore);
return (
<FormComponent
values={values}
errors={errors}
status={status}
onSubmit={e => {
e.preventDefault();
dispatch(PAY);
}}
onChange={e => dispatch(UPDATE, { [e.target.name]: e.target.value })}
onBlur={e => e.target.name && dispatch(TOUCH, e.target.name)}
/>
);
};
const createStore = (action$, creditCardService) => {
const values$ = action$.pipe(ofType(UPDATE), map(creditCardService.validate));
const status$ = action$.pipe(
ofType(actions.PAY),
exhaustMap(({ values }) => {
from(creditCardService.pay(values)).pipe(
mapTo({ status: 'success' }),
catchError(error => of({ message: error.message }))
);
})
);
return combineLatest(values$, errors$, status$, (values, errors, status) => ({
values,
errors,
status
}));
};
class creditCardService {
construtor({ apiUrl }) {
this.apiUrl = apiUrl;
}
async pay(data) {
const response = await fetch(this.apiUrl, { body: JSON.stringify(data) });
return response.data;
}
async validate(ccData) {
await checkValidNumber(ccData);
checkIsExpired(ccData);
}
};
Designer and Developers create a single source of truth and common languageΒ for UI components across products and applications
Pro-Tips:
The 4 main areas that can have the biggest impact on your organizations ability to deliver great software are:
Β
Β
npx create-nx-workspace myorg
npx create-nx-workspace myorg
npx: installed 180 in 7.764s
? What to create in the new workspace
angular [a workspace with a single Angular application]
angular-nest [a workspace with a full stack application (Angular + Nest)]
β― react [a workspace with a single React application]
react-express [a workspace with a full stack application (React + Express)
]
next.js [a workspace with a single Next.js application]
(Move up and down to reveal more choices)
...
cd myorg
apps directory
libs directory
tools directory
npx nx g @nrwl/workspace:lib my-shared-lib
npx nx dep-graph
nx affected:test
nx affected:build
npx nx g @nrwl/react:storybook-configuration my-shared-react-lib
npx nx e2e my-app-e2e
Linting / Prettier
Β
Unit Tests
Β
Integration Tests
Β
E2E/Functional Tests
JavaScript Testing Trophy
Let's Review what we said so far...
Let's Review what we said so far...
Make it work
Make it right
Make it fast
Week 1: Prototype Sprint
Week 2: Integration / Optimization
Week 3: Cool Down and Planning
By Adam L Barrett
This talk is about the fundamental principles for managing the complexity of large front-end applications at scale. It is not about scaling your deployments (i.e. operations), but rather the trouble of scaling front-end development across multiple teams, with strategies for front-end architecture, code organization, predictability and fighting complexity.
Adam L Barrett is a JavaScript and Front-End consultant, a contributor to open source, and avid bike-shedder.