Flavours of busy, restrained features, and variable static views

Hi. I'm Michael Dyrynda.

And I'm Jake Bennett.

And welcome to episode 178 of the North
Meets South Web Podcast. [rock music]

Nailed it. Good job, dude. How's it going?

Nice. Going well. Going, uh, yeah. Going
well.

-Busy-
-Good

-... but but well. How about you?
-Great. Yeah. No. Same. Same. I [sighs]

I've tried recently.

I I catch myself saying the same answer
that you just gave a lot, which is busy,

-right?
-Mm-hmm.

And and i- it's true. Like, it's not a
lie. I mean, we are. We are busy.

-We're all busy.
-But I realized after a while that I would

ask people the same question, they would
say the same thing. And it's like, you

know what? We're all busy. All of us,
we're all busy.

-Yeah.
-Like, so-

All busy all the time.

Yeah. I tried to stop saying that, but it
doesn't work very well 'cause it's still

typically my answer. "How are things
going?"

-Yeah.
-"Oh, you know, bus- pretty busy. But busy

work, but the good. Things are good.
Things are good." You know, so whatever.

-So-
-I mean, I don't, I don't know how else to

-answer the question because that's-
-I know.

-That's how I am.
-There's so many things going on. It's like

-I have to pick one thing to talk about.
-Mm-hmm.

Uh, it's like I I could talk about a lot
of things, but there's a lot of things

-going on, so I'm busy.
-Yeah.

-There's a lot, you know?
-Yeah.

-We all are.
-Busy.

-We all-
-Busy, busy

... are.

You reach that certain stage in life where
you, you think... Uh, I remember thinking

when our kids were little, like, "Man,
once my kids can feed themselves and tie

their own shoes, then things will probably
slow down." And it's like and then they

get older, and it's like then it's
friends-

-Gets harder
-... and sports.

-Yeah.
-And you're like, "Man, after basketball

season is over, then then things are gonna
slow down a little bit." And it doesn't.

-It just keeps going faster-
-Yeah

-... and faster and faster and faster.
-We're we're just moving into that phase

-now with Eli playing sport and soccer.
-Mm-hmm.

-And now it's-
-Mm-hmm

Liv has decided that she doesn't always
want to... I think more often than not,

she doesn't want to go to the soccer
games, which is fair enough-

-Mm-hmm
-... 'cause it's cold-

-Yes
-... and she's sitting around and she's

-bored. And-
-Sure. Yeah. Yeah

... she's not really interested in it. So
because she's not participating, she

doesn't doesn't really wanna be involved.
And so one week, I'll take Eli to soccer.

-One week, Ria will take him. And so-
-Oh, nice. There you go

... it's back and forth, and then, like,
figuring out who's going where. And and

now that the kids are a little bit more
independent and it's a bit easier to do

things. Like, before, when we'd, like,
bath the kids, we want all hands on deck

'cause someone will be washing one,
someone will be drying the other one,

-getting them ready for bed-
-Yep.

-And all that kind of stuff.
-Yep. [laughs]

Now

now both of them can basically wash
themselves, except when it comes time to

washing their hair. And Eli can dress
himself, so it's like you... Uh, we just

watch them get in and out to make sure
that they don't-

-Get in there
-... slip on the bath.

-Yep. Yep.
-You know, so that makes it easier to,

like, go out during the week so that, you
know, Mum can put one of them to bed or I

-can put one of them to bed, feed them-
-Yeah

... all that kind of stuff. And and it's
not like this overwhelming chore of of

having to do all of that stuff because
they're quite independent

already. Um, and so that that makes life a
lot easier, so that we don't have to have

two people here all the time. It makes it
easier for for Rhea to go to the gym or

for me to go out and and grab a bite or
something like that, so-

-Yeah. Yeah. Very true.
-It's just a-

-That is true.
-But it's a different kind of busy, as you

-say.
-It is different.

-You know?
-Yeah. That's right.

-It's just phases-
-Yep

... of busy. And then, you know, once they
get to-

-Exactly
-... the age of your kids, at at the other

end, it's, like, more professional sport
kind of commitments. Not not professional,

-but, like, higher level of of sport-
-Yeah

... commitments, where

it's training multiple times a week. It's
playing multiple times a week. It's all of

-this kind of moving around-
-Right. Right

-... where we now-
-They're trying to get better. Like, when

they're younger, it's like they're just
trying to play. They just, they're happy

-to just play.
-Yeah. Mm-hmm.

And, like, at this level, they have to
kinda decide if they wanna be... If this

-is what they wanna do, if they don't.
-Yeah.

And if they do, it's like they've gotta
commit to practicing outside of the

-practices and games and stuff.
-Yeah. That's right. Yeah.

And so it's like if you actually wanna get
playing time and be good, you gotta do

stuff outside.

-Mm-hmm.
-So coordinating those times as well and

-whatever. So...
-Yeah.

It's all lots of fun, man. It is all lots
of fun.

-It's good though.
-But those, for like, for Graham right now,

he's 14, so it feels like the clock is
starting.

-Mm-hmm.
-The countdown is on. You know what I mean?

-It's kinda-
-The countdown to college because it's very

-different for-
-Give as much time as we can with him

-... for you guys over there. Mm-hmm.
-Yeah.

-'Cause what's-
-Yep.

Over there, very, very common for, you
know, um, kids to to pack up and go off to

-college and not-
-Yep. Yep

-... not stay at home and-
-Totally

... and be away for for months at a time
between breaks and things like that.

Whereas here, they, they, generally,
people will still go to university

where they grew up.

-Mm-hmm.
-And and it's like you'll catch a bus to

the city to, like, go, and then you'll
come back home at the end of the day. So

it's it's very different, you know,
hearing those perspectives. I see Abigail,

you know, tweeting about it, that they're
they're running out of summers with the

kids at home and the kids being around and
all that kind of stuff. And it's just not

something that really

crosses our... my mind because

short of going to the

join the army, you know, like my my nephew
did, you don't really... Like, most

people kind of tend to stay where they are
until they finish study. Not a lot of

people will travel interstate for study.
Um, I think that's fairly uncommon here.

-Interesting. Yeah.
-Yeah.

-Yeah. That is a cultural thing.
-Or is this, like-

