►
Description
Today we discussed Railway Oriented Programming and started work on refactoring into that pattern
https://gitlab.com/groups/gitlab-org/-/epics/10956
A
C
A
C
B
A
Give
some
background
here:
what
we're
doing
is
so
it's
the
Greenfield
feature
it
just
hit.
A
You
know
early
this
year
and
before
we
start
adding
more
features,
we've
made
the
decision
to
refactor
this
to
some
functional
patterns
that
will
make
it
easier
to
work
with
because
it
was
already
getting
a
little
bit
coupled
and
complex
and
and
convoluted
and
hard
to
follow.
And
this
the
pattern
we'll
be
using.
Is
this
Railway
oriented
programming?
A
It's
a
common
functional
pattern,
just
based
around
the
result
type-
and
this
is
a
really
good
presentation-
that
sort
of
explains
it
we'll
go
into
here,
and
so
we
had
sort
of
four
subdomains
to
currently
to
the
remote
development.
There
is
the
workspace
update.
The
agent
config
update
the
workspace
created
in
the
workspace
reconcile,
which
we're
sort
of
in
increasing
orders
of
complexity,
and
so
we've
broken
it
down.
The
first
three
parts
are
done
and.
A
The
fourth
part
here
and
to
show
you
sort
of
what
one
of
the
existing
ones
looks
like.
So,
let's
start
with
you
know
just
the
service
and
we'll
look
at
the
update
service.
That's
the
first
one.
We
did.
A
Here's
an
article
I'm
going
to
talk
about
that
and
this
this
is
linked
in
the
the
readme
I
missed
the
readme,
but
sort
of
there's
these
architectural
layers
and
ports
and
adapters
is
another
way
to
think
of
this.
So
you're
into
main
logic
lives
in
the
middle
here
and
then
there's
services
around
that
and
then
there's
the
other.
Your
API
is
around
that
and
then
these
have
ports
and
adapters
of
how
they
talk
to
the
different
layers
and
I've.
Also
in
our
domain
folder,
you
know
an
ee
lab
remote
development.
A
A
And
like
here's,
the
tldr
quick
start
like
if
you're
just
working
on
this
but
the
overview-
and
this
is
sort
of
a
simplified
version
of
that
diagram
instead
of
square,
not
hexagonal
and
then
so
we're
doing
some
new
things
in
here.
We
have
some
type
safety,
there's
some
interesting
things
you
can
do
in
modern
in
in
roomy
three.
That
can
give
you
some
type
safety,
which
is
cool.
A
A
B
A
It's
a
a
single
pin,
class
method.
We
don't
have
any
instances
because
we
don't
want
State.
There
shouldn't
be
any
state
in
any
of
this
and
we
pass
in
the
stuff,
and
then
we
just
get
a
hashback
from
that
like
it
doesn't
return
a
service
response,
because
that
would
be
breaking
the
the
boundaries
between
the
domain
logic
and
the
service.
A
The
service
response
lives
in
the
service
tier
and
that
would
actually
be
a
circular
dependency
in
terms
of
like
pack
work,
because
the
domain,
the
service
class
would
be
depending
on
the
business
logic,
but
the
business
logic
would
be
referring
to
service
response
which
lives
in
the
service
tier.
That's
the
circular
dependency.
So
that's
why
we
just
return
a
hash
here
and
then
the
we
have
this
little
helper.
That
turns
that
hash
into
a
service
response.
A
So
the
actual
domain
logic
like
I,
said
the
the
orange
space
update
is,
is
really
simple
and
you
can
talk
more
about
the
pattern.
I,
don't
know
how
deep
you
want
to
go
into
it,
but
it's
it's
basically,
a
result
which
is
a
an
object
that
encapsulates
something
succeeded
or
failed.
It
was
okay
or
error
and
then
it's
a
monad,
but
you
don't
have
to
know
that
word
or
what
it
means,
or
that
it's
not
a
burrito
at
all
to
understand
how
this
works.
A
It's
just
when
we
start
with
this
concept
of
a
result
which
could
be
okay
or
error,
and
then
you
just
chain
the
different
steps
of
your
business
logic.
You're
doing
and
you
pass
a
higher
order,
function,
we're
saying:
okay,
then
we're
going
to
call
this
method.
You
know
if
the
first
thing
was
successful,
which
in
this
case
all
it
did
was
wrap
up
the
data
we're
passed
in
and
then,
if
the
authorizer
was
successful
and
then
we're
going
to
go
ahead
and
do
the
update
if
the
authorized
were
not
successful.
A
This
was
short
circuit
and
fall
through
and
not
do
anything
after.
If
and
then
we
have
this
concept
of
we're
just
returning
domain
messages
and
so
like
if
it's
unauthorized,
we
we
pattern
match
on
that
or
if
the
upstate
failed.
You
generate
an
error
response
which
this
just
gets
turned
into
the
service
response.
As
we
saw
the
the
chain
and
if
it's
successful
then
you
know
the
context
contains
the
workspace
update,
which
then
gets
stuck
in
the
service
response
and
returned.
A
B
Yeah
yeah
I
didn't
like
that
class.
Okay
anyway,
that
initial
result
and
and
the
calls
to
and
then
and
then
what
happens
when,
for
example,
the
authorizer
doesn't
succeed,
that's
that's
going
to
stop
the
execution
right.
Yeah.
A
B
B
A
So
these
and
bins
that
you
see
here
is
just
a
method
here
and
you
get
passed
in
the
Lambda
or
a
method
object,
and
it
does
this
check
like.
Is
it
successful,
okay,
we're
going
to
pass
it
along?
Did
it
fail?
Is
it
an
error?
Okay,
then
we're
going
to
Short
Circuit
everything
after
and
this
is
this-
the
names
of
his
methods
and
everything
are
basically
exactly
based
on
rest
and
the
result.
Type
is
a
standard
pattern
in
all
functional
languages.
That
you'll
see.
A
Does
that
explain
it
so
like
here
we
can
see,
you
know
the
and
then
unwrapped
the
value
out
of
the
result
right
the
okay
value
and
passed
it
along,
which
is
what
we
what
we
got
here
and
then
we
we
use
this.
It's
called
right
word
assignment
it's
a
ruby.
Three
thing:
we
just
are
destructuring
this
into
the
two
keys,
but
it
also
gives
us
some
type
safety
so
like.
If
we,
this
happened
to
be
nil
or
the
wrong
type,
it
will
blow
up
immediately
with
a
with
a
language
error.
A
B
A
Yes,
that's
the
best
we
can
get,
but
when
you
run
your
tests,
it's
before
it's
actually
in
production.
So
that's
time
safety
and
so,
like
we've
restructured
that
these
two
values-
and
this
is
like
what
you
would
normally
see
in
the
service
except
it's
down
in
our
domain
layer
encapsulated
in
this
one
step
that
is
decoupled
from
everything
else.
A
This
coupling
is
good
and
it's
cohesive.
It
does
a
single
thing.
All
it
does.
Is
the
workspace
up
a
it
does.
Do
authorization
doesn't
do
anything
else,
High
cohesion,
the
root
of
all
that
is
good
in
software.
There's
coupling
High
cohesion.
So
this
is
the
answer
of
your
question.
Let
me
just
do
the
update
and
you
know
same
thing
check
real
active
record
is
going
to
return.
A
You
know
true
or
false
for
this,
and
you
wrap
that
in
the
result,
if
it
was
okay-
and
this
is
just
a
the
domain
message
like
I
said
rather
than
trying
to
throw
exceptions
like
the
whole
point
of
this-
is
to
avoid
using
exceptions
as
control
flow
and
especially
in
remote
development
like
in
the
reconcile
that
we're
doing
now,
there's
like
we're
processing,
multiple
workspaces
at
a
time
like
lots
of
things,
could
fail
for
an
individual
one,
but
we
want
to
keep
processing
them.
A
We
want
to
be
able
to
log
Trace,
perhaps
record
that
so
the
decoupling
of
all
of
the
failure,
handling
and
messaging
is
the
whole
point
of
this.
That
can
now
live
up.
You
know
at
this
level
or
in
something
that
is
like.
Okay,
we
gotta.
We
got
a
failure
here,
here's
what
we
do
in
this
case
of
this
failure,
and
it
all
of
that
error,
handling
and
Reporting
and
tracing
and
logging
and
everything
doesn't
have
to
live
here
with
the
actual
domain
logic
of
doing
the
work
of
the
update.
A
A
A
Right
and
there's
some
new
answers
we
debated
like
these
messages,
are
only
for
expected.
Failures
like
we
got
some
bad
input.
This
is
something
we
expected
we're
going
to
wrap
it
up
in
the
domain
message
and
it'll
get
given
back
to
the
user,
as
whatever
message
may
be
logged,
maybe
whatever
unexpected
message
out
of
memory,
the
network
failed.
A
You
know
something
like
that:
we
don't
catch
those
just
let
them
bubble
up
to
the
top
rails
will
wrap
them
into
500,
like
it
always
does
so
like
you're
not
going
to
catch.
Every
error
here
only
expected
errors
that
are
like
due
to
input
and
that
that's
a
Nuance
that
we
just
debated
a
lot.
So
looking
at
the
code
like
you
can
see
the
all
of
our
service
layer,
there's
like
nothing
to
it
and
I'm
in
the
process
of
rewriting
this,
the
third
one
here,
here's
the
agent
config.
A
So
that's
intentional,
like
that's
the
hexagonal
architecture,
there
is
no
domain
logic
here,
none
because
it
doesn't
belong
there
and
belongings
in
the
middle
of
the
hexagon.
And
if
you
look
at
create
service,
for
example
like
this
one
is
more
complex,
it's
got
multiple
steps,
it
authorizes
it
fetches
the
div
file
and
valid
pre-validates
the
dev
file.
Then
it
flattens
it
which
is
actually
calling
our
gym,
which
wraps
this
Dev
file,
CLI,
which
does
other
validation
and
then
there's
some
more
validation.
We
do
after
it
does.
A
You
know
that
thing
does
its
thing
and
then
we
we
Define
our
volumes
and
then
we
inject
various
things
into
the
volumes.
This
is
all
setting
up
the
the
kubernetes
environment
for
the
remote
development
workspace
like
or
defining
the
dev
file,
which
will
Define
the
remote
development
environment
and
then
actually
create
the
database
record
for
the
remote
development
which
contains
this
flattened
process,
validated
everything
debt
file.
So
then,
and
then
the
way
remote
development
works.
A
Here,
go
do
your
thing
on
kubernetes
and
and
then
does
it,
and
so
you
can
see
here
like
even
when
I
refactored,
this
I
was
like
man,
it's
I
had
to
completely
re-understand
the
logic
we
wrote,
which
was
already
getting
a
little
bit
nested
and
convoluted
and
hard
to
follow
with
exceptions,
and
now
it's
like
boom
boom
boom
boom.
It
does
everything
in
order,
that's
the
intro
to
what
we're
doing
and
so
now
I'm
on
the
reference
Style
part
of
it,
which
is
turning.
A
This
oh
tearing
it
apart
right-
and
this
is
like
just
the
top
level
like
then
you
go
into
the
Asian
info
parser,
which
does
this
and
then
there's
the
actual
state
calculator.
There's
like
this
nested
hierarchy,
but
now
it's
it's
going
to
be
at
least
this
Railway
oriented
programming,
where
these
will
be
like
clearly
defined
steps
that
can
succeed
or
fail.
A
But
this
particular
one
is
trickier
because
we
have
to
Loop
over
them
and
handle
any
possible
error
that
could
happen
at
for
a
single
workspace,
but
still
go
ahead
and
process
the
others
that
the
because
the
agent
when
it
records
sends
a
reconcile
request.
It's
like
all
of
the
workspaces
reconcile
at
the
same
time,
in
the
same
request.
A
Yeah
it's
like
enemy
nested,
so
at
the
top
level
here
you
know
what
we
have
in
Maine
there's
like
okay.
First
we've
the
request
we
got
from
the
agent
we're
going
to
validate
it,
then
we're
going
to
extract
the
parameters
out
of
it
and
then
and
I'm
sort
of
making
this
up
as
I
go
because
I
have
to
figure
out
what
it's
going
to
look
like
in
this
pattern,
but
then
there's
this
reconciler.
A
B
A
To
ask
them
all
along
and
then
at
the
end,
all
the
ones
that
were
error.
You
know
up
here
at
this
level
or
somewhere
we'll
do
our
logging
reporting
writing
them
to
the
you
know,
our
our
versions,
log
we're
eventually
going
to
want
to
keep
a
version
of
everything
that
happened
to
every
workspace,
like
all
of
that
stuff
will
be
decoupled.
You
know
at
this
level-
or
you
know,
probably
at
this
level,
but
like
not
in
the
individual
places
where
the
air
is
actually
happen,
we'll
we'll
capture
those
okay
thoughts,
Terry.
C
C
Looks
wild
so
I'm
kind
of
interested
to
see
like
how
do
you
decide
like
I
guess
how
to
break
that
out,
like
I,
think
he's
kind
of
like
is
in
the
same
line
of
what
we
talked
about
before
so
like
going
through
the
process
of
taking
something,
that's
like
funky
and
chunky
and
like
getting
it
into
something
workable.
Without
you
know
three
hours
later
looking
and
being
like
okay,
what
did
I
do?
Everything
is
broken
so.
A
A
The
one
we
were
trying
to
refactor
you
me
and
Casio,
and
we
we
failed
because
there
was
that
coupling
it
was
coupled
through
inheritance.
It
was
a
couple
modules.
It
was
coupled
through
instant
state.
A
A
A
C
We
just
need
to
clear
that
all
right,
yeah,
okay
I,
mean
it's
not
technically.
Cheating
I
feel
like
it's
just
like
experience,
coupled
with,
like
the
future
state
that
you
knew
you
maybe
you're
like
I,
want
to
get
somewhere
else
to
like
not.
You
know,
and
this
code
is
what,
how
old,
like
months
and.
A
A
A
And
Gregor's
recommended
that,
which
is
a
great
idea,
and
it's
a
much
less
friction
than
trying
to
do
it
in
the
docks
with
technical
writers,
because
you
really
don't
care
that
much
but
yeah
like
and
the
other
good
thing
about
this.
These
functional
patterns
like
they're,
even
if
you
don't
read
the
review
they're
like
difficult
to
break,
you
can't
just
go
off
and
say
all
right,
I'm
going
to
make
an
inheritance
here,
you
know
pull
in
a
module
what's
like.
That
is
completely
against
the
pattern.
B
A
The
next
steps
need,
but
I
personally,
like
keeping
everything,
because
then,
when
you're
debugging
it
and
you
put
a
break
point,
you
know
like
in
the
very
last
step
here,
like
man,
something's
broken
I,
put
a
break
point
here.
You
can
look
at
all
the
previous
state
that
these
other
things
have
worked
with
and
say.
Well,
where
did
this
come
from?
What
was
the
state
of
the
original
that
file
before
it
got
flattened?
And
you
know
where
did
this
bug
come
from?
So
just
this
value.
B
B
A
B
Yes,
but
you
said
that,
if
I,
if
like
I'm
in
us
in
a
level
that,
in
a
step
in
inside
of
this
chain
that
changes
some
value-
and
you
don't
want
to
pass
only
that
value
on-
you
want
to
pass
everything
so
that
in
the
end,
you
know
the
you
have
a
full
view
of
what
happened.
Do
you
also
know
what
step
changed?
B
A
No
it's
more
like
when,
when
you're
transforming
it
into
a
different,
you
know,
structure
like
for
the
dev
file.
For
example,
we
start
with
you
know,
just
a
it's
a
yaml
file,
but
it's
like
a
minimal
one
that
the
user
takes
into
their
repo
and
then
in
this
flattener
step
is
where
it
gets.
We
pass
it
to
that
gym,
which
is
wrapping
the
the
dev
file.
Cli
like
this
is
a
standard
for
how
to
do
promote
orange
spaces
and.
B
A
Gives
you
back
this
other
yaml?
That's
like
bigger,
expanded
out.
It
has
stuff
injected
into
it.
It's
pulled
in
remote
parents
and
stuff
so
like.
That
is
why,
in
if
you
were
to
look
into
here
right
this,
this
gets
the
original
Death
Valley
ammo,
which
is
the
original
one,
and
then
it
spits
out
this.
A
B
A
And
I'm
always
really
I
put
a
lot
of
thought
into
naming
things
because
it's
important
like
this
one
intentionally,
it's
a
yaml
file,
so
it's
named
in
yaml.
This
one
doesn't
have
yaml,
because
it's
a
hash
right,
like
I,
could
have
just
named
this
Dev
file,
but
by
looking
at
once,
you
understand
the
standards
like
looking
at
the
variable
name.
You
know
this
contains
yaml
just
by
looking.
A
So,
where
I'm
at
like
I,
said
I
just
and
now,
you're
probably
going
to
see
me
flounder,
like,
like
I,
said
I'm
slow,
plotting
and
methodical
like
how
do
we
break
this
up
the
we
need
to
somehow
do
what
we're
going
to
do
here,
the
each
with
object
and
lymph
over
them.
So
my
plan,
like
the
algorithm
here,
is
like
we
have
these.
A
The
request
came
in
and
it's
these,
what
we
called
Agent
infos
and
that's
just
an
array
of
Json
which
in
this
case
the
return
to
the
hash
and
it
came
from
the
agent
K
and
each
of
those
represents,
like
the
information
about
this
workspace,
the
current
state
of
it
in
the
remote
development,
environment
right
and
it
could
contain
an
error,
and
we
have
to
calculate
it.
It's
like
kubernetes
sort
of
specific
stuff,
and
we
have
to
translate
that
and
turn
it
into
what
we
call
like
an
actual
state
which
is
like
is
it
running?
A
Is
it
restarting?
Is
it
terminating?
Is
it
terminated
so,
like
all
of
that
is
sort
of
this
part
of
the
logic
and
then
there's
this
concept
of
the
desired
state,
which
is
the
user
on
the
UI?
They
click
the
button
and
they
said
I
want
to
stop
this
workspace.
I
want
to
start
this
workspace
I
want
to
restart
it.
I
want
to
terminate
it,
and
this
reconcile
is
bringing
all
that
together
for
each
workspace.
So,
like
we
take
this,
this
raw
Json
hash
data
from
the
kubernetes
free
short
space
Loop
over
them.
A
A
We
look
up
the
ones
in
the
database
that
correspond
to
the
request
from
the
the
agent
right,
so
then
persistent
workspaces
for
managing
info.
This
is
like
all
right.
Here's
the
database,
references
that
correspond
to
the
ones
that
we
got
in
the
request
from
Agent
K
and
then
we
say
are
any
of
them
orphan.
You
know
report
an
error
for
that,
and
then
we
say:
okay,
maybe
this
one,
you
know
we
had
requested
it
to
be
terminated.
Our
desired
state
was
terminated
last
time
and
then
on
the
last
reconcile.
A
Loop
okay
now
has
been
terminated
and
we
need
to
update
that
actual
state
in
the
database
to
say
yes,
this
is
terminated
and
then
that
gets
displayed
in
the
UI
when
it's
persisted
in
the
database
and
then
there's
a
concept
of
like
a
full
versus
partial
reconcile.
I
won't
even
do
that,
but
then
the
the
final
step
is
so
then
we
have
to
say:
okay.
Is
there
any
new
workspaces
like
since
the
last
record
style
Loop?
Has
somebody
requested
a
new
one
to
be
created?
A
If
so,
we
need
to
let
the
agent
K
know
about
that.
So
it
can
apply.
All
those
kubernetes
resources
and
create
it.
So
then
the
final
step
is
like
all
right.
We
call
rails
infos,
there's
like
agent
infos,
the
stuff
that
comes
in
rails,
infos,
the
stuff
we
send
back
and
We
Gather,
all
those
together,
which
is
like
either
an
acknowledgment
that
we've
applied.
This
new
information
you
sent
us
about
the
state
or
whatever
or
an
error,
as
well
as
any
new
workspaces
that
have
been
created
since
the
last
time.
A
A
You
know
like
the
agent
infos
and
then
all
of
the
the
worst
Nations
for
that
Asian
info
without
any
additional
things
from
the
database
that
we
found
and
then
put
that
all
together
transform
it
into
the
format
that
we're
gonna
as
Json
pass
over
the
wire
back
to
it.
So
that's
the
algorithm
and
my
thoughts.
B
C
Yeah
yeah
I'm,
hoping
like
I,
can
like
see
almost
like
these
chunks
in
the
pattern
like
you've
kind
of
squint
at
the
code
like
I
can
almost
like.
Are
there
like
four
or
five
places
in
here
where
each
of
those
things
would
be
one
of
those
like
then
blah
blah
blah
blah
and
then
blah
blah
blah
blah
and
so.
A
A
The
difference
is
like
here
both
in
in
all
of
these
previous
ones,
we're
working
with
one
thing
here:
we're
like
creating
a
thing
where
Asian
Asian
config,
you
know
we're
updating
a
thing
and
the
the
workspace
update.
We're
like
updating
a
thing
here
is
different:
we're
like
okay,
we
we
got
this
request.
That
represents
multiple
things.
A
Right
first
thing
we
do
is
make
sure
that
is
okay
and
like
extract
some
data
from
it,
then
the
actual
reconcile,
which
is
going
to
be
Loop
over
those
multiple
things
in
multiple
ways
and
then
do
whatever
we
need
to
do
at
the
end,
so
the
way
I'm
envisioning
it
is
this
reconcile
like,
and
you
can
actually
Nest
these
things.
I
forget
where
else
did
I
do
it
in
here.
A
In
yeah,
so
this
pre-flattened
Dev
file
validator
right.
So
this
is
a
a
step
in
the
top
level
in
the
main
logic
here,
but
it
itself
has
this
nested
pattern,
because
it's
this
one
step
has
some
distinct
sub
steps
that
it
does
in
here
and
they
happen
to
be
private
methods,
but
we're
still
breaking
them
up
with
the
same
pattern,
and
so,
in
this
case,
I
think
for
the
reconciler
we're
going
to
take.
You
know
the
workspace
rails
info
or
sorry,
the
the
Asian
infos
that
we
get
passed
in
this
thing,
abstracted
right.
A
It
won't
be
a
result
and
then
we'll
use
standard
rails,
but
like
functional
patterns
like
this
dot
map
dot
each
with
object,
dot,
whatever
we
do,
which
will
correspond
to
how
we're
doing
here
like
there's
an
each
with
object,
there's
a
loop
and
then
here's.
You
know,
mapping
over
to
find
all
of
the
the
persistent
things
and
add
that
to
the
the
ones
we
found
and
then
here
is
like
updated
workspaces,
persistent
workspaces
with
info.
It
is
a.
A
Sorry
where's
the
loop
here
this
one,
here's
an
each
that's
the
the
thing
that
saves
the
data
coming
from
Agent
K
into
the
database
for
each
one.
And
then
here
is
the
loop.
You
know
adding
putting
them
together
the
ones
we
got
plus
any
new
ones
and
then
finally,
there's
the
loop
like
build
for
each
one
of
these.
The
response
so
the
way
I'm
envisioning
it
is
that
there's
going
to
be
in
this
reconciler
like
multiple
of.
A
A
I
think
I
need
to
see
it's
like
cohesion
right,
so
that
all
this
reconcile
is
going
to
have
is
like
the
logic
to
Loop
and
process
over
these
things,
but
the
actual
logic
of
it
is
gonna,
try
to
be
extracted
out
to
other
classes,
so
yeah.
What
we'll
look
like?
What's
the
first
thing
we
well,
let's
look
at
the
data
we
get
in
here,
so
the.
A
Trying
to
remember
work
space
station
info,
so
that's
the
name
of
his
key
and
then
that
gets
passed
down
to
here.
We
validate
it,
so
this
is
just
flattening
it
out.
So
it's
like
putting
the
agent.
That's
like
the
the
thing
on
the
rail
side
that
sort
of
receive
this
request.
You
know
it's
sort
of
an
internal
API
call,
and
then
we
took
everything
that
was
in
the
params,
which
was
just
the
word.
Space
agent
info
is
in
the
update,
type
and
flattened
that
out
to
the
top
level
of
this
value.
A
Over
workspace
agent
infos
as
far
as
teaching
this
like
I
kind
of,
tend
to
look
at
the
logic
and
write
it
and
then
backfill
some
tests
for
how
I
think
it
will
work.
But
this
is
the
most
complex
one,
so,
first
starting
by
destructuring,
the
value
so
value.
We
do
the
right
word
assignment
and
it's
like
you
can
be
more
space
station
infos
and
that
should
be
an
array.
A
Let
me
throw
this
over
there
right
I
guess
they
changed
the
name
of
that
so
yeah,
we're
like
this
is
sort
of
where
we're
at
doing
this
stuff
go
ahead.
B
Yeah,
like
those
it's
almost
three
or
four
Loops,
if
I
remember
correctly,
and
those
Loops
are
not
really
related
to
one
another,
they
are
just
Computing
like
I'm
doing
the
first
Loop
to
compute
some
some
stuff,
then
I'm
taking
that
stuff
and
passing
through
the
second
Loop
and
go
on
like
that.
So
it's.
A
B
B
So
basically,
you
could
almost
take
those
Loops
one
bytes
by
itself
and
create
a
method
around
that
and
then
basically
create
that
and
then
structure
calling
each
method
one
after
the
other.
B
A
Implies
there's
something
that
could
fail,
but
the
one
thing
I
didn't
mention
like
if
you
look
at
this
one,
for
example,
there's
this
and
then
versus
a
map
right
yeah.
And
if
you
look
at
one
of
the
and
vins
you
see,
they
return
results
because
they
could
possibly
fail.
Yeah.
C
A
This
is
exactly
like
the
rest,
API,
the
exact
same
name
and
behavior
and
the
rest
result
type
but
map.
If
you
look
here
it's
similar
to
and
then
but
it's
used
for
methods
which
always
succeed.
Okay
right
and
if
you
look
at
one
of
them,
they
get
a
value.
You
know
even
the
and
then
gets
a
value
because
it
was
automatically
unwrapped,
but
they
just
return
a
value
directly
and
then
the
framework
wraps
it
back
into
into
a
result.
A
So
that's
why
the
reconciler
is
a
map
because,
like
it
can't
fail,
all
it's
going
to
do
is
go
over
Loop
over
these
things.
The
individual
workspaces
could
be
in
some
failure,
State
and
they're
going
to
be
results,
but
what
We're
looping
over
isn't
going
to
be
an
array
of
results,
so
we
sort
of
have
to
wrap
these,
and
so
like.
B
A
Question
this
is
just
going
to
be
plain
logic.
We
don't
need
to
have
the
ambient
at
this
level
it's,
but
we
need
a
Wrap
I
think.
The
first
thing
we
want
to
do
is
wrap
each
workspace
station
info
in
a
result,
and
then
that's
what
we're
going
to
be
looping
over
and
passing
that
array
of
results
along.
B
Okay,
but
what
happened?
What
if,
for
example,
database
update,
fails,
that's
an
error,
while
looping.
A
Yeah
so
like,
if
it
failed
due
to
a
validation,
error
right
that
meant
honestly
like
that,
should
be
a
bug,
because
this
data
originally
came
from
Agent
K,
which
is
go
code
that
lives
in
git
lab
agent
for
kubernetes
project,
but
we
own
all
that
code
so
like
if
we
gave
it
something
that
couldn't
be
applied
in
the
database
like
there
was
no
user
input
involved.
A
A
So
we
don't
want
to
let
that
bubble
up.
There's
no
downside
to
letting
the
error
Bubble
Up
in
these
things
that
are
only
dealing
with
a
single
thing,
because,
whatever
your
thing
failed,
there's
nothing
else
happening
here,
you're
not
going
to
affect
anybody
else,
and
your
thing
wasn't
going
to
work
here.
We
we
have
to
think
about
it
differently,
because
you.
A
A
Okay,
all
we
do
is
throw
a
message.
I
think
the
one
thing
I
didn't
show.
You
is
like
how
these
messages
work.
So
the
result
you
just
the
the
okay
in
the
error
they
can
wrap
anything
it's
like
whatever
you
want
to
put
in
here.
That
represents
your
your
okay
or
error
is
fine,
but
in
our
case
and
that's
why
this
lives
in
the
top
level
this
is
in
live
anybody
can
use.
This
is
completely
generic,
but
our
our
failure
messages.
A
There
so
these
are
type
safe
and
that's
that's
what
lets
us.
You
know
pattern
match
on
them
in
a
nice
way
here,
it's
like
if
your
air
is
unauthorized
to
do
that.
If
you're,
you
know
any
of
these
errors,
we
do
a
specific
thing.
If
a
successful,
we
do
a
specific
thing,
and
each
of
these
is
an
instance
of
message
which
just
has
a
context
which,
in
our
case,
is
like
it's
just
a
hash
of
information
that
you're
passing
that
could
be.
You
know
why
it
failed.
A
A
A
A
A
A
So
it's
going
to
be
this
same
sort
of
loop,
but
do
we
want
to
have
this
logic
here?
No,
we
probably
went
this
logic
to
live.
Maybe
in
another
class
which
is
the
you
know,
we
already
have
the
corresponding
Asian
info
parser
here,
right
yeah,
which
is
the
all
this
is
doing,
is
taking
the
structure
and
turning
it
into
this
value.
Object
from
the
hash.
A
So
here's
where
I'm
I'll
have
to
think
about
it
more
because
and
I've
talked
a
lot
about
this
with
Paul
Slaughter
and
like
how
this
works
in
Rust.
But
it's
kind
of
different,
like
we
have
the
array
of
results,
but
the
sorry
in
in
here
that
we
can
pass
around.
A
A
Like
these
are
really
the
the
name
is
a
little
off
here,
because
this
this
is
a
a
hash
and
then
what
we
return
here
is
like
Vim
by
name
so.
A
Or
is.
A
A
And
we
basically
could
pull
this
out
to
a
new
class
and
have
it
there
the
looping
part.
We
already
have
the
agent
info
parser
stuff
here
we
could
sort
of
transform
this
to
take,
but
this
is
only
dealing
with
a
single
one
right.
So.
A
This
is
where
I
said
I
would
flounder
like
how
do
we
want
to
handle
that
we
wrap
this
up
in
results
and
and
convert
this?
We
may
have
to
be
manually,
unwrapping
results
and
and
other
stuff.
C
A
C
So
he's
like
posting
the
channel
afterwards,
so
we
can
look
at
the
Mr
when
it's
done.
Yeah.
B
A
B
A
C
The
nice
thing
about
a
refactor
you
can
go
and
be
like
that.
This
don't
feel
right
or
it
doesn't
work
right
or
the
return
object
that
you
get
doesn't
look
right,
but
I
really
appreciate
you
walking
through
this
with
us,
yeah
I
I
would
just
say
if
you
do
end
up
getting
the
Mr
up
and
merged.
If
you
wouldn't
mind
sharing
in
the
channel,
because
I
am
interested
in
what
it
looks
like
yeah.
C
A
A
C
A
A
Instead,
which
is
a
functional
programming
conference
and
I,
went
into
those
talks
and
I'm
like
I,
don't
even
know
the
words
they're
using
I
have
no
clue
what
they're
talking
about,
but
this
seems
amazing
and
then,
when
I
actually
started
doing
it
like
I
did
a
little
bit
in
kotlin
and
I
did
a
little
bit
of
elm
and
what
I
realized
is.
You
know
you
think
about
the
test
pyramid
Indian
tests
at
the
top.
You
know
user
interface
unit
test
at
the
bottom
and
then
the
middle
is
the.
A
A
You
don't
have
to
write
tests
for
that
layer,
it's
like
it
won't
even
compile
it
won't
even
run.
If
you
don't
have
that
stuff
right
and
then
like
when
I
went
back
to
writing,
vanilla,
JavaScript
and
vanilla
Ruby
I'm,
like
oh
man,
I,
have
to
write
all
these
tests
just
to
catch
my
own
stupid
errors,
you
know,
so
they
don't
happen
at
runtime.
A
C
Yeah
I
I,
don't
know,
I
feel
like
just
being
like
flat
out
like
no
against
anything.
For
me
is
just
not
I,
don't
know,
I
try
to
be
I,
try
to
be
open-minded,
I
won't
say:
oh
ISM,
but
I.
Don't
really
I
I
went
to
strange
Loop,
which
is
I.
Think
one
of
the
other
functional
programs.
C
I
never
got
to
use
that
at
work,
but
I
remember
just
being
like
Oh.
It
seemed
it
seemed
pretty
cool
when
I
was
there
so
but
I
make
you
know,
I
think
it's
interesting,
it'll
it'll
be
cool
to
see
like
where
remote
development
is
in
six
months
to
kind
of
see
how
far
y'all
have
been
able
to
take
like
the
development
style
that
that
Aaron
comes
singing.
Maybe
that
can
be
something
that
other
teams
start
to
embrace
and.
C
After
our
last
debugging
session,
yes,
I
appreciate
this.