The Frontend City Thomas Gossmann gos.si gos.si gossi

Brüssel

Brüssel 540 Unispin in front of the Basilique Nationale du Sacré-Cœur

Problem Statement We explain a technical initiative to non-tech folks We use technical language in our explanation We are not understood They approve the budget for our technical initiative They won’t - we weren’t understood Examples (Local) Refactoring Writing RFCs Change build system to Embroider/vite …

Example: Change Build System to Embroider/vite Arguments Questions It’s faster What will it cost us? It’s fancy How long will it take? Tree shaking Half a year to have the same situation as we have Smaller bundle size now? It’s modern How much features can be shipped instead? What’s the return of this investment?

Solution: Translate “ When we can explain it to my Mum, we are good. - My Manager

Task Responsibility Work on the Build System Keep the Frontend Operable

Question What would you need to do to keep the Frontend Operable?

Question 2 What would you need to do to keep a City Operable?

The Frontend City “ We built this city We built this city of rock and roll Built this city We built this city of rock and roll

  • Starship

Infrastructure City Layout Transportation Health & Security Sport & Entertainment Education City Construction

Infrastructure

Infrastructure City Software Electricity Dependency Management Water Build System Cable Release Management Garbage Collection Automated Maintenance Systems (dep upgrades) Traffic (lights) Framework infrastructure

City Layout Architecture

City Layout: Districts Hierarchical structures for managing complexity: Districts Districts to own all coherent parts of it

Architecture: System Landscape Subdomains System Components C4 Model

City Layout: Zoning American Suburbia Strict zoning (housing, commercial, industrial) Less/No mixed zoning Car dependent city Few transportation options By Avi Waxman on Unsplash By Michael Moloney on Unsplash

City Layout: Zoning Medieval Europe Zoning (housing, commercial, industrial) Mixed zoning Many transportation options By Svetlana Gumerova on Unsplash Shorter travels The “walkable city” By Matt Mutlu on Unsplash By Patrick Robert Doyle on Unsplash

Architecture: Code Organization Car dependent city = framework dependent product Your domain defines the organization of your code (never a framework) Use architectural patterns: Clean Architecture Vertical Slice Architecture Hexagonal Architecture … Prevent Tech Debt

Transportation APIs

Transportation Modalities Public Transport Private Transport Infrastructure Transport Hubs Railway network Streets Scope of traffic Local Traffic Global Traffic Public Transport Vehicles Private Transport Vehicles Bike Unicycle Tram Feet U-Bahn Car S-Bahn Bus ICE Stations Train Stations Bus Stops Stations Parking Space

Transportation: APIs Public API amongst subdomains Private API within a subdomain Use architecture lint to prevent illegal connections

Construction

Construction Houses in a City are the equivalent to Features of a Product City Software Construction workers evolve their tooling Linting - as railguards for programming languages Build houses… Formatting - to have the same syntactical look … faster (faster recognition) … safer Editor integration - For instant feedback on their … accessible fingertips … more sustainable Fixtures + Mocks Frontend Workshop

Health & Security

Health & Security: City Institutions Processes Firefighters Alarms for immediate actions Hospitals Pre-warn systems Emergency Medical Services Security checks for buildings Police Alpine Rescue Service Disaster Control …

Health & Security: Software Institutions Error Monitoring (Sentry) Processes Vulnerability management Entire app Monitoring or Subdomains Emergency changes Resource monitoring in grafana All sorts of tests from the testing pyramid Code coverage metrics Pre warn system through @embroider/try Rollback of changes Testing procedures Bug reporting Risk management

Sport & Entertainment DX

Sport & Entertainment Panem et circenses City Sport and entertainment are the most unnecessary Software DX minor matters in a city A city would function without Citizens greatly benefit from its presence Scaling Frontend: Superchar Ember Fest

Education

Education City Software Schools Onboarding Libraries Documentation Universities Diataxis: … Tutorials How-To Guides Explanation Reference Training Learning Time

The Frontend City “ Take me down to the Paradise City Where the grass is green and the girls are pretty Take me home (I want you, please, take me home) - Guns N’ Roses /gossi/the-frontend-city

Usage We do live longer in cities, than we live in code! Documentation Hub Decision Framework Structure your documentation based on the

  1. Connect an incoming request to the topic frontend city idea
  2. Decide from within that topic No onboarding needed
  3. Higher qualitative answers (connect to context & People feel “home” immediately and can navigate scope) 4. Higher confidence in your answers 5. Faster and more competent answers 6. Increase of trust in you