-I think-
-... part of the course for you guys?

I think... Very, very common. Yeah.
Exactly.

-Mm-hmm.
-And a lot of kids see it as their first

opportunity to sort of escape their
hometown. You know what I mean? It's like

-they wanna get outta here.
-Mm-hmm.

They wanna go experience the world, live
somewhere different, live apart from their

parents and family. Kinda have their their
leap into adulthood, if you will. So-

-Yeah
-... which comes with the pros and cons,

you know, because they're only 18, so
they're still kids, man.

-Yeah.
-It's like-

-Yeah.
-... you can make really stupid decisions

as 18-year-olds. You can make really
stupid decisions as a 40-year-old too.

-But-
-Yeah

... got a little bit more life experience
behind you. So, anyway, yeah. It's, uh,

it's fun, man. It's, it's been a good
start to the summer, and

things are going good.

Um,

last show, when we were talking, um, we
came up with, like, a bunch of things that

we wanted to talk about, and so I wrote
them down. And we talked about how we

wanted to sort of have a little bit
more... What did you call it? Like, not

-consistency, but, like-
-Continuity.

-Continuity. That's it.
-Yeah.

That's the word. Continuity between the
shows. And so last time, we were talking

about

Wistia, talked about the new Wilber Jobs
website and how-

-Mm-hmm
-... that w- that was pretty cool. Um, I've

got a couple things we could talk about
with that. Staggered CSS animations, live

photos, we could talk about that. Or we
could talk about where to store values for

templates in static sites. That's an
interesting one.

-Mm-hmm.
-Or defensive programming.... or time

bombed feature flags. All right, which one
sounds the most interesting to you?

Hmm. Time bomb feature flags I've played
with in the past, and they've bitten me-

-Yes
-... because they don't, they don't work-

-Ooh
-... quite as, quite the way that I thought

they would.

All right, let's dive in. Let's dive into
time bomb feature flags. Okay.

-Should I set the stage real quick?
-Mm-hmm.

You wanna tell me what Pennant is? Tell
us, tell all the people what Pennant is.

Pennant is a Laravel first party
implementation for f- feature flagging,

uh, in, in your Laravel apps, right? So
Tim McDonald-

-Yeah
-... built, built that one out, hmm, not

last year, the year before, I think. So
it's a couple of, couple of years-

-Yeah
-... it's been around now. And, yeah, it's

a, it's a first, first party, you know,
it, it feels like a Laravel implementation

of feature flags.

Yeah, it's, um, it's a really good,

um, it's a really good library, and it's
very simple. Um, so it's,

you know, it's basically the minimum
amount of code that you would need in

order to be able to run feature flags is
kinda how I think of it. So

it's really, um,

wonderfully simple. Uh, the couple of
things that we, the way that we use it is

you have...

You can either have a closure

that helps to give it a name. You can name
the feature and then have a function that

accepts a scope and then resolves the
truthiness of that feature.

So

you say, let's say, um, the feature is,

I don't know,

Ken Call Michael. It's Ken Call Michael.
The, you know, one of our support people

gets a emergency button on their
dashboard, which if they need help, they

can call Michael. And only certain people
get access to this because, you know,

there's people who have abused this in the
past. And so we wanna start out with only

giving it to managers, because managers
are the ones who, uh, can escalate calls

to Michael. So what we're gonna do is
we're going to thi- name this feature Ken

Call Michael, and, uh, the way that I'm
going to do it is I'm going to implement

it inside of a class called Ken Call
Michael Feature. And, um, inside of that,

I have a resolve function, or sorry,
resolve method, which accepts a scope, and

I think typically that's just a generic,
it's mixed $scope. But you can specify

things like user. So I know that I'm
passing a user into that scope, and it

will fail if I pass anything else. So I'll
pass a user in as that scope, and then I

can say user hasRole manager, something
like that. And I return that, return the

truthiness of that statement. So if that
statement returns as true, when that

person visits the page that, uh, checks
that feature, right, where that feature is

actually on the page, it will grab that
class. It will resolve that feature,

resolve that method, and then it will
return a truthy or falsey, um, value. And

then that will get stored. Depending on
what driver you're using for Pennant,

it'll either get stored in the database,
or it'll get stored, you know, in Redis or

other places, wherever you might have it.

-Mm-hmm.
-And then at that point, it is resolved. It

is not stored. It will not ever resolve
again unless you delete or, or, uh, purge

that feature for that person, which is
great.

So that's the idea, right? I can turn
features on or off. I can also launch it

as, like, nobody gets it. I can just, from
that resolve function, return false. And

then I can go into the database, and I can
say only I get it, right? Or I can

release it to a beta group of users. So I
can test it in production without having

any fear of breakages occurring because
nobody can see it except for me. So if it

breaks, it's only gonna break for me, or
it's gonna break for a very small group of

users. So really, really nice. Now,

after having explained that, Michael, I
want to hear your idea or explanation of

time bombs,

why you might use them, and how you
implemented them and how they bit you.

Mm-hmm.

Yeah. Well, I think it's, it's the, the
fact that they are resolved once and

persisted that has bitten me because-

-Mm-hmm
-... the, the time bomb nature is that I

would expect that a feature flag applies
or doesn't apply depending on how you've

got your code wrapped by that feature flag
at some point in the future.

-Mm-hmm.
-So the way that I wanted to use them,

rightly or wrongly, last year when, when I
looked at it, was to time bomb the

-display of speakers for Laricon AU.
-Hmm.

So, like, on some day in the future, we
want this speaker to appear on the

-website.
-Yeah, yeah.

So I don't have to remember to do it. So I
don't have to be at the computer to, you

know, tick a box or whatever. So I
thought, yes, I will, I will time bomb

that feature flag,

uh, so that that speaker appears at some
point in the future.

Now, the problem with that was, because
that was resolved once, when it resolved

-the first time that it was loaded-
-Mm-hmm.

-It was false
-... it was like... It was false. So it

went into the database, and that was it.
It was just false forever. So I would have

to then go in, [laughs] on that time, on
that day, to then remove that flag, which-

Yeah

-... kind of defeated the purpose of it.
-Defeats the purpose.

-So that's-
-Totally.

That's where, that's where I got bitten by
them. Other than that-

