Public Speaking

for Developers

Eve Porcello

@eveporcello

eve@moonhighway.com

Agenda

Start: 7:00am

Break: 7:45am

End: 9:30am

  • Writing a Talk Proposal
  • Mapping Talk Content
  • Creating an Opener
  • Storytelling Techniques
  • Live Coding
  • Rehearsing Your Talk
  • Incorporating Feedback
  • Handling Anxiety

Tahoe City, CA

 

This is a little weird.

Make it your own.

Take what is useful.

Why do you want to give tech talks?

 

 

Think back to a great talk you saw. 

 

Why was it good?

Writing a Talk Proposal

Talks are entertainment.

Proposals

  • Focus on how people will benefit
  • Who is it for?
  • Pique people's interest 
  • What's the hook?

Write Down One Topic That You Could Give a Talk On

Creating a Catchy Title

Algebraic Effects in React

FROM

Algebraic Effects, Fibers, Coroutines... Oh my!

TO

React's Component Lifecycle

FROM

The Life Cycle Methods and The Wolf: A Musicological Romp

TO

JavaScript Games

FROM

Build a Chrome Dinosaur Game in 15 Minutes

TO

React, Vue, and Svelte

FROM

React, Vue, and Svelte as Teen Movie Archetypes

TO

  • Have a point of view

  • Use alliteration

  • Make it sensational!

Writing a Title

Activity!

  • Create a title for that topic
  • https://sumo.com/kickass-headline-generator/

Abstracts

Proposals

  • Focus on how people will benefit
  • Who is it for?
  • Pique people's interest 
  • What's the hook?

Who's the jock? The nerd? The misfit? Who's the type A overachiever, or the moody artist, or the partier?

Get to know each of these JavaScript frameworks through the hallowed medium of the teen comedy.

In this talk, we'll dig into what makes these frameworks unique, and as in every good millennial teen movie, you'll leave with a better understanding of each one.

React, Vue, and Svelte as Teen Movie Archetypes

Activity: The Abstract

  • 3 sentences
    • 1st sentence: Catchy 1st line (maybe a question)
    • 2nd sentence: What you'll cover
    • 3rd sentence: What people will learn

Use your own topic or enhance this abstract with specifics.

Have you ever wanted to learn Node.js? In this talk, we'll dig deeper into Node.js. You can expect to walk away knowing Node.js.

Organizing Your Content

Where to Start

  • Build a Demo / Sample Application

Where to Start

  • Sticky Notes

Where to Start

  • Outline in a Document
  • Then outline in Slides

GraphQL intro 

Query Language and the spec

Fields in a query 

  1. All of JavaScript
  2. All of GraphQL
  3. All of Prisma

40 mins

Start with Emotion

  • Excitement
  • Sadness about Failure
  • Personalization
  • Capture attention in the first 60 seconds

Activity!

  • Volunteer
  • 30 seconds

End Definitively

  • Avoid trailing off
  • "Thank You"

Map every minute in between

Presentation Skills

When Crafting Your Talk

  • Bring yourself
  • Get excited
  • Have a point of view
  • Relate to what you're presenting with personal experience

If you're in person...

Face Forward

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  const allUsers = await prisma.user.findMany({
    include: { posts: true },
  })
  console.log(allUsers)
}

main()
  .finally(async () => {
    await prisma.$disconnect()
  })

😀

Live Coding

import React, { Component } from 'react'
import { storage } from '../../client'
import { PLAYER_ROOT_QUERY, LISTEN_FOR_INSTRUCTIONS, LOGOUT } from '.'
import { WaitingForInstructions } from './ui/WaitingForInstructions'
import { End } from './ui/End'
import { Team } from './Team'
import { Game } from './Game'

export class CurrentPlayer extends Component {

    logout = () => {
        this.props.client.mutate({ mutation: LOGOUT })
        storage.removeItem('token')
        this.props.client.writeQuery({
            query: PLAYER_ROOT_QUERY,
            data: {
                me: null
            }
        })

    }

    componentDidMount() {
        this.stopListeningToInstructions = this.props.client
            .subscribe({ query: LISTEN_FOR_INSTRUCTIONS })
            .subscribe(({ data, error }) => {

                if (error) {
                    return console.error(error)
                }

                console.log('new instructions: ', data.instructions.endEvent)

                this.props.client.writeQuery({
                    query: PLAYER_ROOT_QUERY,
                    data: {
                        me: data.instructions
                    }
                })

            })
    }


