Skip to content

Instantly share code, notes, and snippets.

@briangonzalez
Last active January 7, 2020 15:51
Show Gist options
  • Save briangonzalez/2ece66bfffff31ddc230ca8342e80b3e to your computer and use it in GitHub Desktop.
Save briangonzalez/2ece66bfffff31ddc230ca8342e80b3e to your computer and use it in GitHub Desktop.
briangonzalez.org
# This file is blank, but here in order to have more clear view of the gist from within github.

👋! I'm Brian, and I am a software guy. I like leading teams and building products.

Currently, I do this at the company I co-founded, Curri. We're revolutionizing that way supplies are brought to/from construction sites.

I used to spend my days building world-class e-commerce experiences amongst the best in the biz at Dollar Shave Club. I've also worked with brands like Sweetgreen, VMWare, Geni, MyHeritage, just to name a few.

I love writing code, especially Javascript. I also love thinking about how teams of software engineers can do their jobs more efficiently.

You can find more about me on the Twittersphere or the Githubsphere. You can also read some of my posts if you'd like.

I adhere to the 80/20 principle. I listen to a lot of podcasts. I've read a fair amount of books (here are some of my favs). I've run 3 marathons. I have a masters degree from Norway (for free). I used to own a ‘72 and an '84 VW Bus, but now I am riding in my '14 Mercedes Sprinter. Fancy, I know. I currently reside in Ventura, CA.

Oh, and this whole blog was written with Gustavo – a blog platform atop Github Gists and Nuxt.

Colophon

  • Editor: VSCode w/ Operator Mono
  • Stack: Gustavo
  • Fonts: SFMono & Inconsolata

Alfred has become such an integral part of my workflow over the years. One thing that always bugged me about OSX is that when I would receive a text message notification, I could read the text, but would need to click on the notification or open Messages to respond.

I thought to myself: What if I could respond from Alfred directly?

With Script Debugger and Alfy in-hand, I was able to whip up an Alfred plugin.

You can install it yourself like so:

npm install --global alfred-messages

You can find the code on Github.

Here's a demo:

From Remote by Jason Fried and DHH

You certainly don't need everyone physically together to create a strong culture. The best cultures derive from actions people actually take, not the ones they write about in a mission statement. Newcomers to an organization arrive with their eyes open. They see how decisions are made, the care that's taken, the way problems are fixed, and so forth.

* Highly influential

I often consider the concept of a "career" and think about how harmful it is. I know the term has various meanings, but I often find it defined as "the running list of all job titles one has held over their working life". This usage seems to be a more modern one.

A societal construct of the 20th and 21st centuries, career as we know it today can cause good people to act in odd, harmful ways.

We are conditioned to desire a "career trajectory" that trends upward. Accountant to Manager, Manager to Director, Director to Sr. Director, Sr. Director to VP. Why does it matter? We even have a name for this ladder. The Career Ladder.

What happens to our career when we grow old and pass? Is it etched into our gravestone or recited in our eulogy? Nope. It's ripped up and forgotten. What is remembered and talked about? What you did. What you made. Who you helped. How you lived a life of humility and servitude.

If a move down the career ladder means a happier, fuller life, I hope we'd all make the right move.

Couldn't have said it better myself:

The big issues facing us today are twofold: improving engineer autonomy while maintaining system security in the production infrastructure, and evolving a safety net for engineers to deploy quickly with confidence.

From The Evolution of Code Deploys at Reddit

There are many ways to copy an array in JavaScript, and with ES6, that list has grown even longer.

Here are some options I came up with (with the help of Twitter). They are shown in order of performance.

const names = [ 'Jon', 'Jacob', 'Jeff' ]

const copy1 = names.slice()
const copy2 = [].concat(names)
const copy3 = Object.values(names)
const copy4 = [...names]
const copy5 = Array.of(...names)
const copy6 = JSON.parse(JSON.stringify(names))
const copy7 = names.map(i => i)
const copy8 = Object.assign([], names)

Performance results can be found on jsperf.

Can you think of any others?

As your Ember app becomes more complex with user authentication, tricky redirect rules, error substates, etc., you'll often find yourself reaching for Ember's transitionTo method, but this may not always be the right tool for the job.

Maybe you need to redirect a user away from the login page if they have it bookmarked but are already logged in, or redirect them to the login page if the try to access their account but are authenticated.