-So-
-... I think they work fantastic.

Okay. So, so

it's probably helpful to talk about
definitions of what a time bomb is. So

what you've explained there is not
necessarily a time bomb. A time bomb, as

Martin Fowler describes it when he's
talking about features and toggling, is a

way for you to make sure that feature
flags don't stick around for forever,

-right?
-Mm-hmm.

So you could think of a time bomb more as
an expiration date than a... Only to show

-it at this time. Now-
-Mm-hmm

... I think it's worth discussing how we
would actually approach your particular

-problem that you're talking about.
-Mm-hmm.

And

maybe,

I don't know. I- I'm actually not sure how
I would solve that with Pennant. I think

I would honestly, in that instance, I
would literally just put a

timestamp check or something [laughs] like
that.

-Yeah. All right.
-I would wrap it with a conditional if that

-says-
-Yeah

... if, if, uh, now is passed and then
pass in the date-

-Mm-hmm. Yeah
-... and then I would... Then that's how I

-would do that probably.
-... yeah, this year. This year, we put all

of the, the speakers into the database,
so now we just have a, like, publish date

-is in the past.
-Ah, so- oh, perfect

-That works fine this time
-... there you go.

Yeah. Which is the sensible way of doing
it, but last year, we kind of... The, it

was all static HTML really, so we, we put
all the spon- uh, the, all the speakers on

-the page that way. And so we're-
-Yeah

... just expecting, like, for each one to
then,

t-to, to appear effectively when, when the
time is in the past, but didn't work out

that way. Uh, but this year, yeah. It's
just a, just a field on the database

that's an announced at or something like
that, and we just return all of the

speakers where announced at is less than
or equal to now, which is much-

-That makes sense
-... easier way of doing it.

-Great way to do that
-Don't use feature flags for that. Yeah,

-no.
-Absolutely. Great way to do that. So,

so if we're approaching this idea of time
bombs as this, as more of, like, an

expiration date, um, I, I would love to
talk about that just for a little bit.

And, and essentially, I'll give you the
scenario that

we faced that had me looking back into
this, which was we had a feature flag that

was,

you know, gate, gating a feature that we
had written

and I pushed it out on a Friday

-and promptly forgot.
-It's time to push down

-About that feature.
-Yeah. Just want to push down

Totally forgot about it. It didn't matter.
It was like, "Okay, hey, whatever." So,

uh, I enabled it for a couple users and

the users of us who had it just

looked at it and figured, "Well, everybody
must have this," right? We totally forgot

-that we did not release it for everyone.
-Yeah.

And so six months later, somebody's like,
"Yeah, I don't know how to see, like, if

this file is timed up or not." Like, well,
just use the, you know, just use the

-timed up, you know, thing at the top.
-Yeah.

They're like, "I've never seen that." And
they're like, "Well, like, certainly.

Like, it's right up here. Here's where you
should see it." Go into the features

table. Yup, not enabled for anybody except
for us. Like, ah, crap. And so what

happened is

we had this feature flag that was not
supposed to be around forever. It was only

supposed to be for this beta testing sort
of idea. And once it was good, then we

needed to remove it. So the question is,
how do you inform yourself when

you should, you know, how do you basically
put an expiration date and say, "Hey, by

the time a month has passed, we should
have figured out if we want this feature

-or not for everybody."
-Mm-hmm.

It should be general release to everybody,
or it shouldn't be.

-Yeah.
-And, you know, we kinda need to pull the

trigger on one way or the other.

So I asked Tim McDonald. I was like, "How
would you do this?" We had a couple ideas

for how we would do it, but the way that
he did it was very, uh, clever. And so I

wanted to share the idea that he had,
which is,

uh, to put on each one of your feature
classes, which again, is the way that I

really prefer to do it, is to use a
class-based resolution because you get all

the other things you can do, this
behavior, these traits that you can put on

it and whatnot. But you make a trait
called is, like, concerned with

expiration, you know, maybe something like
that. And inside of there, um, you have a

contract essen- or sorry, maybe it's a
contract, not a trait. But it's, uh, a

contract that specifies that you need to
have a

is expired

method that returns a Boolean.

And then what you can do is, uh, in that
is expired, you can do a date. You could

say now is past a particular time, or you
can do other things, right? You can,

there's other things you could do. It
doesn't have to just be a date, but you

just return a Boolean from there.

And then what you can do

is

you can, in your service provider, you can
say there's an event that says feature

resolved, I think is what it is. So what
this does is any time that a feature gets

resolved, even if it's out of the
database, if it's grabbing it,

it will look and say,

um, is this an instance of,

you know, or does this extend the contract
or implement the contract of, uh,

you know, can expire or something,
whatever. Like, what, you know, I'm using

bad names here, but that's the idea,
right?

-Sure. Yeah, yeah, yeah.
-And if it is, if it does extend that

contract or implement that contract, then
what you do is you check to see is it

-expired.
-Yeah.

And if it is expired, then you can do a
couple things. So, um,

you know, you could log, warn yourself,
something like that. Um, but the thing

that Tim did, which I thought was really
cool, is there's this way that you can

check to see if you're running tests
currently. Have you ever seen this before?

-So it's like-
-The other container that's, like, is

-running-
-Yeah

... running unit tests or something like
that.

Yeah. If app dot op running unit tests. So
you can do this conditional. You should

say, "If we're running tests

and it's expired,

then we want to throw a runtime exception
that says feature has expired." So what

that does then is if you're ever running a
test that encounters this feature, and

the feature is expired, it's going to
force you to make a decision one way or

-the other.
-Yeah.

-You either need to extend-
-Extend it

... the amount of time that you have until
it expires.

-Or remove it. Mm-hmm.
-Or get rid of it. And I love that because

it does... It's not destructive. It
doesn't ever mess you up in production.

Uh, you can have it log if it's in
production if you want.

-Mm-hmm.
-Instead of throwing that runtime

exception. Um, but it's a great way to
ensure that any of your features that

you're putting in place have a reasonable
expira- uh, expiration timestamp on them

and that you're forced to deal with them
at some point in the future.

-Um, so I thought that was pretty cool.
-I like that.

-Yeah.
-That is a very Tim thing to do. [laughs]

Mm-hmm.