    componentWillUnmount() {
        if (this.stopListeningToInstructions) {
            this.stopListeningToInstructions._cleanup()
        }
    }

    render() {
        const { avatar, name, login, team, playingGame, instrument, endEvent } = this.props

        return playingGame ?
            <Game instrument={instrument} /> :
            team ?
                <Team {...team}
                    avatar={avatar}
                    onLeave={this.logOut} /> :
                    endEvent ? 
                        <End /> :
                        <WaitingForInstructions
                            name={name || login}
                            avatar={avatar}
                            onLeave={this.logout} />
    }
}
import React from 'react'
import { ExitButton } from './ExitButton'
import styled from 'styled-components'

export const WaitingForInstructions = ({ name, avatar, onLeave=f=>f }) =>
    <Container>
        <figure>
            <img src={avatar} width={48} height={48} alt="" />
        </figure>
        <h1>
            <span>Welcome,</span>
            <span>{name}</span>
        </h1>
        <ExitButton onClick={onLeave} />    
    </Container>

export class Wejay extends Component {

    state = { loadingMusic: true }
    
    async componentDidMount() {
        const files = [bass,drums,percussion,sampler,synth]
        const tracks = await loadAllAudio(files)
        tracks.forEach(track => {
            track.volume = 0
            track.loop = true
        })
        tracks.forEach(track => track.play())
        let [BASS,DRUMS,PERCUSSION,SAMPLER,SYNTH] = tracks
        this.tracks = {BASS,DRUMS,PERCUSSION,SAMPLER,SYNTH}
        this.setState({ loadingMusic: false })
    }

    componentWillUnmount = () => {
        Object.keys(this.tracks).forEach(instrument => this.tracks[instrument].src = '')
    }

    instruments = data => 
        data.gameChange.playingMusic.map(({ instrument }) => instrument)  

    isPlayingMusic = (data, instrument) => data && 
        -1 !== this.instruments(data).indexOf(instrument)
    
    playTrack = data => {
        if (data) {
            this.playSound(this.instruments(data))    
        }
    }

    playSound = instruments => 
        Object.keys(this.tracks).forEach(key => 
            this.tracks[key].volume = instruments.indexOf(key) !== -1 ? 1 : 0
        )

    render() {
        const { players } = this.props
        const { loadingMusic } = this.state
        return loadingMusic ?
            <LoadingScreen /> :
            <Subscription subscription={LISTEN_FOR_GAME_CHANGES}>
                {({ data }) => {
                    this.playTrack(data)
                    return (
                        <Container>
                            {(data && data.gameChange.faces.length) ? 
                                <Audience faces={data.gameChange.faces} /> : 
                                null
                            }
                            {players.map(p => 
                                <Musician key={p.login} 
                                    avatar={p.avatar}
                                    login={p.login}
                                    instrument={p.instrument} 
                                    playingMusic={this.isPlayingMusic(data, p.instrument)}/>
                            )}
                        </Container>
                    )
                }}
            </Subscription>
    }

}
    

export class Wejay extends Component {

    state = { loadingMusic: true }
    
    async componentDidMount() {
        const files = [bass,drums,percussion,sampler,synth]
        const tracks = await loadAllAudio(files)
        tracks.forEach(track => {
            track.volume = 0
            track.loop = true
        })
        tracks.forEach(track => track.play())
        let [BASS,DRUMS,PERCUSSION,SAMPLER,SYNTH] = tracks
        this.tracks = {BASS,DRUMS,PERCUSSION,SAMPLER,SYNTH}
        this.setState({ loadingMusic: false })
    }

    componentWillUnmount = () => {
        Object.keys(this.tracks).forEach(instrument => this.tracks[instrument].src = '')
    }

    instruments = data => 
        data.gameChange.playingMusic.map(({ instrument }) => instrument)  

    isPlayingMusic = (data, instrument) => data && 
        -1 !== this.instruments(data).indexOf(instrument)
    
    playTrack = data => {
        if (data) {
            this.playSound(this.instruments(data))    
        }
    }

    playSound = instruments => 
        Object.keys(this.tracks).forEach(key => 
            this.tracks[key].volume = instruments.indexOf(key) !== -1 ? 1 : 0
        )