Or perhaps you're running an A/B test and don't want users in a certain test to see a certain page.

What if the user is trying to access the sign-up page and they're already signed up? We'll redirect them as well.

This article will attempt to shed light on the tools you have at your disposal in Ember

  • transitionTo
  • intermediateTransitionTo
  • replaceWith
  • Transition#retry

Let's start with this high-level breakdown of each approach, then we'll walk through a few scenarios where you'd use one over the other.

State Management History Operation Controller Equivalent
transitionTo Manual Push transitionToRoute
replaceWith Manual Replace replaceRoute
intermediateTransitionTo Manual None None
Transition#retry Auto Push n/a

Scenario 1 - Redirecting away from an authenticated page

Take an unauthenticated user visiting /account, a route that requires user authentication. The desired UX is to kick them to /login, and once they login, to send them back to the account route:

// app/routes/account.js

beforeModel(transition) {
  transition.abort();
  this.replaceWith('login');
}

// app/routes/login.js

onLoginSuccess() {
  this.replaceWith('account');
}

The beauty of this approach is that the you don't break the user's back button as you send them to log in. If you blindly used transitionTo, the user's back button would likely break and they'd become trapped. No bueno.

Scenario 1 - API failure

Let's say your API intermittently fails or times out. The desired UX is to show the user some sane error messaging, and perhaps tell them to refresh shortly (or refresh the browser on their behalf). intermediateTransitionTo is the right tool for the job here.

// app/routes/application.js

 actions: {
    error(error) {
      const errors = error.errors || [];

      const isTimedOut = errors.find((e) => typeof e.detail === 'string' &&
                         e.detail.search('timed out') !== -1);
      const isAPIDown = errors.find((e) => e.status === 423);

      if (isAPIDown || isTimedOut) {
        this.intermediateTransitionTo('application-error');
      }
    },
  }

Remember, intermediateTransitionTo does not modify the URL or the state of window.history. When the page is refreshed (or programmtically refreshes), the route the user intended to visit is preserved and will be reloaded.

When to use transitionTo

One mistake I often see young Ember developers make is overusing transitionTo.

This bit of markup with a corresponding action in one's route:

<button {{ action 'transitionToAccount' }}>
  Take me to my account
</button>

...could be written more succinctly (no action!) as:

