EmberConf 2020 Notes

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 ✨
  • 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
    • 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 🎊
      • :one: HTML-First Framework
        • Core of Ember is HTML and CSS
        • No special Ember-specific tweaks…Just copy paste :scissors:
        • Components can simply be a natural extension of HTML → Driven by HTML and Templates
          • Template only components (Improved performance, no this in template) 🏎️
      • :two: 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 in shareURL change
            • @tracked properties
            • Even works on Native JS classes
      • :three: 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();
          }
        }
        
    • 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 🥇

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
        • :one: Warmup the application - Create baseline objects
        • :two: First snapshot
          • Now, do the suspected memory leak action
        • :three: Second snapshot
          • Now, repeat the action
        • :four: Third snapshot
  • 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 a Registry
  • 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
  • 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
  • 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
  • :one: Tools 🛠️
    • ESLint
      • Disallow unreachable code
        function foo() {
          let retVal = 1;
          return retVale;
          returnValue = 2; // <-- Unreachable code detected ts(7027)
        }
        
    • 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;
      });
      
  • :two: 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
  • :three: How does syntax transformation work?
    • Parsing
      • Lexical analysis (Scanning/Tokenization)
      • Syntax analysis - AST Explorer (Includes Glimmer parser ✨)
    • Transformation
    • Code Generation

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
    • 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
  • 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 to DS.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
  • 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
  • First Paint (Is it happening?) → First Contentful Paint → First Meaningful Paint (Is it useful?) → Time to Interactive (Is it usable?)
  • How can I help?

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

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
  • 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
      

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 and triggerKeyEvent
    • 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
  • Logical properties
    • inline: start to end of a line of text in the block
    • block: start to end of the block of text
  • dir=rtl and writing-mode: vertical-lr support for free
  • grid-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
    • repeat(<count>, <length>)
    • repeat(12, 1fr) === 12 column Bootstrap
  • grid-area: A grid-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 😨

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
  • 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
    • :one: Dev vs Prod
      • Sources tab
      • Breakpoints
      • Pretty print formatting for minified JS
    • :two: External Libraries
      • Stack trace ⛔
      • Don’t be afraid to step in 🚶‍♀️
      • Addon vs NPM library code location
    • :three: Not My Code
      • Use the Ember Inspector
      • Find the function location

Talking to Your Dog with Ember - Robert Wagner

  • wuf.plus 🐶
  • Web Audio API
    • fftSize (Fast Fourier Transform) and frequencyBinCount
    • 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
  • 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
    • Phase 2: Codemods
    • Phase 3: Prepare for Glimmer
    • Phase 4: Adopt Glimmer
      • Preliminary component refactors
        • Empty tagName
        • Migrate classNames, classNameBindings, attributeBindings
        • {{on "click" (fn this.foo 'bar')}} event handlers
        • Modifiers
      • Finish Glimmer conversion
        • computed() / this.set()@tracked
        • Convert lifecycle hooks
  • Classic vs Octane Cheat Sheet
  • Ember Atlas Recommended Migration Order