Example: Change Build System to Embroider/vite Task vs. Responsibility Task Responsibility Work on the Build System Keep the Frontend Operable See the task through the lens of responsibility Connect to context Reshape weight of task vs. responsibility -> Priority?

Solution Mission (Translation) Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber

Reason: Time and Money Savings Optical fiber has lower latency, more resilient conncetions, higher bandwidth Economic Proof on Savings N umberOf Engineers ∗ ØRebuilds/Day ∗ RebuildT ime N umberOf Engineers ∗ ØBuilds/Day ∗ BuildT ime N umberOf Engineers ∗ Ext.SocialM ediaT ime/(Re)BuildDelay CIruns/Day ∗ BuildT ime Use numbers (Re)Build time numbers with classic and embroider/vite to run a comparsion Threshhold for N umberOf Engineers to savings to become significant If saving numbers are too low/insignificant, ROI/amortisation is not of interest

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Time and Money Savings

Assessment: Technical Feasibility classic Embroider (loose mode) Can we roll out fiber in the city? Can we roll out fiber in to each district? Can we roll out fiber to each street? Can we roll out fiber to each house? Embroider (strict mode) vite

Assessment: Technical Implementation classic Embroider (loose mode) Embroider (strict mode) Preparation: Strict Imports Prepare requirements: Strict Components/Helpers/Modifiers, use @embroider/template-tag-codemod Tasks can be parallelized Can be done by product teams Great to onboard them with the new technology Iterative learning opportunity vite

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Time and Money Savings Method Parallelize Involve product teams Incremental Delivery & Improvements

Challenge: Mindset Shift ember-cli shields engineers from build system internals vite provides much more exposure bundlers/transpilers are much more closer to engineers NPM is much closer ( imports and exports fields) CJS vs. ESM CJS ESM Align with JS Ecosystem Storybook 10 is ESM-only

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Method Time and Money Savings Parallelize JS Ecosystem Compatibility Involve product teams More OTS Solutions (JS Ecosystem compat) Incremental Delivery & Improvements

Ecosystem Integration Internationlization ember-intl Authentication ember-simple-auth Icons ember-svg-jar ember-phosphor-icons intl-schematic openauth-js @formatjs/intl auth.js i18next better-auth linguist passport.js globalize Polyglot.js paraglide-js The solution for all of us