To put a thing in there. I've,

-I've-
-So he wa- so he did... So here's the deal.

He hasn't actually, like, this is not...

This does not exist. You have to just add
it on yourself.

-Yeah.
-Right?

-Yeah, exactly. Yeah.
-That's why I was like, "It would be cool

if it was first party." He's like, "I
mean,

I didn't feel like there was a good..." He
said, "I didn't feel like there was a

good generic option to put on top of it."
So-

-Yeah
-... I built the tools. A lot of the users

to decide how they wanna handle it, but
it's not, it's not difficult to implement

-it.
-Yeah.

-Right? You could see how you would do so.
-Yeah. It demonstrates a lot of restraint

on, on his part and on, I suppose, on
Laravel's part in general about where you

draw the line in the sand for, for what
you do offer as part of the library and

for what you say, "The tools are there. Go
and implement it."And, and I think this

is, this is a fairly good

case, use case of the tools that go and
implement it yourself. I've, I've gone

back and forth over the years about
whether or not

using those kind of conditionals in
application code is a good idea or a bad

-idea, you know?
-Mm-hmm.

Doing an, like an environment check or
doing a, are we running unit tests? Or, or

that kinda stuff to then trigger things
because you're, you're putting

test logic inside of your application code
to do this kind of stuff.

Erm,

I think it's fine, in general. I don't, I
don't really see any reason to do that. I

know that in parallel testing and things
like that, we will have all kinds of

conditionals that check, like, if the
parallel testing token is set, then we

need to go and do this stuff. And then
somewhere else we go, "Okay, don't do this

stuff because we are parallel testing,"
and, and things like that. So

there's definitely cases, I think, where

doing that kind of runtime, testing time
logic is good. I think

forcing you to, you know, blow up your...
[sighs] It depends on how strict you are

on your continuous integration. Like, if
you're running this in CI and it fails

because somewhere between where you pushed
a pull request

-into GitHub and some-
-Mm-hmm.

And, and when the CI ran, your, your test
suite is now failing

because of this expired token or this
expired check,

but it's unrelated to the pull request

that, that was pushed up. So I think

that's, like,

that's the one thing that, that sticks to
me. It's like, okay, yes, we need to do

something about it. It is now impacting on
this unrelated thing,

and it's, you know, a team decision. What
do you do with that? Is someone now tasked

with going immediately and, and updating
that? Do we... You know, it, it may not be

a decision that gets resolved straight
away, depending on the size of the

organization. It, it might be, like, you
as a developer or as a founder, you can go

like, "Yeah, I'll just kick that can down
the road a week," or, "I'll go and remove

all of those feature flags, and this is
now just a feature that's part of the

platform." So yes, it does prompt you to
do that, but sometimes that decision

-involves committees. It involves-
-Yeah

... product teams, product managers,
things like that. You've gotta go ask.

You've gotta go wait. They don't have an
answer. They've gotta go chase it up with

-someone else.
-So now you have a blocked PR, yeah.

And meanwhile you've got a blocked PR and
a failing test suite, and all of that

-kinda stuff. So, you know-
-In fact, every PR is blocked, right? If

you had multiple PRs out there, all of
them are blocked.

-Mm-hmm. Yeah.
-And every single person is trying to

scramble to figure out what do we need to
do with this.

Yeah, yeah. And everyone's going, "Oh,
this is failing. Retry fail tests." Like,

'cause they're like, "Oh, this wasn't
supposed to fail," you know? Es-

especially, like, we get into situations
at work where the, the test suite will

just be flaky.

Erm,

and it's just over time, the, the
construct of, of the application has

changed where, you know, you've got
factories that, that are resolved in a

certain way. Which is okay when you've got
100 tests, but when you've got 500 tests

or 1,000 tests, those factories can, like,
step on each other. You might not have

something that's unique, so

over

enough iterations, you end up with
collisions and things because you don't

have the, like, fake, faker Unique applied
in there. So there's, like, all these

different

cascading

arbitrary failures that you might not even
look at it for a couple of days-

-Yep
-... until someone goes, "Hey, this is,

this is failing." So

I like the idea in

theory.

-Mm-hmm.
-I think

whether or not it works depends on

the kind of company that you're in and how
quickly they respond to that. Like, if

you,

and, like, whether you put that in there
at all,

uh, really comes down to how quickly
someone is going to respond

when... It may be a case that you log,

you know, for two weeks or something
before the failure,

erm, even if you are running in test so
that something bubbles up somewhere that

hopefully someone would see.

Erm,

but yeah.

-That's a l-
-Yeah, you're, you're-

... long-winded way of saying that, like,
I think in general, I agree with the idea.

I like, I like the idea of putting
something [laughs] that explodes in, in

test. Because that's something that

at some point in your release cycle,
whether it's during development locally or

as part of CI or deployments, like,
something will blow up because of that.

-Yeah.
-Erm, and, and what you have in place to

work around it. You know, okay, we can
just merge this PR anyway knowing that

this is,

erm,

-unrelated to that pull request.
-Yeah.

If you do, if you do automated deploys,
it's a bit trickier. Erm,

it depends on, like, if you do... I know
with, erm, Laravel's testing stuff, you

-can --fail on your test.
-Mm-hmm, mm-hmm.

And, like, it will f- after the first
fail- like, if that's the first failure

and it doesn't get to something else-

-There's just stuff there.
-Yeah. Yeah, okay, so this is unrelated to,

to my failure. I'm gonna, you know, ship
this anyway. Oh, whoops. There was a, some

error further down in the test suite that
didn't get picked up 'cause we bailed out

on this thing. So...

-Yeah.
-You know?

-I'll say that the-
-Rest reward, I guess.

Yeah. The,

the concerns that you bring up are the s-
very same concerns that Andy Hinkle had

when we were going to implement this. He
was like, "I don't like the fact that

other developers are gonna have to deal
with a feature flag before they can merge

their stuff." So we came up with some
ideas and some solutions. The one thing I

will say too, though, is that this, I feel
like, follows the convention that has

been brought about in many

different... You know, like we talked
about Nuno's, um, thing where it's, like,

just here's the best practices applied to
the app service provider.

-Mm-hmm.
-Where it's like, disallow n+1 queries or

disallow lazy loading or, you know, those
assignment overflow things or whatever.

Like, those, those sorts of things that
only fail if you're in local, if you're in

your local environment. You know what I'm
talking about?

-Yeah. Yeah, yeah.
-So, like, it'll check those things. It's

not gonna blow up in production. It's not
gonna blow up in your face. If you happen

to ship it to production, it's gonna be
like, "Eh, okay. Just let it go." But if

you're in local dev or in testing, it's
gonna blow up in your face and say like,

"Yeah, you can't do that." You, you can't-

-Mm-hmm
-... you know, do that lazy load stuff. So

this sort of falls in line with that to
me. Um...However, it's not a

yes or a no, or an always or a never.
It's, it's only based on some time-based

thing a lot of times, which is... So it's
not a right or wrong. It's just like if

you happen to be the guy who runs it just
before it expires, or right after it

expires, then you're screwed. You're the
one who has to deal with it. So

okay, so how do we address this? Well,

two couple... Two, two different ways I
think we could deal with it. Um, one is

that you could, if you're running,

uh, your CI on a regular enough basis, you
could start dropping warnings a month in

advance of the expiration, right? So you
could say, "If it expires in the next 30

days, throw a warning on the tests. If it
expires in the next..." You know, if it's,

if it's in the past, then go ahead and
throw a failure. You know, something like

that. So that would allow you to be
notified of it ahead of it actually

expiring, so that you could fix it. Um,
and like, you know, you see it, it's, it's

erroring, or not erroring but it's
throwing a warning, and you're like, "Oh,

okay. I should probably make an issue for
that so somebody can fix that or make a

decision." We have 30 days to do so. The
other thing that we talked about is making

a command that runs once a day at like
6:00 AM, something like that, that runs

through the features, checks if any of
them are expired and if they are, sends

off an email or sends it or creates an
issue, or whatever you might have that

says, "Hey by the way, these features are
expiring within the next 30 days or the

next 7 days," or whatever. Uh, or they are
expired and these need to be addressed,

and that's it. You know, so there was...
That was, there was a couple options

there. You could say it doesn't ever fail
tests, it just sends out a warning to let

somebody know that this needs to be
addressed. Um, so there's a couple

different ways you could do that there
that I could see being effective that

would not necessarily block the team, but
could inform a project manager that these

are something that we need to prioritize
within the next cycle.

Kind of, you know, deprecation warnings I
guess for features.

Yes, exactly that.

-Mm-hmm.
-Yes, correct. Yep, yep.

Yeah, and I think realistically that's the
only way to, to deal with it. And if, if

no one's gonna pick up the deprecation
warnings

for the feature flags like that

on a, you know, across a team, across an
organization, you know, if you're

involving all these different p-

all these different people, then

probably have bigger concerns to, to worry
about. You know, at least sending that

email or that notification in Dislike or
whatever else

that happens to be from that scheduled
job, scheduled task, is...

You know, you've got to address it in some
way. Um, and if it goes to enough people,

someone... Well actually, if it goes to
too many people everyone's gonna be like,

"I thought someone else was gonna deal
with it," and then you've got to be

-careful there as well.
-Yeah.

So

yeah, keep the, keep the list small but
make sure it gets actioned, I guess is the

-main thing.
-Exactly.

But again, comes down to the team and,
like, someone actually taking ownership o-

over that. So

-yeah.
-Yep.

-Good, uh-
-Yep, you got it.

Good, good problem. Um, I think good, good
solution to that problem as well.

Awesome. Yeah, thanks. I, it was, it was a
fun one to kind of run down and it was...

Uh, yeah. A couple different approaches
there, a couple different concerns, but I

was happy with where we landed on it, so
yeah. Stoked about that.

-Mm-hmm.
-Okay. Since you talked about your, um,

your speakers on Laracon, um, I think this
is a good transition into this other part

which is this,

where do you store values

for

templates in a static

view? Okay, so let me pitch it to you this
way. Let's say you didn't have a database

for those team members, or not another
team members, for those speakers, right?

Um, because locally you are going to do it
and you don't want to have to like... How

do you, how do you populate your database
locally and then push that up to

production without having to have access
to the production database? You can't

really do that. It's like I know what the
values need to be, they're not necessarily

dynamic, it's just I- I don't... Where do
I store them, right? Do I... What are my

options? If I, if I can't put them in a
database, where are the other places that

I could put them? So I actually came up
with one just as we were talking here, but

there was a couple options here that,
that were thought about, right?

One is you could literally just dre- like

create a component and then in Blade, just

you don't even bother doing a loop. You
just put in the values.

-Yeah.
-Right? That's it. Create a component, put

the values in, that is your database
essentially, right? You just-

-Mm-hmm
-... write them all out in the blade, and

that works. That's fine. Like you just
basically, your component is going to have

locations or values, like the values that
you would normally store in the database

are gonna be essentially like arguments to
that component, right? So like name,

image source, um,

title, announcement date, right, all those
things.

Right? Those are gonna be, those are gonna
be stored like in the Blade file.

-Yeah.
-That's one way to put it.

-Yeah.
-That's one spot to put it.

-Yeah.
-Um, can you think of any other spots you

might, you might put these things?

I can because this is what we did last
year was-

Ooh, okay. I wanna hear, I wanna hear. I
want wrong answers only.

-We, uh-
-Wrong answers only.

-Wrong answers only [laughs]. Yeah.
-Yes. What were the other places you could

-put it?
-We created, we created a YAML file that we

-hosted in GitHub that you had to-
-Okay

... in a JS, it was a secret JS... No
[laughs], I'm joking.

-I was gonna say, oh dang. Okay.
-You said wrong answers only.

-That's crazy [laughs].
-You said wrong answers only.

I- I, at first I thought you were being
serious. I was like wait a second, do you

really? Okay. All right, all right. A YAML
file in-

-No, we-
-... a JS that you were pulling in R.

-In a JS.
-Fair enough.

-That's right, yeah.
-Yeah.

-So if anyone wants to go and-
-And then you used Sushi.

... uh, and scan. Sushi. Yeah, to use as
an-

Used, uh, Caleb Porzio's Sushi package,
yeah.

... eloquent database. That's right. Uh,
no we just, I just put all that stuff

-inside of like a config Laracon.php.
-Okay.

And it was just an array of speakers which
was keyed by...

Actually, I don't think it was keyed. I
think it was just an, an array that we

then pulled out and we, you know, we
collected it. We put it in a collection.

We sorted it by announced. We filtered
ones that were not, you know, didn't have

an announced in the, in the past and that
was it. That's, that's how we did it.

-Yeah.
-Um, and then I think w- we just used, you

know, Cloudflare to cache that so we
didn't... Well, you know, obviously the

page gets cached so it doesn't have to hit
the origin server to, to resolve that in

the future. So yeah, that was, that was it
really.

Yeah. Uh, that works pretty good. So,
like, you could put it in the config. You

also, if you're being a little bit crazy,
you could just chuck it into the

-controller. Like, if you wanted to-
-Mm-hmm. Yeah

... just inline an array in the
controller, you-

-Yeah. Sure
-... could kinda put it in there. Uh,

that's one way to do it as well. Um, so,
uh, my,

my junior-ish developer, he's actually...
He's Landon. Landon is his name. Um, he

played basketball a little bit last year
at Laracon with me right afterwards. There

was a couple dudes that we all played.
Me, David, Hemphill, Landon, and then

three other dudes that absolutely smoked
us. It was really fun, but kinda crazy.

-[laughs]
-Landon's a great basketball player, junior

developer though, and he's, he's figuring
stuff out. And so for him, he ini- or

initially just put it, like, in the
controller. Like, he actually had

a method for each. Like, so we had, like,
four locations that we were trying to,

like, you know, deal with. And so what he
did is he put,

uh, a method in, in the controller.

So you would have, like, a, a value being
passed into the controller, um,

like, uh, you know, in the, like, the
array that gets passed in to the, to the

-view. I'm sorry, to the view.
-Yep. Mm-hmm.

And he would say, like, "Location one, Fat
Arrow,

this.get('location1')." And then say,
"Location two-"

-Yep.
-"... this.FatArrow.get('location2')." So

he was just calling private methods inside
the controller that were sort of then

-returning these arrays. And I was like-
-Yep

..." Hmm,

that is fin-" Like, it works. It's
probably not how I would do it, but it

-works. And so I-
-Yeah

... was like, "I'm wondering..." You know,
config file is the first thing that came

to mind. But for some reason, I remember
when looking at it, there were some

reasons why it wouldn't have really worked
in a config file. And I think partly

because he was doing some PHP stuff inside
of that config file, and, like, it

would've been weird to do it there. Um,

but

the other thing that I'm wondering here is
this. If you didn't want to store it in a

config, what if you just put it in a
SQLite database and then shipped the

-database up?
-Yeah. Yeah,

-totally.
-If you put that in somewhere? Like, could

you... Where would you put that, though?
Would you... You'd put it in the storage

file or something? I don't know how that
typically works. If you put it in the

storage, you have to, like, symlink it or
something weird like that if you're using

-Envoyer.
-Yeah. I would just, just put it in the

database, 'cause that's, that's where the
SQL files go by default.

-If-
-Okay

... you know, if you, if you, if you do a
Laravel new and you say you wanna use

SQLite, it will create a
database/database.sqlite file inside of

storage. Uh, inside of the database
folder, and then you just commit that to

-version control and off you go.
-Yeah, 'cause I'm... As, I'm sure initially

it's probably.gitignored maybe?

Hmm, not a... Oh, yeah, maybe
database.sqlite specifically, but you

-could just remove it from there, like-
-Totally. You could.

Just because Laravel puts it there by
default doesn't mean you can't change it.

-Um-
-Absolutely.

Yeah. Yeah, shipping, shipping sqlite is
fine. Um, who, who was it? Like, was it

Aaron Francis was talking about that for,

for, um...

I think for his aaronfrancis.com. He's, he
ships an sqlite file or something like

-that, so.
-It seems like the right place to do it,

-right? I mean, like-
-[laughs]

... you literally have, you have the
structure in there. You can pull it using

-your, uh, you know, using models and-
-Mm-hmm

-... all that good stuff.
-And, you know-

So it's like, I don't really see a reason
why you wouldn't or why you couldn't.

SQLite is, is made to be small and
portable like that.

-Every, you know-
-Mm-hmm

-... the, these things, every-
-I mean, the problem is it can fill up

-... everyone's iPhones-
-It's just a flat file, yeah.

Everyone's Android file. Yeah, it's just,
just shove it all in there. Yeah.

-Yeah.
-Um-

-Yeah, so I think-
-I mean, the other thing you could probably

-do is like a-
-... that's, that's an interesting third

-option. Yeah
-... a document store. You know, something

that writes JSON to a file, and

-do that, I guess, with, like-
-Yeah, but the SQLite thing seems way

better to me. Yeah, as long as you have...
I mean, as long as you can set up... You

know, you just have to make sure that
every person, each person that's looking

at it,

uh, when they're trying to develop stuff,
uh, that they map... Uh, you know, they

can open TablePlus to that sqlite file or
whatever, right? So-

Yeah. Yep.

Yeah, that seems like a good way to do it
though. Seems like a pretty good way to do

it. Um, portable, light. It's still a mi-
it's still a, uh, you know, queryable

-entity. Um, you don't have to write-
-You could be-

You don't have to write, like, factories
or anything for it. You could just... You

know, you just ship it. You ship the
actual data up.

-Yeah.
-Yeah.

You could open up TablePlus and use that
as your, you know-

-Totally
-... as your admin interface-

-Yeah
-... to put stuff in there.The only-

-Absolutely, and you've got-
-... the only other thing that, th-

... version control on and everything, you
know?

Yeah, yeah. I mean, the only other thing
that you might do that's probably a little

bit more approachable in terms of version
control is just a, like, a CSV file,

-and then use-
-Yeah

... Switchy to, to, to manage that.

-Yeah. But I like the-
-Because then-

-... SQLite. I like the SQLite option.
-Yeah. The ISQL-

-And I, I'm not pushing that direction
-... is definitely nicer from a, from a dev

perspective. If, if you needed, like,
someone else,

you know, someone from product or someone
from sales or marketing, whatever, to be

putting data in their CSV would be fine.
And just like, "Here's the updated file."

Yeah.

-Yeah.
-"Drop it in, overwrite, replace it." You

-know?
-Yeah, it's only developers working on this

one, so I think SQLite's gonna be the
solution there. And I think that's, um,

that's a really great way to do that. So,
uh, we're gonna move towards that,

actually. That's w- exactly what we're
gonna do. We're gonna end up doing that

precisely.

Love it.

Love it. Awesome.

Okay, um, what else we have here?

Live photos, staggered CSS animation,
defensive programming.

What do you think? Hmm.

So, uh, Matias...

I can't say his last name. Starts with a
G. Guimaraes, I think. Uh, he's got a

defensive Laravel

course coming to Laracasts at some point,
so it should be cool.

I saw Jeffrey tweeted about that, like,
today, I think. Yeah.

Yeah. Yeah, he, um... De- definitely check
that out if you're a Laracasts

subscriber. I, uh, I watched his...

-It was Event Sourcing Tour- uh, series-
-Mm, yes

... that he had on Screencast. That was,
that was really good. He did a, a good job

of that, so I'm, uh, I'm keen to see

his, um,

his defensive Laravel stuff. Because he,
he works at, like, a payment provider or

-something over, over there-
-Oh, interesting

... where he lives in,

pretty sure, Brazil.

-One of the-
-Okay

... Portuguese slash and/or
Spanish-speaking nations. Sorry, Matias.

-But, uh, yeah, he, um-
-That's right, that's Portuguese, right?

-Yeah. I-
-Yeah, he's a-

Did I tell you about that, right? When I
said-

-Yeah, yeah
-... when I thought

But I couldn't remember if he was from
Spain or from Brazil. But I know in

-Brazil-
-Oh, gotcha

-... they speak Portuguese. Yeah. So-
-Yes, indeed.

Um,

yeah, he...So, he does some very intense
things, uh, in terms of, like, the

extremes of what you can do with Laravel,
so I can't... You know, he'd be a, he'd be

a... You'd be hard-pressed to find a
better teacher for that kind of Laravel at

scale type of thing. So, yeah, keen to
check-

-Yeah
-... that one out when it drops.

That'll be really good. I'm sure he'll
have some excellent sort of tips on using

Laravel tools in order to be sure that you
can catch things if they happen terribly,

if they happen to go terribly wrong.

We had something today where,

um,

it was, it was the sequence in which
something was working, so we were reading

an email from an email inbox,

we were creating a record for it, and on
that database we had a unique column for

the ID of that item from that inbox. So
that item from that inbox was given a

unique, like, Outlook message ID.

And so it's, you know, it's a GUID. And so
it's, it's unique. You cannot create

another one with that same GUID.

However, the step after we created it was
to move it from that location, that

folder, to another location.

If that failed,

right? So you'd move it from the inbox to
a folder called Processing or something

like that, right? So we create the record,
and then we start to process that email.

We read the body. We read the subject. We
do some, you know,

guessing as to where we think it needs to
go and basically have our own really

intelligent rule system that we can build
up off of that database record, right? So

you create the record, and then you send
it to processing. Well, if that sending to

processing fails for some reason, which
sometimes is this weird race, race

condition, if it fails, then the email
doesn't move, and when the inbox gets

scanned in the next minute, it tries to
pick that up again and create the record.

Well, since you have a unique ID, it
fails. So

yeah. It, it's like just using simple
things like a database transaction around

those two pieces, right? Create it, and
then move it. And if it fails while

moving, roll back the creation so that it
can try it again next time without hitting

a unique constraint. So those are the
sorts of things that we're talking about

here, right? These, you can't anticipate
everything that's going to happen. You

don't know all the different failure
points, but you can certainly wrap

something into database transaction and
roll back if something fails. You can do

that. And that's, you don't have to know
everything. You just have to know if

anything fails in here, roll back. Don't
leave this unfinished, weird state, um,

that you're gonna have to contend with
later, especially if you have-

-Yeah
-... constraints around unique values. So I

hope in, in, you know, in his course he,
he covers some of those things or, you

know, like the rescue function in Laravel
is so insanely awesome. Where if there is

a failure while you're attempting to do
something, you can provide a default

return value and just continue the program
running as if nothing failed, right?

Those, that's incredibly helpful. So
Laravel has a ton of tools to help make it

more resilient and more bulletproof if
you know they exist. So I'm sure he'll-

-Yeah
-... cover all that stuff and do a great

-job doing so.
-Yeah. One, one thing I've been caught out

with by that Rescue helper in the past is
typically I'm wrapping something in Rescue

because I don't wanna know about it, and
I always-

-Yeah
-... I, I have on more than one occasion

forgotten to set the report flag to, to
false.

Uh-huh.

So I still, I still get the exception to
bubble up, and then I go like, "What is

this?" And then I, I, like, I put the
Rescue in there, and I go, "Ah, I forgot,

forgot the, to report." Because the, the
place that we mainly use it is when we are

trying to parse dates using Carbon or
the-

-Oh
-... or the date facade. Because, you know,

you guys use, um, month, day, year, and
we use day, month, year.

-But-
-Ah, yes. Right

... if you take something that's
day/month/year

and you throw that at date parse, because
that's how we would re-enter it into a UI.

Yeah.

When you take day/month/year and put it
into PHP, PHP assumes that it is

-month/day/year.
-Yeah.

And so what you end up with is something
that's, like, 13/3/25.

-Yeah.
-And then Carbon goes, "Thanks."

Freaks out.

Um, so yeah. We, we've got in a number of
places where we're handling that, you

know, a date create from format, and then
we explicitly tell it, like, "This is

-day/month/year." So that-
-Yeah

... it goes, "All right. Yeah, this is,
this is the right way round." Um,

and then we fall back to just doing, like,
a date pass in case something comes

through as year-month-day or whatever else
and then, then gets picked up that way.

But yeah. When it, when it hits that first
Rescue, uh, callable

and you don't have the report, then we
still get the exception bubble up into,

um, our observability tooling. And it's
like, "Oh, yep. I don't really care about

-that," because-
-Yeah

... it's, it's... Like, it will, it will
catch the exception from the Rescue,

report it, and then go to the f- the
fallback, so you're, like-