{{#link-to 'account' class='button'}}
  Take me to my account
{{/link-to}}

So my advice is to use transitionTo when you want your app to behave as if the user had clicked on a link. But, don't use transitionTo when a simple link-to is more appropriate.

If you enjoyed this post, follow me on Twitter as I'll be writing more on Ember over the coming months.

The algorithm is pretty straightforward once you wrap your mind around it:

  1. Bind to all keydown events
  2. When an event occurs, give it a unique slug, eg. ⌥-t corresponds to pressing CTRL and t
  3. Add to an array inside a map of all currently known presses
  4. Clear all known timeouts for a given slug
  5. Create a timeout to clear known presses after some threshold. In the example below I am using 300ms
  6. Measure length of array in map, if equal to 2, double keypress is found

And here's the code:

const map = {}
document.addEventListener('keydown', e => {
  const slug = `${ e.shiftKey ? '⇧-' : '' }${ e.ctrlKey ? '⌥-' : '' }${ e.metaKey ? '⌘-' : '' }${e.key}`
  map[slug] = map[slug] || []
  map[slug].forEach(clearTimeout)
  map[slug].push(setTimeout(() => delete map[slug], 300))
  if (map[slug].length === 2) {
    console.log(`Double keypress of ${slug}`)
  }
})

Tim Ferriss uses the D.S.S.S method when he sets off to learn a new skill. Why? It's simple. This method frontloads the bulk of the learning (hello 80/20 principle), lowers the barrier to entry, tightens the feedback loop, and creates accountability.

The principle essentially breaks down learning into these four steps:

  1. Deconstruct: identify the key characteristics
  2. Selection: select the characteristics that will provide 80% of the benefit for 20% of the effort
  3. Sequence: run small trials of learning to figure the best ordering of these characteristics
  4. Stakes: add in an element of accountability to entice yourself to endure

Let's take this rubric for a spin on a passion of mine: surfing.

Deconstruct

  • Non-surfboard gear (wetsuit, roof rack, wax)
  • Surfboard
  • Understanding the tides
  • Paddling out
  • Catching the wave
  • Riding the wave
  • Turning

Selection

In this step, it's important to identify (a) what you can achieve quickly with your current skillset (b) what might cause you to quit if not overcome shortly after starting. For me and surfing:

  • Get the right gear
  • Get the right surfboard
  • Paddle out frequently
  • Catch waves, no matter how small

Sequence

The one mistake I made during this phase was going out with a cheapo board. Did the board really matter? No. Was I ready, skillwise, for a better board? No. However, my cheap foam Costco special made me feel like I didn't belong out there.

I upgraded, to a mid-level board and instantly leveled up by paddling out much more frequently. Win.

Stakes

I never actually applied any "stakes", but I am considering making myself accountable in the following ways.

  • If I don't go out more than once a week, donate to anti-charity
  • If I don't go out more than once a week, surf foam surfboard the following week

A very common problem when working with menu bar electron apps is setting the tray icon to some dynamic text.

For example, what if you had an electron app that copied the 2FA auth code that was just sent to you via iMessage (sorry, shameless plug) and you wanted to change the icon momentarily to said code.

Here's what the final result looks like:

To achieve this effect, I used a library called merge-img, which simply horizontally concatenates png files. I used 10 number icons (png files), 0 through 9, and I create an image on the fly and set it as the icon.

This example below is Typescript, but you get the idea hopefully:

import * as mergeImg from 'merge-img'

// For example, the code argument below might be the string `123456`
function updateTrayIconWithCode (code: string, tray: Tray): void {
  const numberPaths = code.split('')
  .map(n => path.join(__dirname, `numbers/${n}.png`))

  mergeImg(numberPaths)
  .then((img: any) => {
    const numericalIcon = path.join(__dirname, 'numerical-icon.png')
    img.write(numericalIcon, () => {
      tray.setImage(numericalIcon)
    })
  })
}

Enjoy!

The longest lived businesses in the world aren’t the ones that were biggest in their day. Many of them are family firms, or small to mid-sized enterprises content with steady evolvement of their niche. Content with enough.

A great read from DHH reminds me of what I've been thinking about a lot myself. I've seen growth pull owners away from the "front lines" and ultimately away from what excited them in the first place: rolling up their sleeves and making a broad-sweeping impact.

Ever login to a Google Hangouts only to have everyone tell you that they can't hear you?

Close your hangout, paste this little trick in your terminal, then re-join the Hangout.

sudo killall coreaudiod

This whole blog is built using a single Github Gist.

Why? Well earlier this year one of my best buds (Jeff W.) and I set out to build a blogging platform atop Nuxt and Github Gists. After a few iterations on names and architecture and a month or so, behold Gustavo, which now powers this very blog.

With a simple naming schema, pushing content out will be painless. I can simply pop into the Gist interface, create a new post or page, then publish. This was exactly the vision.

You can find Gustavo on Github.

I came across this comment while scouring the web, and wow, it's compelling.

The comment is a reply to a post entitled [creepy filter] Is it normal to become this distracted from seeing an attractive person in public? where the OP goes into detail about how distracted they become upon seeing an attractive female. The OP is soliciting feedback on how to alter their behavior.

The commenter equates low-grade sexual harassment (what the OP is doing) with being asked for a dollar each day by a subset of all individuals. Regardless of who is and who isn't asking for the dollar, it's natural to treat everyone as if they want a dollar.

An excerpt from the comment:

A substantial portion of the population believes that they have a right to a woman's attention, and if they don't get it, they get offended, mean, and sometimes even violent. You're just one of many, many men who believe that any woman you like owes you something. It's exhausting and sometimes terrifying to be on the receiving end of that.

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

tl;dr Prefer interface types over type aliases.

First, let’s take a look at what the spec says:

Interface types have many similarities to type aliases for object type literals, but since interface types offer more capabilities they are generally preferred to type aliases.

But what are these capabilities? Well, interfaces can be extended in a very similar manner to classes

interface Plant {
  color: string
  height: number
}

interface Cactus extends Plant {
  spineCount: number
}

as well as augmented or merged allowing for properties to be added later on down the line:

interface Cactus extends Plant {}

interface Spine {
  length: number
}

// ...then later on
interface Cactus {
  spines: Spine[]
}

In many cases, an interface can be written as a type alias, but the following flexibility is lost (from the spec):

  • An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.
  • An interface can have multiple merged declarations, but a type alias for an object type literal cannot.

Lopp speaks of this cancerous Grapevine within a company. Do you feed it, or do you kill it? It's easy to feed it, because, as Lopp points out, "Being part of a secret feels powerful."

Without active prevention, the Grapevine can be stronger than any individual. While you can’t kill the Grapevine, you can dubiously stare at it when it shows up on your doorstep and simply ask the person delivering it, “Do you actually believe this nonsense? Do you believe the person who fed you this trash?”

Managing Humans by Michael Lopp

Today, I'll run my third marathon, the LA marathon. I'll be running with my boy @ratherfancy. We begin at Dodgers Stadium and end on Ocean Avenue in Santa Monica.

This will be my first race where I wasn't on a special diet (2016, keto) nor training with an actual marathon regiment (2014).

I find pushing my body to its upper bounds fascinating. Wish me luck.

I read a Medium post called Lazy Leadership this weekend, and its points on delegation and building a team which operates like a machine resonated with me.

Some entrepreneurs never break through the delegation barrier and get stuck along the way. They try hiring someone, and when that person doesn’t behave exactly like they would, they jump in and take over.

Although I am not an entrepreneur, I lead a small team of developers and I like to think we operate like a small business within the company.

We have goals, accountability, consequences, deadlines, projects, etc. all baked into our humble little team.

Shielding

It’s often said that the best leaders shield their team. Think pressure, politics, and drama.

While I think this notion is a false one, I often find myself caught up in it and doing it.

Whether that be rolling up my sleeves when a last minute request comes in so the team doesn’t have to. Or protecting the team from deadline talk so they don’t get stressed out. Or commandeering tough interactions and relationships on their behalf.

Do they actually want this? Maybe, maybe not. Does this mean I should shield nonetheless? No.

Building the Machine

Once I started thinking about my business like a machine, I realized that there were people out there who relished the opportunity to travel for work and thrived doing the same thing.

I can think of at least 2 things which I could hire for or delegate off of my plate to make the team more efficient:

  1. Scheduling
  2. Project Management

I wonder what others on the team are doing outside of their wheelhouse.

Here's a small flow I like to use when learning a new technology. I follow these one-by-one, moving from one to the next, skipping those which seem unnecessary.

  1. google: <topic> ELI5
  2. google: <topic> diagram
  3. google: differences between <topic> and <something you already know well>
  4. google/youtube: <topic> introduction
  5. youtube: <topic> tutorial (sort by length, favor videos no longer than 9 min.)
  6. google: <topic> best practices
  7. google: <topic> documentation
  8. Go off and build something super small in said technology. Limit yourself to 1-5 hours.

One of my favorite subreddits, LifeProTips, got me thinking that I might be able to contribute some of my own.

Here are just a few that bubbled to the top of my head that work for me:

  • K2R works wonders to remove grease spots from clothes.
  • If you pay for laundry in quarters, get $100 worth at a time from the bank.
    • 1 load/wk. * ($1.50 wash + $ 1.25 dry)
    • $2.75 * 52 wks. = $143 per year
  • Keep your Amazon app handy and buy things the moment you think of them, and don't let them take up mental space. Especially useful when in the kitchen.
  • Can’t download something too big over data on your phone because you see the “100MB” limit? Tether to a friends device and trick your phone into thinking you’re on wifi.
  • Turn an old stereo into a wireless one using a cheap bluetooth receiver like this one.
  • Make a room feel instantly clean by dusting the largest surface. This will partially trick your brain into thinking the whole room is clean.
  • Surf or hike and don't want to lug your keys around? Get a lock box, put your key inside, and attach it to the door handle of your car. I recommend this one.

One of the key pieces of my development workflow is using iTerm with each of my project's commands running in its own pane. Some of my projects require 5+ commands - think vagrant up, ember build --watch, redis-server, rails s, etc.

Who has time to remember all this, much less manually configure iTerm with each of these commands each time?

To that end, we've created a new tool, called mert, which automates iTerm pane management. I previously used termrc, but it was brittle and imcompatible with iTerm 3. mert is built in node and uses Javascript for Automation (jxa) at its core.

Find mert on Github

I was listening to Adventures in Elm by Jessica Kerr and I was stuck for a while on the following idea:

My fingers work...I’d rather do a little more work with my fingers and less work with my brain because I want to be able to save my decision power for my actual business logic.

The idea is that, due to the contraints of a statically typed language like Elm, you’re forced into writing code that your future self has an easier time reasoning about. I get it.

It’s this very notion which has led to a lot of shaming of Javascript as of late.

I, however, think the conversation is more nuanced.

As someone who enjoys mentoring new developers, the utililty of opening literally any browser and pressing CMD + OPT + i to invoke a REPL and tinker and prototype and explore cannot be understated. Javascript is fast, expressive, and it runs everywhere.

I do believe maintainability is crucial. However, shortening the path to gratification, especially for new developers, is invaluable.

Your Speed

Consider the “Your Speed” traffic sign, which embodies the Evidence, Relevance, Consequences, and Action Feedback loop cycle concept – outlined here.

  • The driver is immediately shown evidence that they’re speeding
  • It’s put into perspective by contrasting the speed limit
  • The driver is reminded about consquences – tickets, citations, etc.
  • The driver slows down as a results.

Javascript is the “Your Speed” sign for young developers. With little ceremony – install steps, etc. – a developer is instantly injected into this feedback loop and they’re able to modify their behavior nearly real-time.

The word "my" is toxic in the workplace for leaders.

It implies ownership. It implies dominance. It implies a team of sub-ordinands. It implies singular ownership. It implies hierarchy.

It's easy to say, and it feels good to say.

My team. My project. My initiative. My feature. My test.

The words we use day-to-day evoke emotion.

Some alternatives: The team. This project. Our initiative. The feature. The test.

Here's a nice and simple explanation of a Naive Bayes classifier used in machine learning:

A classifier is a way to use math to identify something. For example, you see something on the playground that is red. It could be a playground ball, or maybe a rabbit, or a tennis ball - but it's probably not a rabbit or tennis ball because you've never seen a red one of those before.

A fellow named Thomas Bayes figured out that if you actually knew how often playground balls, rabbits, and tennis balls were red, you could use math to work out a number that says how often a red thing that you see is a playground ball, rabbit, or tennis ball. Pretty neat. Maybe you notice other things about what you see too: it's size, shape, whatever. Well, Bayes' rule works even when you have more than one way to describe what you're looking at.

A Bayes Classifer is, then, something that uses Bayes rules to figure out how often red things are playground balls, how often they are rabbits, and how often they are tennis balls and then picks the one that happens most often. If most playground balls are red, and most rabbits an tennis balls are not, then when you see something that's red, it's probably a playground ball.

A Naive Bayes Classifier is one where you have several things that describe what you are looking at, like it's color, size, whether it has eyes or not… and you assume that they have nothing to do with each other. The color of something has nothing to do with it's size or whether it has eyes or not. This might not be a good a assumption, for example, there are very few purple things with eyes. But we may not know that, so we'll just say that it is so because it makes the math much easier.

This weekend was full of new things:

  • I dove in head first and switched to vim
  • Operator Mono as my new code editing font of choice
  • Got an Amazon Echo - I'll help build a Dollar Shave Club Skill this summer with the engineering team and some new interns
  • I launched a new site: new design & new tech stack (Hexo, VueJS, Github Pages)
  • Game of Thrones S06E06
  • confident != arrogant
  • rest != laziness
  • driven != busy
  • confident != arrogant
  • fun != non work
  • smart = complex
  • thoughtful != silent
  • candid != blunt

Here are a couple of modern ways to parallize requests. Disclaimer, this code has not been executed.

Using Promise.all (Bluebird)

const Promise = require('bluebird');

const getResponses = async (urls) => {
  const requests = urls.map(u => fetch /* fetch is a newish builtin API */)
  const responses = await Promise.all(requests)
  return responses
}

const urls = [
  'https://foo.com/bar.json',
  'https://foo.com/baz.json',
  'https://foo.com/qux.json'
]

(async () => {
  const responses = getResponses(urls)
})()

Using async/await & for-of

const getResponses = async (urls) => {
  const requests = urls.map(u => fetch /* fetch is a newish builtin API */)
  const responses = []

  for (let url of urls) {
    const response = await fetch(url)
    responses.push(response)
  }
  
  return responses
}

const urls = [
  'https://foo.com/bar.json',
  'https://foo.com/baz.json',
  'https://foo.com/qux.json'
]

(async () => {
  const responses = getResponses(urls)
})()

Update #1: This is a post of what might eventually land in the Ember documentation. Until then, enjoy.

Update #2: It landed! Find the docs here.

Polymorphism is a powerful concept which allows a developer to abstract common functionality into a base class. Consider the following example: a user with multiple payment methods. They could have a linked Paypal account, and a couple credit cards on file.

Note that, for polymorphism to work, Ember Data expects a "type" declaration polymorphic type via the reserved type property on the model. Confused? See the API response below.

First, let's look at the model definitions:

/* app/models/user.js */
import DS from 'ember-data';
let { hasMany } = DS;

export default DS.Model.extend({
  paymentMethods: hasMany('payment-method', { polymorphic: true })
});
/* app/models/payment-method.js */
import DS from 'ember-data';
let { belongsTo } = DS;

export default DS.Model.extend({
  user: belongsTo('user', { inverse: 'paymentMethods' }),
});
/* app/models/payment-method-cc.js */
import PaymentMethod from './payment-method'
import DS from 'ember-data';
import Ember from 'ember';
let { attr } = DS;
let { computed } = Ember;

export default DS.Model.extend({
  obfuscatedIdentifier: computed('last4', function () {
    return `**** **** **** ${this.get('last4')}`
  })
});
/* app/models/payment-method-paypal.js */
import PaymentMethod from './payment-method'
import DS from 'ember-data';
import Ember from 'ember';
let { attr } = DS;
let { computed } = Ember;

export default DS.Model.extend({
  linkedEmail: attr(),
  obfuscatedIdentifier: computed('linkedEmail', function () {
    const last5 = this.get('linkedEmail')
      .split('').reverse().slice(0, 5).reverse().join('');
    return `••••${last5}`
  })
});

And our API might setup these relationships like so:

"data":{
   "id":"8675309",
   "type":"user",
   "attributes":{
      "name":"Anfanie Farmeo"
   },
   "relationships":{
      "payment-methods":{
         "data":[
            { "id":1, "type":"PaymentMethodPaypal" },
            { "id":2, "type":"PaymentMethodCc" },
            { "id":3, "type":"PaymentMethodApplePay" }
         ]
      }
   }
},
"included":[
   {
      "id":1,
      "type":"PaymentMethodPaypal",
      "attributes":{
         "linked-email":"ryan@gosling.io",
      }
   },
   {
      "id":2,
      "type":"PaymentMethodCc",
      "attributes":{
         "last4":"1335"
      }
   },
   {
      "id":3,
      "type":"PaymentMethodCc",
      "attributes":{
         "last4":"5513"
      }
   },
]

I've created a little repo to play around with.

When I am working on a node project, I am usually either working with some API (right now I am hacking on the Amazon API) or working with large sets of data. More often then not, I need to log some object to the console and inspect it.

The issue with logging an object using console.log in node is that each nested object is displayed as [Object]. Helpful right?

A little Googling around surfaces reccomendations of JSON.stringify(obj) or instead installing yet another npm module.

The truth is, node has this built in.

util.inspect

One of node's core libraries, util, has a method inspect which is the right tool for the job. Here's how to use it:

var util = require('util');
var obj = { a: { b: 'Hello, world!' } };

console.log(util.inspect(obj, false, null));

The second argument, showHidden, determines if the "non-enumerable" properties of an object will be logged.

The third argument is the depth level; setting it to false will recursive to the furthest depths of the object.

If you'd like to have some more node tools in your toolbelt, I reccomend learning the ins and outs of the util core library.

The Proxy object is a new feature of ES6 which is looks to be super useful and promising.

I was working on a new Javascript for Automation (JXA) project and came across the npm module called jxa. jxa uses the Proxy object to pipe commands to OSX's osascript executable. You should poke around the source, it's quite neat.

If you want to learn more about Proxy, check out this article from Mozilla and this article from MSDN.

Note, the Proxy object cannot be shimmed by Babel and browser support is not universal.

One of the main reasons I love typed languages like Typescript is that they allow a developer to reveal how their code should be used through the use of interfaces.

For example, it's simple to reveal what arguments should be passed to a function, the shape of those arguments, and, one oft overlooked feature, the ability to mark properties of objects or even whole objects as read-only. The ability to mark objects as read-only (or quasi immutable) is especially powerful when building functional programs, eg. a React application.

Like all parts of programming, there's one way and then there's the right way.

First let's look at how not to mark an entire object as read-only:

interface Props {
  readonly firstName: string
  readonly lastName: string 
}

const props: Props = {
  firstName: 'Brian',
  lastName: 'Gonzalez'
}

props.firstName = 'Jose' // Won't compile

There's a better way.

We can use Typescript's built-in Readonly<T> generic type to achieve the same effect with less visual noise or cognitive overhead:

interface Props {
  firstName: string
  lastName: string 
}

const props: Readonly<Props> = {
  firstName: 'Brian',
  lastName: 'Gonzalez'
}

props.firstName = 'Jose' // Won't compile

A few caveats: if you need to mark only bits of your object as immutable, dont use Readonly<T>. Also, Readonly<T> does not reach into nested objects, so you'll need to wrap those objects in Readonly<{}> accordingly.

Update

As pointed out by reader schlenkster on Reddit, this method only marks a per-use instance as readonly. We can get around this nuance by extending Readonly<T> at definition time:

interface Props extends Readonly<{
  firstName: string
  lastName: string 
}> { }

const props: Props = {
  firstName: 'Brian',
  lastName: 'Gonzalez'
}

props.firstName = 'Jose' // Won't compile

Take the following Dockerfile in ~/foo

FROM postgres:10.4-alpine

LABEL description="This is the Curri Database built atop postgres."

ENV POSTGRES_USER=postgres
ENV POSTGRES_PASSWORD=hiiiiiiiiiii
ENV POSTGRES_DB=hola

VOLUME /var/lib/postgresql/data

EXPOSE 5432

To persist postgres data by using ~/foo/postgres-data as the data volume, run your docker container like so:

docker run -itd --volume=/$(pwd)/postgres-data:/var/lib/postgresql/data --name curri_db curri_db

The $(pwd) is the most important part, as docker run does not allow for relative paths like docker compose.

I've come to realize over the past 6 years the power of identifying a right and how it differs from an expectation.

Examples of rights:

  • Water
  • Food
  • Shelter
  • Access to internet and all of its data
  • Speech

Examples of expectations:

  • Well-paying job
  • A house
  • Having kids
  • Wealth

Why is it important to identify rights vs. expectations?

When we take inventory, identify, then name them, we are much more capable of dealing with the result of not receiving either the right or the expectation.

If we're not receiving something we have a right to, we should feel injustice and we should take action to fix that. If the right continues to not be given, we should continue the cycle of feeling injustice and acting.

Our relationship with expectations should look much different.

If we're not receiving something we expect to receive, we often become crippled by the inability to obtain said expectation. The power lies in identifying the expectation, being an active participant in achieving the expectation or not, then letting go of the results.

Stress is often avoided at all costs. But why? Some is good and some is bad. Let's explore how we can reframe stress to separate the good from the bad.

There are two types of stress: eustress and distress.

Eustress brings joy and fulfillment. Like watching a huge wave approach, developing a little angst, and not knowing whether or not you'll catch it or get pummeled. Or like that feeling that comes when your big race approaches and butterflies of excitement develop within your stomache.

Distress brings anxiety and pain. Like a pending, arbitrary deadline with your boss and all stakeholders hounding you to just get it done. Or, like an approaching commitment you said yes to but should have said no to all along.

Don't throw the baby out with the bath water. Seek out eustress, and avoid distress.

Us surfers are crafty and we love our hacks. Here are some of my favorites.

The Wetsuit Shower Hook

→ Amazon Link

Ever needed to hang your wetsuit in you shower but couldn't find a place for it? Grab one of these little guys and hang it wherever you please.

The Wetsuit Hanger

Instead of paying $5 for a proper wetsuit hanger, I just take 3 old hangers and little electrical page and fashion a hanger which is strong enough for a wetsuit.

The Key Fob Combo Lock

→ Amazon Link

My Sprinter van key fob is chock full of electronics, so tucking it away in my wetsuit while I surf is not an option. I attach this combo box to my door handle with my key inside while I surf. Simple.

The Surfboard Rack

→ Amazon Link

This little lumber rack serves as a great way to tidy your boards. Slide some PVC pipe padded with some pipe insulation rover the rungs to add a little extra room for your board.

Testing ES6 modules may seem like a difficult task, but is quite straightforward once you know the approach.

First, create the module you'd like to test. The important part is to export an object with functions you'd like to spy/stub.

function whom = () => { return 'world' }
function sayHello = () => { return `Hello, ${whom()}!` }

export { whom, sayHello }

In our test file, it's important to import the whole object and name it using the import * as someName syntax.

import * as helloWorld from './hello-world'
import sinon from 'sinon'

test('it should say hello to compadres', function (assert) {
  sinon.stub(helloWorld, 'whom', () => { return 'compadres' })
  assert.equal(helloWorld.sayHello, 'Hello, compadres!')
})

Seth Godin illustrates a phenomenon that occurs when we set out to achieve something: start a business, tackle a New Year's resolution, lose weight, for example. This phenomenon is called The Dip.

What is The Dip?

Well, consider gym memberships. 12% of new gym memberships come in January come by percentage, but it actually represents about a 33-50% increase in volume (see this post).

I wanted to play around with Vue 2.0 and learn more about the Chrome extension API. @sifxtreme and I, because we often have a lot of open tabs for work, also had a desire to build a Chrome extension that:

  • would help us cleanup tabs to save computer memory and mental space
  • was pretty

So we did just that.

Introducing TidyTab. You can find the code on Github.

Enjoy and please provide feedback.

This is mostly a post to help me remember, but I've found these Google search tips useful over time.

When learning a subject

  • diagram [ topic ]
  • [ topic ] plain terms
  • eli5 [ topic ] * ELI5 = Explain it like I am 5
  • how to [ topic ]
  • [ topic ] tutorials
  • [ topic ] wikipedia

Thanks Benny Wong!

When fixing or working on a project

  • how to [ topic ]
  • video tutorial [ topic ]
  • manual pdf [ topic ]
  • youtube [ topic ]

When traveling and wanting non-touristy experience

  • off the beaten path [ city ]
  • hole in the wall [ interest (eg. coffee, beer, antiques) ] [ city ]
  • unknown [ city ]
  • budget [ city ]

(These next "hipster" few seem cheesy, but these areas tend to have great restaurants, shops, bistros.)

  • hipster coffee shop [ city ]
  • hipster restaurant [ city ]
  • hipster district [ city ]
  • brewery [ city ]
  • [ interest ] [ city ] – for example “dinner Tokyo”
    • Then navigate to images, find the most intriguing photo, and go there

One of the neater technologies that powers Dollar Shave Club's member experience is our UI icons powered by ember-data. I wrote about that here, back in the day when we used gulp to build our ember app.

Within the past month, we updated our app to be ember-cli based. With that migration came the need to refactor away from some of our gulp dependencies. Luckily, one of those dependencies was one I wrote -- gulp-file-contents-to-json.

I wrote a Broccoli equivalent: broccoli-file-contents-to-json. Please check it out when you get a chance.

Using this simple technique to parse a URL using the DOM and an anchor, we can create some useful Vue template filters.

For example, to display the host of a url in your template:

import Vue from 'vue';

export default Vue.filter('host', function (url) {
  const parser = document.createElement('a');
  parser.href = url;
  return parser.host;
});

Then invoked like so:

{{ url | host }}

This could easily be extended to protocol, hostname, port, pathname, search, and hash.

I am heading to the Way to Work Workshop tomorrow at Basecamp in Chicago. I hope to glean valuable chunks of knowledge to bring back to my team and implement in practical ways.

Shawn Blanc has some nice tidbits in his summary of the workshop:

  • Time is the single most valuable resource of the company. And pretty much every single Basecamp employee has their entire day free to work on the one project at hand. Literally everything they do at Basecamp is about safeguarding everyone’s time. Nobody’s time at Basecamp is more or less important than anyone else’s.
  • ...there is an “epidemic of collaboration” amongst corporate spaces.
  • Try to remove as many dependencies as possible so there are no bottlenecks forcing people to wait to get work done until they finally hear back from someone else.
  • Basecamp has found that written communication skills are critical. Because with strong writing skills, it means you have employees who also have the ability to think critically and communicate their ideas.
  • There is no backlog of work at Basecamp. Every 6-week work cycle is a new cycle and there is no “plan” or “map” of what they’ll do next. There is only the project at hand.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment