Happy New Year!
Every engineering decision comes down to "it's a trade-off". But what are we trading off?
The best way I've found to quantify a trade-off is to talk about the opportunity cost and the carrying cost.
The opportunity cost is something you pay up front—at the cost of not pursuing another opportunity. A carrying cost is something you pay constantly to live with the solution. Ideally, a strategic opportunity cost will reduce carrying cost and pay for itself, like so:
A poorly-chosen opportunity cost, however, will make things worse. I once paid an opportunity cost in designing a slick barcode-parsing framework for an app at Stitch Fix. It could dynamically figure out from any barcode what row in the database that barcode referred to. It was way too complicated and every change required navigating its convoluted design.
Not a good trade-off, since the carrying cost was high.
On the other hand, the first time Stitch Fix created an internal API/service, we decided to spend some time authoring and vetting a set of HTTP conventions for the entire team. It turned a one day task for one person into a one week multi-developer project.
But, it virtually eliminated all future discussion about versioning, JSON, headers, and anything else you can imagine about building internal services. A good trade-off.
Try it yourself the next time you face a technical or product decision: what's the opportunity cost and what will it do to the carrying cost for you or your team?
JavaScript has a well-earned reputation for being, well, kinda janky. But over the years, it's been slowly updated and changed and now, well, it's kinda nice, sometimes!
Lots of OO languages allow an object to expose attributes. Java tends to use getWidget
and setWidget
, while Ruby allows you to make a method named widget
and another named widget=
. JavaScript—way back when—followed the Java Model, but really most JavaScript programmers set values on objects directly. some_object.widget = 42
.
Modern JavaScript, however, lets you maintain the conciseness of using attributes, but inject code:
class MyClass {
get widget() {
return new Widget(this.widget_id)
}
set widget(newWidget) {
this.widget_id = newWidget.id
}
}
const c = new MyClass()
c.widget = { id: 1234 }
console.log(c.widget_id) // => 1234
One warning, however, is that both obj.widget
and this.widget
are the same thing, so the following code would cause a problem:
class MyClass
get widget() {
return this.widget // returns the getter function
}
set widget(newWidget) {
this.widget = newWidget // overwrites the getter function
}
}
d Even still, this is still a handy feature to design classes that behave the way you want. If you aren't a regular JavaScript programmer, now you know!
Unless otherwise noted, my emails were written entirely by me without any assistance from a generative AI.