-Then it'll continue on, but yeah
-But, and then you go, "But this worked.

Why am I...? Oh, okay. Yep. Gotcha."

-So don't, uh-
-Yeah, exactly

-... don't miss that one. [laughs]
-I'm surprised that there's no, like,

localization thing for Carbon where you
can basically just tell it at the top

level, "Hey, we're in Australia. Please
handle dates accordingly."

Yeah, yeah.

Probably. Probably is and we just miss it,
but, um-

-Yeah. Maybe
-... no, 'cause this is an underlying PHP

thing as well.

-Like-
-Oh, gotcha

... if you were to do... Yeah, if you were
to do, like, a create, whatever the

underlying

PHP function is, it will do the same
thing.

-Got it.
-The, the-

-Yeah
-... the correct approach for that is to

-use hyphens instead of slashes.
-Ah, interesting.

But no one, no one here is going to enter
the dates with hyphens instead of slashes,

-because that's just not what we do, so.
-Yeah.

-Like, that is-
-Yeah

-... I mean, I assume that's-
-We don't, we don't do hyphens either.

Yeah. I assume that's, like, the
workaround in, at the language level. To

be like, "Oh, yeah, you can do this as
long..." But you, you're not gonna tell,

you know, users of your platform who have

become accustomed to using slashes to use
hyphens in your application wherever else

-it's just handled, so.
-Yeah.

Yeah.

Absolutely.

Well, hey, dude. I think we have a couple
things left to talk about next time. Um,

we could probably talk a little bit more
about defensive programming and some

examples that we have. We could talk
about...... staggered CSS animations,

which is

interesting to me. This is when you go
onto a page and you want, like, this

effect of when you hit a certain
observability point, and there's a, what's

that called?

Interaction observer? It will animate
something in into view.

But if you have, like, three paragraphs of
text or something like that right

following each other and you scroll down
really fast, you don't want that whole

block to animate and at the same time. You
want them to animate in, like, a

-PowerPoint-
-One after, yeah

-... like, one, two, three. Yeah.
-Mm-hmm.

Which is a little bit tricky to do. And
so, um, I think, uh, motion.dev allows you

to do that. We figured out how to do
that. I still have to implement it. Uh,

and then this idea of how do we, how do we
accomplish live photos on the web, where

if you roll over something, it kind of
moves the photo. It kind of gives you this

motion, where it changes from a photo to
a video while you're rolled over it, and

-then-
-Yeah

... and then when you roll off it, it, it
stops doing that.

-Interesting.
-So found some interesting stuff about

that. It'd be, uh, I'd love to kind of
talk that through with you and see what

-your thoughts are-
-Mm-hmm

... on that. So

-next show, folks. Come on back and-
-Sure

... um,

you know, hey, uh, to go along with the,
uh, the news of, uh, Steve and Erin

breaking up, I, I gotta let you guys know
that, um, Michael said he's leaving the

podcast, and it's, he's just leaving it to
me. He said, he said he's giving me

-everything. Just take it.
-[laughs]

I'm paying, I'm paying him 50% of what
it's worth.

-So [laughs]-
-50% on anything is nothing.

-Since we haven't had a sponsor.
-[laughs] Sorry.

-[laughs]
-We are, we-

-Since we haven't had a sponsor in, like-
-[laughs]

... years, I'm getting a steal on this
thing.

-That's right. I said, I said to Aaron-
-Oh, man

... that, uh, that the, the unsponsorable,
the unsponsorable comment was ruthless.

It was fair, but it was ruthless. [laughs]

-Oh, so funny. So funny. Oh, my.
-He'll be fine.

-Well, anyway.
-I think, I think he's for himself.

Yeah, I agree. I agree. No, totally,
totally. He'll do great. And I think Steve

will do well too. I mean, I think people
knowing that he's available, I mean, heck,

when I heard that he was available, I'm
like, "Oh, geez. I have a couple things I

could have him do actually." Like,
actually-

-I said how-
-... one specific thing that I thought of

that I was like, "I would love for Steve
to do this," but I knew he wouldn't have

-time.
-Yeah.

-So maybe now he does.
-Maybe. Get into it. 'Cause I said, "How

long before he'll... How, how long before
he lands on the Lara ship?" So...

-[laughs] Right.
-Get him before it's too late.

May- Who knows? Maybe that was, uh, maybe
that was part of his, his calculation.

Maybe he was like, "You know what?

I can have a job over here if I really
wanted one."

-Mm-hmm.
-"So maybe I'll just do the job thing for a

-bit." Who knows?
-Yeah.

Not making any, uh, assumptions here. Hey,
folks, also if you have not bought your

Laracon tickets yet, it's might be too
late. But if it's not, you should

definitely go buy them because Michael and
I would love to see you there. We're

gonna doing some interviews there. We're
gonna be enjoying the show, watching all

the talks, and we would love for you to
say hi. So please stop by and say hey.

Look for, uh, the really tall guy and look
for the handsome Australian with the, uh,

other cursing Australian next to him.
That will be Aaron. Uh, OG, OG Aaron.

-[laughs]
-OG Aaron.

[laughs] OG Aaron making an appearance
again at Laracon US.

-Yeah.
-He's gonna be a riot. I can't wait to see

him.

Fun.

-It'll be good fun.
-Awesome.

Episode 178, folks. Thanks for tuning in.
You can find us at North Meets

South.audio/178. Hit us up on X or on
BlueSky at Jacob Bennett, at Michael

Dorando, or at North South Audio. And, uh,
if you liked the show, rate it up in your

podcast app of choice. Five stars would
be amazing. Thanks, folks. If you'd like

to sponsor us,

also talk to us on those channels. It
won't happen. But if you'd like to, we'd

love for you to. But until next time,
we'll see you.

Oh.

Creators and Guests

Jake Bennett
Host
Jake Bennett
Christ follower, software dev @wilbergroup using @laravelphp. Co-host of @northsouthaudio and @laravelnews with @michaeldyrynda
Michael Dyrynda
Host
Michael Dyrynda
Dad. @laravelphp Artisan. @LaraconAU organiser. Co-host of @northsouthaudio, @laravelnews, @ripplesfm. Opinions are mine.
Flavours of busy, restrained features, and variable static views
Broadcast by