    render() {
        const { players } = this.props
        const { loadingMusic } = this.state
        return loadingMusic ?
            <LoadingScreen /> :
            <Subscription subscription={LISTEN_FOR_GAME_CHANGES}>
                {({ data }) => {
                    this.playTrack(data)
                    return (
                        <Container>
                            {players.map(p => 
                                <Musician key={p.login} 
                                    avatar={p.avatar}
                                    login={p.login}
                                    instrument={p.instrument} 
                                    playingMusic={this.isPlayingMusic(data, p.instrument)}/>
                            )}
                        </Container>
                    )
                }}
            </Subscription>
    }

}
import React, { Component } from 'react'
import { random } from 'faker'
import styled from 'styled-components'


export class ConnectedPlayer extends Component {
    bounds = {
        height: window.innerHeight,
        width: window.innerWidth
    }
    constructor(props) {
        super()

        let top, left
        switch(Math.floor(Math.random()*8)) {
            case 0: 
                top = `${random.number({ min: 0, max: this.bounds.height * .25 })}px`
                left = `${random.number({ min: 0, max: this.bounds.width * .25 })}px`
                break
            case 1:
                top = `${random.number({ min: 0, max: this.bounds.height * .25 })}px`
                left = `${random.number({ min: this.bounds.width * .25, max: this.bounds.width * .75 })}px`
                break
            case 2: 
                top = `${random.number({ min: 0, max: this.bounds.height * .25 })}px`
                left = `${random.number({ min: (this.bounds.width * .75)-100, max: this.bounds.width-60 })}px`
                break
            case 3: 
                top = `${random.number({ min: this.bounds.height * .25, max: this.bounds.height * .75 })}px`
                left = `${random.number({ min: 0, max: this.bounds.width * .25 })}px`
                break  
            case 4: 
                top = `${random.number({ min: this.bounds.height * .25, max: this.bounds.height * .75 })}px`
                left = `${random.number({ min: (this.bounds.width * .75)-100, max: this.bounds.width-60 })}px`
                break       
            case 5: 
                top = `${random.number({ min: this.bounds.height * .75, max: this.bounds.height-60 })}px`
                left = `${random.number({ min: 0, max: this.bounds.width * .25 })}px`
                break  
            case 6: 
                top = `${random.number({ min: this.bounds.height * .75, max: this.bounds.height-60 })}px`
                left = `${random.number({ min: this.bounds.width * .25, max: this.bounds.width * .75 })}px`
                break
            default: 
                top = `${random.number({ min: this.bounds.height * .75, max: this.bounds.height-60 })}px`
                left = `${random.number({ min: (this.bounds.width * .75)-100, max: this.bounds.width-60 })}px`
                break          
        }

        this.state = { top, left }

    }
    render() {
        const { avatar, login, team } = this.props
        const { top, left } = this.state
        return (
            <Container teamColor={team && team.color.name} top={top} left={left}>
                <img src={avatar} alt={login} />
            </Container>
        )
    }
}    

const Container = styled.div`
    position: fixed;
    top: ${props => props.top};
    left: ${props => props.left};
    img {
        width: 60px;
        height: 60px;
        border-radius: 50%;
        border: solid 5px ${props => props.teamColor ? props.teamColor : props.theme.colors.contrast};
    }
`

What

Terminal

VSCode

Start from Scratch
Minimize Cut and Paste

Zoom In Then Zoom Out

(Have a backup)

Storytelling

Stories

  • Humor
  • Vulnerability
  • Connection
  • Memory

Tricks

  • Rule of threes
  • Raise the stakes

Formats

  • Hero's Journey
  • Start in the Middle
  • Post Mortem

Activity: Today!

  • What's the most interesting thing that has happened to you today?

Activity: Success & Failure

  • Tell me about a time when you felt really successful/unsuccessful at work.
    • Who were you with?
    • Why was it important?
    • When you think back, what emotions do you have?

Dealing with Pre-Talk

Anxiety

If you look relaxed, you're prepared.

Rehearsing the Talk

  • Create a rehearsal schedule
  • Run through the content at least once with a friend, co-worker, or family member

Make it feel real

  • Present in as close to the conditions as you can (standing, etc)
  • Present at a local or online event

Tech Rehearsal

  • Go to the venue 
  • Plug in your computer if possible
  • Share your screen
  • Go to the worst seat
  • From tech rehearsal to presentation, don't change your demo

Have backups 💥

  • Slides 
  • Wifi
  • Dongles

You're the talent.

Treat yourself accordingly!

Play Music

One Cool Thing

Next Steps

  • Write down 3 events that you'd like to speak at
  • Send your abstract to one of your fellow ambassadors
  • Send in your abstract!

Thank You!

  • @eveporcello
  • eve@moonhighway.com

Public Speaking for Developers

By Moon Highway

Public Speaking for Developers

  • 481