Integration: paraglide-js services/intl.ts export class IntlService extends Service { @tracked locale = getLocale(); setLocale = (locale: Locale) => { setLocale(locale, { reload: false }); this.locale = locale; }; t<MessageFn extends (…args: any) => string>( messageFn: MessageFn, params: Parameters<MessageFn>[0], options: Options = {} ) { return messageFn(params, { locale: this.locale, …options }); } formatNumber(value: number, options?: Intl.NumberFormatOptions) { return new Intl.NumberFormat(this.locale, options).format(value); }

Integration: paraglide-js helpers.ts function T<MessageFn extends (…args: any) => string>( messageFn: MessageFn, options?: Options | Parameters<MessageFn>[0], params?: Parameters<MessageFn>[0] ) { return resource(({ owner }) => { const intl = owner.lookup(‘service:intl’); if (params) { return intl.t(messageFn, params, options); } return intl.t(messageFn, options); }); } export const t = resourceFactory(T);

Integration: paraglide-js Usage import { m } from ‘#paraglide/messages.js’; import { formatNumber, t } from ‘ember-paraglide’; <template> {{t m.greeting name=”World”}} {{t m.greeting}} </template> Paraglide compiles messages to functions (vite/unplugin plugin) The (t) accepts a function Tree-shaking unused messages away Tooling Ecosystem (UI for messages in vscode)

Integration: better-auth They have signals Beatiful implementation for Vue and Svelte Let’s start using signals for a similar Ember implementation … That is not a smooth experience yet Community Feedback needed: RFC #1071, RFC #1079, RFC #1122

Integration: better-auth class AuthService<User extends BetterAuthUser = BetterAuthUser> extends Service { client!: AuthClient; @tracked internalData?: Data<User> = undefined; get user(): User | undefined { return this.internalData?.user; } setup = (auth: AuthClient) => { this.client = auth; if (auth.useSession.value?.data) { this.internalData = auth.useSession.value.data as unknown as { user: User; session: Session }; } this.loading = !this.internalData; auth.useSession.subscribe((payload) => { if (!payload.isPending) { if (payload.data?.user && !this.authenticated) { this.#handleSessionAuthenticated(payload.data as unknown as Data<User>); } else if (!payload.data?.user && this.authenticated) { this.#handleSessionInvalidated(); } } this.loading = payload.isPending; this.internalData = (payload.data as unknown as { user: User; session: Session } | undefined) ?? undefined; });

Integration: better-auth class AuthService<User extends BetterAuthUser = BetterAuthUser> extends Service { requireAuthentication(transition: Transition) { return new Promise((resolve) => { if (this.authenticated) { resolve(this.authenticated); } const handleAuthentication = () => { if (!this.authenticated) { this.#attemptedTransition = transition; } resolve(this.authenticated); }; const waitUntilLoadingIsComplete = () => { if (this.loading) { return next(waitUntilLoadingIsComplete); } handleAuthentication(); }; if (this.loading) { next(waitUntilLoadingIsComplete); } else { handleAuthentication(); } });

Integration: better-auth very similar to ember-simple-auth user menu protected route export default class UserMenu extends Component { @service declare auth: AuthService; export default class ProtectedRoute extends Route { @service declare auth: AuthService; <template> async beforeModel(transition: Transition) { {{#if this.auth.authenticated}} {{#let (popover position=”bottom-start”) as |p|}} const authenticated = await this.auth .requireAuthentication(transition); <Button {{p.trigger}}> {{this.auth.user.name}} if (!authenticated) { </Button> this._router.transitionTo(‘login’); }

<Menu {{p.target}} as |m|> <m.Item @href=”/user/profile”>Profile</m.Item> <m.Item @href=”/user/sessions”>Sessions</m.Item> <hr /> <m.Item @href=”/user/logout”>Logout</m.Item> </Menu> {{/let}} {{else}} <Link @href=”/login”>Login</Link> {{/if}} } }

Icons Use Iconify Configure vite.config.js import { FileSystemIconLoader } from ‘unplugin-icons/loaders’; import icons from ‘unplugin-icons/vite’; export default defineConfig({ plugins: [ // … icons({ autoInstall: true, compiler: ‘raw’, customCollections: { custom: FileSystemIconLoader(‘./assets/icons’) } }) ] }); Usage sports.gts import import import import { Icon } from ‘@hokulea/ember’; Unicycle from ‘~icons/custom/unicycle’; Activity from ‘~icons/ph/activity’; svgJar from ‘ember-svg-jar/helpers/svg-jar’; <template> Do some <Icon @icon={{Unicycle}} /> <Icon @icon={{Activity}} /> Fallback <Icon @icon={{svgJar “unicycle”}} /> <Icon @icon={{svgJar “activity”}} /> </template>

Integrations with Ember Github Organization: ember-integrations Candidates: vitest-browser-ember , ember-vitepress , … Integration code is tiny glue code

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Method Time and Money Savings Parallelize More OTS Solutions (JS Ecosystem compat) Involve product teams Integrate with JS ecosystem Incremental Delivery & Improvements Faster and cheaper development with more functionality

Breaking Changes? Ember Ember provides a migration path Can you migrate in time to receive future updates? Relevant: Security fixes Addons Supported Ember versions are at the will of its authors When will addon authors stop supporting Ember version x? EMBER INTEGRATION ADDONS Use tsdown over rollup ESM only type=”module” No @embroider/addon-dev

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Method Time and Money Savings Parallelize More OTS Solutions (JS Ecosystem compat) Involve product teams Faster and cheaper development with more Incremental Delivery & Improvements functionality Risk Framework Update Continuity (security fixes) OTS Adoption (limited to legacy adoptions = higher cost)

Architecture: Exploit the Degree of Freedom Strict imports (template imports): Organize code by your domain Strict resolver: RFC #1132 Don’t build a car-dependent city Ember has the best template system Router: Subject of the next Edition to also build the best Router

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Method Time and Money Savings Parallelize More OTS Solutions (JS Ecosystem compat) Involve product teams Faster and cheaper development with more functionality Increase Architectural Freedom Architectural Freedom: Build our City Risk Framework Update Continuity (security fixes) OTS Adoption (limited to adoptions = higher cost)

Solution Mission Technical: Change Build System to Embroider/vite City: Change connectivity from broadband (DSL) to optical fiber Reasons Method Time and Money Savings Parallelize More OTS Solutions (JS Ecosystem compat) Involve product teams Faster and cheaper development with more functionality Architectural Freedom: Build our City Risk Framework Update Continuity (security fixes) OTS Adoption (limited to adoptions = higher cost)

Thank You There was something about a Translation and a City There was something with vite There was something with modern Ember on vite