Here is a highlighted overview of the major points from some of my favorite EmberConf 2020 talks:
DAY 1
Opening Keynote โ Yehuda Katz, Jen Weber, Godfrey Chan
- First ever all-virtual EmberConf ๐ป โก ๐
- There’s more to software than the number of lines of code you write
- Value sustainability
- Innovating on Community ๐ค ๐ช
- Ember 1.13 had a large number of deprecations
- Technically followed SemVer, but created lots of chaos…๐ฐ
- SemVer doesn’t tell the whole story of ecosystem stability
- RFC Process (Started 2014 ๐
)
- Driven by the community
- Aid the core team with many perspectives
- Collect constraints
- Build relationships
- Provide structure for implementation
- Record history and rationale
- RFC: Slack โ Discord ๐
- RFC: Website Redesign โจ
- But where’s the Tomster? - Drives conversation and solutions
- Core teams โ Diverse leadership
- Togetherโข
- 2017: Ember framework began to feel like it was falling behind
- Surviving the Framework Hype Cycle by Brandon Hays ๐บ
- Settlers and Pioneers
- Shipping features as low-level primitives and let the pioneers finalize the APIs
- Stable ๐งฑ
- Give pioneers the tools and leave the settlers alone
visit()
API โ Fastboot- Component Manager โ
@glimmer/component
- Modifier Manager โ
ember-modifier
- But when do settlers adopt?
- 2019: Ember Editions
- Collection of features
- …and the settlers keep on working
- Ember Octane
- Fresh look for a new user ๐
- 1️⃣ HTML-First Framework
- Core of Ember is HTML and CSS
- No special Ember-specific tweaks…Just copy paste ✂️
- Components can simply be a natural extension of HTML โ Driven by HTML and Templates
- Template only components (Improved performance, no
this
in template) ๐๏ธ
- Template only components (Improved performance, no
- 2️⃣ Integrating JavaScript
- Old: Managing DOM ๐ญ ๐ โ New: Managing Data ๐ ๐
- JS file co-located next to your existing Template
- Native JS syntax and idioms
this.args
get shareURL() { //... }
โ{{this.shareURL}}
(JustWorksโข in the template)- Autotracking: Auto-updates the getter if any passed-in
this.args
properties used inshareURL
change@tracked
properties- Even works on Native JS classes
- Autotracking: Auto-updates the getter if any passed-in
- 3️⃣ Working with the DOM
<button {{on "click" this.toggleSize}}></button> {{#if this.isLarge}} Large code... {{else}} Small code... {{/if}}
import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; export default class MyComponent extends Component { @tracked isLarge = true; @action toggleSize() { this.isLarge = !this.isLarge; } }
- Powerful, intuitive
<input {{autofocus}} />
export default class AutofocusModifier extends Modifier { didInstall() { this.element.focus(); } }
- 1️⃣ HTML-First Framework
- Syntax and mental model overhaul
- Shipped Dec 2019
- Don’t have to rewrite apps to begin using features
- Linting out of the box
- Updated defaults when generating apps
- Zero config builds
- Refreshed guides
- Create a new app โ
ember new
- Paste in HTML and CSS โ
application.hbs
- Fast deploy โ Netlify
- Incrementalism
- Backwards compatibility
- Interoperability between new and old paradigms
- Codemods
- Ember 2019-2020 Roadmap RFC
- Invest in Octane
- Modernize build system
- Better accessibility by default
- Share Octane outside our community
- Building Ember Together ๐ค
- ember-inspector - Octane certified ๐ฅ
- Ember Twiddle - Octane certified ๐ฅ
- Fresh look for a new user ๐
FastFlood: The Story of a Massive Memory Leak in FastBoot Land โ Sergio Arbeo
- Fastboot: Render Ember apps on the server
- Memory leak: piece of data which should have been garbage collected โป๏ธ
- But Whyโ
- A reference is being kept somewhere
- Chrome Developer tools ๐ ๏ธ
- Object memory graph - All objects in memory ๐
- Distance - Distance from GC root
- Shallow size - Size of the object itself
- Retained size - Size we would free if we freed the object reference
- Heap profile - Capture memory state at a point in time
- Three snapshot technique to find the problem areas
- 1️⃣ Warmup the application - Create baseline objects
- 2️⃣ First snapshot
- Now, do the suspected memory leak action
- 3️⃣ Second snapshot
- Now, repeat the action
- 4️⃣ Third snapshot
- Three snapshot technique to find the problem areas
- Object memory graph - All objects in memory ๐
- Timeline tool
- Step 0: Reproduce locally on a production-ish build (no uglification)
- Step 1: Find the leak ๐
- Run the server with debugging enabled
- Make one request
- Start timeline
- Make a few requests
- Inspect
class LeakDetect { constructor() { Object.assign(this, attrs); } }
- Step 2: Find the dominator (retainer we need to remove so the leak is gone) ๐
Container
: used to instantiate and cache objects, associated with aRegistry
- Look for Owner leaking (public API of the
Container
) - Problem:
export default Adapter.extend({ headers: computed(function() { return { Authorization: `Bearer ${something.here}`; } }) })
- Fix:
export default Adapter.extend({ get headers() { return { Authorization: `Bearer ${something.here}`; } } })
Octane: A Paradigm shift in EmberJS โ Suchita Doshi
- The Journey of Ember ๐โโ๏ธ
- Ember 1.x
- Convention over configuration
- Built-in routing
- Ember Data
- View driven architecture
- Two way bindings ๐
- Attribute bindings
- Ember 2.x
- Component driven architecture
- Glimmer rendering engine adoption
- Better binding with properties
- Improved template scoping
- “Data Down, Actions Up” approach
- Roadmap for further improvements
- Ember 3.x
- Road to Octane
- Cleanup
- Remove IE9, IE10, PhantomJS and Bower
- Native Classes
- Angle Brackets
- Lots of documentation
- Ember 1.x
- Evolution of Ember
- Edition: Shift in programming model due to new framework features โจ
- Native Classes
- Increased performance
- Smooth learning curve
- More aligned with JS community
- Glimmer Components
- Simple, Ergonomic, Declarative ๐ช
- Fewer lifecycle hooks and properties to learn
- Removed the implicit component wrapper
- Namespaced arguments
- Templating in Octane
{{!-- Old --}} {{employee-details name=employeeName empId=employeeId addEmployee=(action "addEmployee")}} {{!-- New --}} <EmployeeDetails @name={{this.employeeName}} @empId={{@employeeId}} @addEmployee={{this.addEmployee}} />
- Tracked Properties
- No more
this.set()
- Reduce complexity
- No more
- Modifiers and Decorators
ember-codemods
- Ember Atlas
AST: the Secret Weapon to Transform a Codebase โ Sophia Wang
- How do I bulk edit syntax at scale?
- Example: Wrap all requests with a global error handler
- But we have a problem… Hundreds of requests scattered around the codebase
- Update manually? ๐ค๐ข Tedious and time consuming
- Update with RegEx? ๐ค๐ข Too inefficient for so many unique changes
- Update with Codemods? ๐ค๐
- Understanding the grammar behind a language
- Apple === Noun
- 1️⃣ Tools ๐ ๏ธ
- ESLint
- Disallow unreachable code
function foo() { let retVal = 1; return retVale; returnValue = 2; // <-- Unreachable code detected ts(7027) }
- Disallow unreachable code
- Codemod: Bulk edit syntax
- Babel Transpiler: Write modern JS โ Transpile โ Run in any browser
// Convert this [1, 2, 3].map((n) => n + 1); // To this [1, 2, 3].map(function(n) { return n + 1; });
- ESLint
- 2️⃣ What is an Abstract Syntax Tree (AST)? ๐ณ
- A Tree structure highlights the most important syntax of a language
- Tree: Nodes connected by Edges
- Heap Tree
- Parse Tree
- AST: Best parts of a Parse Tree (Structure) but only highlights the most important information
- Remove extraneous information, Simpler
- 3️⃣ How does syntax transformation work?
- Parsing
- Lexical analysis (Scanning/Tokenization)
- Syntax analysis - AST Explorer (Includes Glimmer parser โจ)
- Transformation
- Code Generation
- Parsing
Taming the Beast: Managing a really ambitious codebase โ Luke Deniston
- But this time I will build things the right way…
- The Beast === Complexity
- When we write code, we’re telling a story
- Audience: Developers, Computers
- Strategies for dealing with complexity
- Abstracting
- Subdividing (Systems โ Subsystems)
- Codebase v1: Coffeescript, Rails, Ember ๐
- Regressions with each upgrade
- Performance degradation
- Codebase v2: Shared addon and micro front ends ๐
- Solved some issues but full page refreshes when navigating from app to app
- In-repo engines? Repo-mageddon
- Fix bug in shared addon โ 5-6 different cascading pull requests
- Codebase v3: Mono repo - yarn workspaces with Ember Engines ๐ฅณ
- Workspaces: 1 repo, many packages
- Packages can import each other
{ "private": true, "workspaces": ["packages/*"] }
- Pro tip: Make individual package folder with the same name as the
package.json
name field
- Packages can import each other
- Engines: Mini application, built and booted by the host application
- Optional lazy loading
- Code isolation
- Routable engine
Router.map(function() { this.mount('super-blog'); })
- Routeless engine
{{mount "super-blog"}}
- Tests: Use the correct resolver
ember-engines/test-support/engine-resolver-for
- Sharing services
- Workspaces: 1 repo, many packages
- Controversial Tipsโ๏ธ
Replace this with your real tests
โ Treat this as a bug!- Use the last argument in tests
.assert()
to describe the test - Use Prettier and ESLint
- Be careful with Addons (Actively maintained? File size bloat?)
- Use TypeScript
- Use Tailwind
Lessons Learned from Changing Careers โ Kara Luton
- Your past experiences make you the developer you are today ๐ฅ
- A non-traditional background is a feature, not a bug
- What did I want in a new career?
- Codecademy
- Get a CS degree, self teach or go to a bootcamp?
- The Iron Yard bootcamp
- Overwhelming amount of information about HTML, CSS, and JS
- Job rejections โ Judged for not having experience ๐ฉ
- Lessons learned along the way (Ballerina โ Music Publicist โ Developer) ๐ฉโ๐
- Practice doesn’t make perfect, it makes progress ๐โฌ๏ธ
- Pay attention to the small details
- Accepting feedback and not taking it personally
- My writing skills โ Code commenting! ๐ช
- How to work well with others
- How to stand out amongst the crowd
- Interviewing skills
- Community is important
- 37.6% of developer who have a college degree did NOT major in Computer Science
- Look back on your own past experiences
Ember as Song โ James C. Davis
- How best to compare building an app with composing a song?
- Programming and Songwriting are very similar ๐ถ โจ๏ธ
- Song: composed of sections
- Section: composed of instruments, notes, parts, measures, phrases
- Section โ Route
- Instrument โ Service
- Part โ Component
- Notes โ Contextual Components
- Other globals: tempo, master volume, playing state, where are we in the timeline
- Web Audio API: Powerful but low level. Provides primitives for making sounds
- Tone.js: Built on top of the Web Audio API. Provides primitives for making music
- Scale: string of notes, one after another
Democratizing Frameworks Through Developer Experience โ Sarah Yu
- Reach: Engineering apprenticeship program at LinkedIn
ember-m3
: alternative model implementation toDS.model
- What is developer experience (DX)?
- Things that make developers’ lives easier
- DX is often not prioritized ๐
- Involves people ๐ฉโ๐ฆฐ๐จโ๐ฆฐ
- Metrics can be hard to measure ๐
- Much easier to just say you reduced the build size by
n
Bytes
- It’s a bug it that happens -Yehuda Katz
- When should you contribute to DX?
- Beginner: Getting started guides
- Intermediate: Advanced APIs
- Advanced: Self-documenting source code
- Where can you contribute?
README.md
- Ember Learning
- Debugging tools
- Source code comments
Why JS is Coming to Ember Templates โ Matthew Beale
- “No more unification RFCs” ๐จ
<Welcome />
could live anywhere since resolvers are a runtime concern- Local maximum โ Global maximum
- Matt’s resolving Ember Microlib
const template = [ [0, 'To you I say:'], [1, 'welcome'] ] setup(); render(template);
- rollup.js
- terser
- Dynamic resolution vs. static linking
import { welcome } from './components' const template = [ [0, 'To you I say:'], [1, welcome] ] render(template);
- How can we bring the benefits of a statically linked system into Ember โ
- Handlebars Strict Mode ๐ช
- What are the constraints in strict mode?
- No implicit
this
fallback - No resolution.
{{foo-bar}}
is only ever a variable - No dynamic resolution.
{{component foo}}
- No partials
- No implicit
- Need a static solution for getting other components into template scope.
createTemplateFactory({ "scope": () => [OtherComponent] })
- Template imports
- You can import a default of named export into your template
- The right side of an import, the path, works just like it does in any system using Node.js resolution.
- Adopt ES Modules syntax module syntax into templates
--- import Quote from './quote'; import { titleize} from '@ember/template-helpers'; import { animatedEach } from 'ember-animated/helpers'; --- {{#animatedEach @greetings as |myGreeting|}} To {{titleize this.subjectName}} I say: <Quote>{{myGreeting}}</Quote> {{/animatedEach}}
- Next steps:
- Get Handlebars Strict Mode into Final RFC and land the primitives
- Build an addon for template imports so we can experiment
- Start a design for what the ES module API is for built-ins like
<LinkTo>
or<Input>
- Performance + Payload size benefits
- Explicit templates
- Strict mode for templates RFC
Solving Problems for African Soil โ Ridhwana Khan
- Kasi Maths
- Why should you care?
- Outline of challenges
- Power/Electricity: Loadshedding and power outages (Rolling blackouts) ๐
- Plant breakdowns ๐ญ
- Poor cellphone reception
- Basic digital literacy ๐ป
- Reduced access to computers in public school and at home
- High data costs ๐ฐ
- Low end smartphones
- Bandwidth speed
- Power/Electricity: Loadshedding and power outages (Rolling blackouts) ๐
- First Paint (Is it happening?) โ First Contentful Paint โ First Meaningful Paint (Is it useful?) โ Time to Interactive (Is it usable?)
- How can I help?
- 1️⃣ Reduce Bundle Size
- Minifying & concatenating JS
- Code splitting
- Tree shaking
- Measure
- 2️⃣ Server/Static Rendering
- Fastboot and Prember
- 3️⃣ Service Workers
- Caching and offline
- ember-service-worker
- ember-pouch
- 4️⃣ Other Performance Tips
- Optimizing images
- Optimizing the JSON
- Adaptive loading
- 1️⃣ Reduce Bundle Size
Shift Left โ Melanie Sumner
- Where did you start: Hobbyist? Computer Scientist degree? Coding Bootcamp? Self-taught?
- Change is the constant we can rely on ๐
- Continuous learning is a must
- Assistive technology is not included is most curriculums
- Find your niche and grow
- Think beyond
- Enjoyable UX
- No vision
- Keyboard-only
- Low vision
- Accessibility settings
- High contrast mode
- What does a typical pattern look like? ๐งฉ
- Basic examples
- Variations
- Rendered code
- Copy & paste
- Too many DOM nodes can crash screen readers
- Patterns should also include anti-patterns
- ember-template-lint
- ember-a11y-testing
- It’s ok to not know everything. Lean on tooling
- Shift Left mindset: Intent matters
- Accessible interfaces can used the way they were intended to be used
- Don’t wait for the audit, move accessibility into the design workflow
- Elevate the quality of your code
- Technical Accessibility Issues for New Ember Apps RFC
DAY 2
Autotracking: Reactivity and State in Modern Ember โ Chris Garrett
- Reactivity: How apps update when things change
- Autotracking is a form of reactivity
- TodoMVC
- How do we let the template know to when to update?
this.rerender()
๐ญthis.rerenderItem()
๐ญ
- Annotation overhead: All the extra thought that has to go into doing things the way the framework wants you to do them
- Grows combinatorially with the size of our application ๐จ๐จ
- jQuery
- Reactivity can solve this by linearly increasing rate instead of exponentially increasing rate
- Declarative programming model for updating based on changes to state
- Declarative: “What, not how” โ
- HTML (Derived State)
- State: All the things that can change in your app
- Variables
- Properties
- User inputs
- Root State
firstName = 'Liz';
- Derived State
get fullName() { return `${this.firstName} ${this.lastName}`; }
- Observable - RxJs
- Observable โ Events โ Transform โ Subscriber (Push-based)
- Similar to classic Ember -
set()
,pushObject()
allTodos = Observable.of([ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ]);
- Performance++ / Ergonomics–
- Virtual DOM - React
- “Where did the state change occur?” (Pull-based)
- Tree: Dirty โ Rerender
- Class based components
state = { allTodos: [ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ] } this.setState({ allTodos }); // Specifically communicates "What" to the framework
- Hooks
let [allTodos, setTodos] = useState({ allTodos: [ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ] }); this.setState({ allTodos }); // Specifically communicates "What" to the framework
- Performance–
useMemo
/shouldComponentUpdate
(manual optimization) โ Scalability โฌ๏ธ โ Complexity โฌ๏ธ
- Can we bend the curve? Performance++ and Annotation overhead–
- Autotracking: Use the JS state model (Pull-based)
- Focus on root state: Push to array, Add to object
allTodos = new TrackedArray([ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ]); @tracked displaying = 'all';
- Performance++ / Ergonomics++
- Root State โ Output
- Memoization: Return a previously computed value if nothing changed
memoizedRender(...args) { if (deepEqual(lastArgs, args)) { return lastResult; } lastResult = render(...args); lastArgs = args; return lastResult; }
- Clock: state v0 โ state v1 … โ … state v15156;
- Did the clock increment? Update
- Tag:
myClass.trackedProp
โ state v15156 (last known clock when this was changed) - Simple / Performant
- Dirty: Increment a number
- Validate: Array.map + Math.max
- Lazy (only checked on demand)
- Only need to annotate root state
- This is what bending the curve looks like
- What’s next? ๐ฎ
- Libraries, patterns, common abstractions - tracked-built-ins
- Tooling - Ember Inspector state timeline
- Extract to be used anywhere
- Focus on root state: Push to array, Add to object
An Octane-Powered JAM Stack โ Chris Manson
- JAM? JavaScript, APIs, Markup
- Fast sites delivered by prerendering files and serving from CDN (Serverless)
- Created by Netlify
- Evolution of some of the things we were already doing
- JAM Spectrum ๐
- Server-side Rendering ๐๏ธ
- Pre-rendering: Prember
- JAM Lifecycle: Serve HTML โ Load JS
- Gatsby - $15M Funding ๐ฐ
- VuePress
- Empress
- Stable ๐งฑ
- empress-blog - Shallow fork of Casper theme from Ghost
- Guidemaker - Powers EmberJS guides
- Field Guide - Ember website redesign
- Beta
- Alpha
- Stable ๐งฑ
empress-blog
Architecture- Host App (Ember) โ empress-blog (Broccoli) + empress-blog-template (Handlebars/CSS)
npm uninstall empress-blog-casper-template npm install empress-blog-attila-template
- Host App (Ember) โ empress-blog (Broccoli) + empress-blog-template (Handlebars/CSS)
A11y First and Everyone Wins โ Ava Wroten
- Adding Functionality with Composable Components
- Equitable & Discoverable UX
- Automation Testing
- 15% of the world lives with some form on disability ๐
- Degrees of disabilities ๐โ๐ฆบ
- Limited mobility, Muscle slowness, Tremors, Low vision, Color blindness, Partial hearing loss
- W3C Pattern Rearrangable Listbox
- ember-sortable
<SortableGroup>
โ<SortableGroupAccessible>
(wrapper)<SortableItem>
โ<SortableItemAccessible>
(wrapper)
- Splattributes
<SortableGroupAccessible tabIndex="0" class="border focus:border-teal-400" />
<div ...attributes> {{yield}} </div>
- Modifiers
<div {{key-up this.handleArrowUp key="ArrowUp"}}></div>
@ember/test-helpers
triggerEvent
andtriggerKeyEvent
- Test reordering and key events ๐
test('it can listen for specific key up events', async function() { this.keyUp = ({ key }) => { assert.equal(key, 'Enter'); assert.step('key up'); } await render(hbs` <div {{key-up this.keyUp data-test-id="keyup"}}></div> `) let selector = '[data-test-id=keyup]'; await triggerKeyEvent(selector, 'keyup', 'Enter'); assert.verifySteps(['key up']); });
assert.dom(findAll('[data-test-id=item]')[0]).hasText('Item 1'); assert.dom(findAll('[data-test-id=item]')[1]).hasText('Item 2'); // Reorder await triggerEvent('[data-test-id=group]', 'focus'); await click('[data-test-id=sort-down]'); assert.dom(findAll('[data-test-id=item]')[0]).hasText('Item 2'); assert.dom(findAll('[data-test-id=item]')[1]).hasText('Item 1');
- Quick feedback loop
EmberQuest: Building an Octane Role Playing Game โ Dan Monroe
ember new emberquest
๐ฎ- Hex tiles
- Pathfinding
- WebGL
- Canvas
- Web Audio
- ember-concurrency
@task *reloadHealth() { // ... }
- Phaser ๐น๏ธ
- ember-phaser
ember install ember-phaser
ember generate phaser-scene tomster
ember generate service game
ember generate component gameboard
An Ember Dev’s Guide to CSS Grid โ James Steinbach
- Grid: Responsive CSS-only layout method
- Column / Row / Gap control ๐ค
- Grid properties & values:
grid-template-columns
,grid-template-rows
,fr
,max-content
,grid
๐ฑ๐จdisplay: grid; grid-template-columns: 1fr 40em 20em 1fr; grid-template-areas: "header header header header" ". body sidebar . " "footer footer footer footer"; gap: 12px 16px;
grid-template-columns
: Set the proportions for tracks along the inline axis of the grid container- 30% 150px 30%;
grid-template-rows
: Set the proportions for tracks along the block axis of the grid container- 50px repeat(10, 100px);
- ๐จ Warning ๐จ Fixed heights cause overflow
- Better:
auto
,min-content
,max-content
- Better:
- Logical properties
inline
: start to end of a line of text in the blockblock
: start to end of the block of text
dir=rtl
andwriting-mode: vertical-lr
support for freegrid-template-areas
: assign names to grid areas- One rectangle, adjacent cells, strings (not integers)
grid-template
: assign rows, columns, and areas as a shorthand- Every row ends with its height
- Every column ends with its width
grid-template: "header header header header" auto ". body sidebar . " auto "footer footer footer footer" auto / 1fr 40em 20em 1fr;
gap
: Creates gaps between columns and rows- Grid container values
fr
: 1 fraction of the grids free space- Calculated after non-
fr
space is used - Based on the total number of
fr
in the row or column
- Calculated after non-
repeat(<count>, <length>)
repeat(12, 1fr)
=== 12 column Bootstrap
grid-area
: Agrid-template-areas
name from the parent- Center an item
display: grid; justify-content: center; align-items: center;
- Gotchas
- Images sizes:
img
obeys a the grid-cell size โobject-fit: cover
- Animating grids: Some browsers animate, can’t animate between areas
- IE 11 ๐จ
- Images sizes:
Stronger App Architecture Using Maps โ Matt Gardner
- GIS (Geographic Information System) Mapping technology
- NYC Planning ๐
- Changing expectation about how governments deliver digital services
- We use maps every day ๐บ๏ธ
- ZoLa
- Making data easy to consume
- Where can we build Housing?
- A brief history of maps
- John Snow: London Cholera outbreak map
- Florence Kelley: Income map by residential block
- Basemap: Static data, always present
- Data Layers: Polygons, Lines, Points
- Enter…The Tile: Avoid triggering a fullpage reload when navigating
- Dynamic interactions ๐ฑ๏ธ
- How are tiles made?
- Cylindrical map projection
- Assume that the world is a square ๐ฆ
- GeoJSON: Opinionated JSON format for storing spatial data
- Best for most use cases
- Leaflet
- ember-leaflet
- mapbox-gl-accessibility
- ember-mapbox-gl
- Test Stubs โ Dependency Injection
- How to lie with maps ๐คฅ
- “Map users seldom, if ever, question these authorities, and they often fail to appreciate the map’s power as a tool of deliberate falsification or subtle propaganda.”
- Spatial correlation !== Meaningful data relationship
The Power of Debugging โ Samanta de Barros
- Challenges
- 1️⃣ Dev vs Prod
- Sources tab
- Breakpoints
- Pretty print formatting for minified JS
- 2️⃣ External Libraries
- Stack trace โ
- Don’t be afraid to step in ๐ถโโ๏ธ
- Addon vs NPM library code location
- 3️⃣ Not My Code
- Use the Ember Inspector
- Find the function location
- 1️⃣ Dev vs Prod
Talking to Your Dog with Ember โ Robert Wagner
- wuf.plus ๐ถ
- Web Audio API
fftSize
(Fast Fourier Transform) andfrequencyBinCount
getByteFrequencyData()
getByteTimeDomainData()
- Determining dog bark types ๐
- ~1000-2000 Hz range and between ~80-90 dB (decibels)
- Finding db spikes
- Types: Alert, Greeting/Playful, Distress
- Deciphering audio data ๐
@action async startRecording() { const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); const options = { mimeType: 'audio/webm' }; this.mediaRecorder = new MediaRecorder(stream, options); this.mediaRecorder.addEventListener('dataavailable', e => { this.args.uploadAudioVideo({ blob: e.data }); }); this.mediaRecorder.start(); }
- Integration with Ember ๐น
- Future work
- Add more bark types
- Refine frequency ranges
- Add “Talk Back” feature
The Moderate Programmer โ Derek Gavey
- Moderate: Avoiding extremes of behavior
- The moderate programmer names things appropriately
- 3 words or less
- Avoid jargon and metaphors
factory
,object
,class
- Use plurals where appropriate
- For booleans, prefix with
is
,has
,can
- For functions, user a verb then noun
- The moderate programmer writes small functions
- Function does one thing
- Beware of flags in arguments
- Beware of too many arguments
- Components are functions too
- The moderate programmer writes tests
- Write your tests immediately (or you won’t write them)
- Integration tests are your best bet
- You have diminishing returns after
n%
code coverage
- The moderate programmer refactors
- RailsConf 2014 - All the Little Things -Sandy Metz
- “Duplication is far cheaper than the wrong abstraction”
- Write ugly code!
- Rule of 3 (abstract on your third duplication)
- Will future me/teammates understand this better?
- Weight the costs of the refactor
- The moderate programmer gives up
- Give up and ask for help
- Give up and take a break ๐ง
- Give up and throw out your code…it’s ok
Why Contributing Seems Scary โ Anne-Greeth van Herwijnen
- Contributing ๐โโ๏ธ
- Everyone sees this differently
- Add / Remove code
- Setting up a meetup
- Code review
- Ideas
- Motivation โ Social Norms โ Community
- Motivation: Intrinsic / Extrinsic
- Social Norms: Ask โ๏ธ โ Encouragement ๐
- Community: Psychological sense of community โ Commitment
- What can we learn?
- Thank every contributor ๐ค๐ป
- Ask people to contribute where their strengths are
Octane Octopus: The Multi-Faceted Migration โ Jordan Hawker
- Why is the migration experience important?
- Past migration pains
- Stability
- Productivity
- Can continue building new Octane feature while you’re migrating
- Unlock new features quickly
- Reduce manual refactoring costs
- Minimize overhead of learning new patterns
- Many features are polyfilled and stable back to 3.8
- Recommendations
- Phase 1: Upgrade to Ember 3.16 LTS
- Enable Octane features
- ember-cli-update
- Phase 2: Codemods
- Phase 3: Prepare for Glimmer
- ember-classic-decorator
- Remove classic Ember patterns
- Template-only components
- Phase 4: Adopt Glimmer
- Preliminary component refactors
- Empty
tagName
- Migrate
classNames
,classNameBindings
,attributeBindings
{{on "click" (fn this.foo 'bar')}}
event handlers- Modifiers
- Empty
- Finish Glimmer conversion
computed() / this.set()
โ@tracked
- Convert lifecycle hooks
- Preliminary component refactors
- Phase 1: Upgrade to Ember 3.16 LTS
- Classic vs Octane Cheat Sheet
- Ember Atlas Recommended Migration Order