See associated blogpost, Preemptive Pluralization is (Probably) Not Evil.
Clip from The Art of Product (13 mins in)
Preemptive Pluralization is Probably Not Evil
Swyx: [00:00:00] For a while I've been observing that it's much easier to take things from 2 to 3 or 3 to 4, basically anything to N, than it is to take things from 1 to 2, especially in code. And I didn't really have a frame around this until i heard this part in a recent Art of Product podcast. So I'm going to let Derrick Reimer and Ben Orenstein explain.
Derrick Reimer: [00:00:20] I'm starting to get the sense that like, all right, I can see the boundaries where the abstractions should be, where they aren't currently today and building this, like building another client, building another major integration, like this forces you to get those abstractions, right. Because, or you're going to just hack stuff in which don't want to do so once those abstractions are truly right with truly two different adapters in place, then it's going from two to three, like you said, shouldn't be that bad.
Ben Orenstein: [00:00:45] Yeah. Once you make the, like one to N abstraction . The N becomes pretty arbitrary
Derrick Reimer: [00:00:50] I'm excited for the possibilities of what that'll open up once I go into the N territory on that.
Ben Orenstein: [00:00:56] I have this theory and this is like pretty half baked.
I probably will always be half baked, but like in programming, as soon as you go from one to two, you should just go from one to N. As soon as you're like, Oh, there's not just one kind of user, there's a user and there's an admin. It's like, just assume there's going to be some number of user types and build the abstraction to handle the N and maybe by default, instead of ever assuming there's one of anything, assume there's an, if anything, and if there happens to be one great.
And then when you want to go to two or more, don't change anything. It's like, what if every time you use hasOne in rails you instead just use hasMany, and do you use map over things like, you know, map over the collection and to do that as opposed to being like there's exactly one, do the thing to it.
Derrick Reimer: [00:01:39] I've had to face a couple of those in building SavvyCal, like with respect to integrations, you know, a lot of times you end up coding things like I will assume this person will have one zoom account. So you're only allowed to have one of these types of integrations and it's like, no, I'm going to make sure it's multi, because you always remember this at Drip — we always encountered scenarios where like, couldn't imagine it when shaping the product, but sure enough, someone's like, no, I've got these two Stripe accounts and this is the exact justification. Why? And I need to do this thing. And it's like, okay, well, And it's painful having to re architect in that direction.
Ben Orenstein: [00:02:09] I've done this refactoring a million times, I'll be like, I thought there would only ever be one subscription, team, user, plan, name, address, and it always ends up being like, Oh, actually there's more. I've done this a million times. I always never go the other way. What if you just paid the upfront cost of thinking: "this is just always a collection"?
So given that, what should I do and solve that problem as part of the initial design, never build up all these assumptions about singleness and then you have effortless expansion into the N over time. Yeah.
Derrick Reimer: [00:02:40] Like as much as you can centralize your logic around accessing, like, if you're treating it as one for now, the hard part is sometimes to not sprinkle hacky things all over the place, like always taking the first element off the array, basically.
If you can centralize that in one place so that if you end up expanding it down the line, it's pretty, you only have to change in one place. That's, I've found I've had to refactor that multiple times in that direction. Totally.
Ben Orenstein: [00:03:04] Yeah. This comes up in Ruby in particular. I think this is almost extra true for Ruby because you end up with nil in certain places.
Like if you're like user dot address dot capitalize or whatever, it's like, Oh, address was nil. So you can't call it capitalized. But if you say like user dot address dot map, capitalize. It's like, okay, well, if it's an empty array, no problem. That's just you'll have an empty array or at the end.
And if it's got one thing in it, you get that. And if it's got a thousand things in it, you get that. And it's just ah, like the map abstraction just clears this up for you and handles those cases. And you're never calling stuff on nail. Like right now in Tuple, it's like, you can be on one team.
It's like, yep. It might be nice to change that one day, but just imagine the magnitude of that change. It's huge. Whereas if we just said users could have many teams and in practice, they only have one, but we just know this always comes back with the collection. And so we operate on that collection and then some day later we changed that and it's like, Oh, this isn't, this actually is way easier.
I guess like it doesn't impose much cost and then potentially gives you big gains later on when the world almost inevitably changes
Derrick Reimer: [00:04:10] down to at least the database layer. So you're storing it in the database as, as a one-to-many relationship. And maybe at the earliest point in your code where you're touching that you're like forcing it into being a singular.
Thing... so like most of your code things, that's one thing that's still a lot easier to change than like refactoring database stuff is the worst. Like it's a lot easier to change code that operates on a database schema than it is to actually change the scheme.
Ben Orenstein: [00:04:33] But yeah, it's just everywhere.
I had just done like user dot teams dot map name. It's like, well, if it ever changes, I know I'm not gonna need to come back here and deal with this again. It's like, if you can build, if you can build in a way that you're not going to have to come back and change it, that sure is nice. If it's not too costly in abstraction complexity, this is a pet theory of mine. Next app I make, I'm just going to make everything hasMany.
Don't Go Too Far!
Derrick Reimer: [00:04:54] There's probably an extension of this where it gets too insane , like I do enjoy a good one-to-one if I know for sure. And there are cases where you know for sure that this is only gonna be one and then it's just really nice.
If you can just Rely on it being the only thing. And it's like always there. And I also like non-mental constraints. I love those, you know, it's like, Oh yeah. This thing will never be no.
Ben Orenstein: [00:05:17] absolutely good. No constraints is great. Yeah. Hammer and hammer. And as many of those as I can into the database.
So of course, neither extreme is correct here, but I think over time, part of the wisdom of being a programmer is anticipating the stuff that's going to come down the line later accurately. And so maybe what I actually just need is like a list of things where it's like, just always assume a team is going to have multiple subscriptions or an organiza...
Create your
podcast in
minutes
It is Free