00:00:04.620
all right hello everyone I'm Tim commuter sweet from Australia or
00:00:11.620
I work for a company called ice lab and I'm also a core developer in the dry
00:00:16.840
bein Rama B Ruby projects and it's really great to be back in Singapore we
00:00:23.140
love this city it's a great weather great food and thanks it is my whole family this is us here we're here for
00:00:29.769
last year's conference we had a great time our daughter was 1 and my wife was pregnant and here we are now back again
00:00:36.719
my daughter first daughter is 2 years old second one seven months and I was
00:00:41.829
thinking about this and I'm actually scared about what might happen if I come back next year we have space right angle keeps in the
00:00:48.370
family and onto the technical things I'm sorry to say I've got nothing to add to
00:00:53.980
matters comments about every end or JIT compilers except to say that I'm glad he is taking care of it I'm here today to
00:01:01.660
talk about something a bit different building applications with review and I want to talk about a big shift in the
00:01:07.479
way I've been writing rubia I want to talk about functional architecture and I
00:01:13.869
wouldn't start our journey into functional architecture strangely enough with object-oriented design that's that
00:01:20.530
thing we should all aspire to as rubyists right we had these object-oriented design
00:01:25.659
principles like solid to guide us and we know these things are important and that they should influence the way we write
00:01:31.330
our code we've been hearing this for years and myself I'd watch talks about these things too and I say to myself
00:01:37.150
yeah this is how I should write my code and then I'd go back to whatever I was
00:01:43.000
working on and quite frankly it was a mess by comparison and I think my
00:01:48.310
problem was that in my mind I tend to opt for pragmatism over design and I'd
00:01:53.710
reassure myself and I'd say this situation is ok I'm a practical developer I've got work to do what
00:01:59.950
architecture but not surprisingly the longer I worked in these apps the harder
00:02:05.170
and harder they became to change and that's really the point of architecture and design that applied to code these
00:02:11.980
things aim to make change easy and a well-designed codebase it should stand the test of time and we can see
00:02:19.720
these things illustrated through martin fowler's design stamina hypothesis we can lay it out on a chart on the bottom
00:02:26.170
axis we have time on the Left we have features built and then if we start an
00:02:31.960
app without paying much attention to design we may get a really nice initial spike in features but over time that
00:02:37.750
curve kind of leveled off as it becomes harder and harder to build new things but on the other hand if we pay a bit
00:02:44.290
more attention upfront to some good design approaches well there might be a bit of a slower ramp up but over time we get this really steady ability to add
00:02:50.650
new features so we see here we have this line between them this design payoff line and I think my problem was I spend
00:02:57.550
too much time thinking about the bottom left of that chart when really I should have been thinking about all the space above that line there and I think this
00:03:04.750
is a mindset that's perhaps endemic in our community in general because we found our fame in enabling those
00:03:11.440
early-stage productivity wins my problem was also that I wasn't comprehensively
00:03:18.610
applying better designs of my applications some band-aid approaches here and there they might help but
00:03:25.030
they're really not just enough and since our job as developers is to deal with change and given the truth that we can't
00:03:33.070
always predict where change will come from what we want ideally is a good
00:03:38.110
design that covers our in their entirety so that's why I'm here today so everyone
00:03:44.440
stand back about something to say functional programming will save us well
00:03:51.600
maybe not quite like that this is the Ruby conference after all and I know
00:03:56.680
many of us 20 were different languages but I can still consider myself happy with Ruby and a practical rubyist and
00:04:02.260
likely Ruby itself is a practical malleable language and it's going to allow us to model things nicely along
00:04:08.740
functional lines - the first step towards a functional architecture is a
00:04:13.780
change in mindset it's about viewing your app as a series of transformations we did our initial data HTTP request for
00:04:21.790
example and then we can run that through a number of transformative steps with each one passing some data to the next
00:04:27.400
until at the other end we get some HTML so in another light an app model is a
00:04:33.729
series of transformations is really an app model is a series of functions and
00:04:38.880
this is where we get to the functional part of functional architecture we can
00:04:43.990
model these functions nicely in Ruby as functional objects let's take a look at one now so for exit our example today
00:04:50.889
we're going to be making an import products class say we're building some kind of online store we use something
00:04:57.370
like this to populate our M product database from some third party feed of products and even in this clewd right
00:05:04.120
here we see the first quality of a functional object usually we can name them by word and then it has a call
00:05:11.979
method just like Ruby's own language level procs occasionally we might want a few more methods at most of the time
00:05:17.949
call it enough that call method accepts an input goes to work on it and return
00:05:25.539
some output now during the lifetime of that method it shouldn't mutate the state of the object and it shouldn't
00:05:31.360
mutate the input data so this is one of our big departures from a classical object-oriented design approach our
00:05:38.289
functional objects separate data from behavior let me keep that data anywhere
00:05:44.320
in their own state before we go any further let's actually take a quick look
00:05:49.539
at what this method will actually need to do the first thing it will do is get
00:05:54.669
a list of product records by downloading that feed and then it will work with a products repository and we'll loop
00:06:01.449
through to the products and create a record for each one in our own database now is it pretty clear and simple method
00:06:07.210
to read and that's because it delegates a lot of its work to some dependencies these are what allow us to break down
00:06:13.720
our application into smaller more useable objects here those dependencies
00:06:18.849
again we have download feed and we have a products repository and from here we
00:06:25.360
can see the next trait of a functional object those dependencies are passed in by the initialized method and then we
00:06:31.840
capture them in the object state and once these are set they never need to change and what you're seeing here
00:06:37.360
really is constructed appendixes it's one of those classical object-oriented design techniques and it works great with these functional
00:06:43.310
objects so the end result is that we can initialize this object just once and call it many times over and once it's
00:06:50.960
constructed if you then go on any passed around to become the dependency of other objects too now you might be thinking
00:06:57.860
what we've seen so far is really just one of those service objects that we occasionally sprinkle around our apps
00:07:03.740
where we see hotspots of complexity it and you'd be right this is one of those things but what I'm proposing is that we
00:07:10.730
use this approach to build out the entirety of our applications functionality because we want that
00:07:17.120
comprehensive design approach so all of that crud that we used to building well they can be functional objects too so
00:07:26.360
that's how we take care of the behavior side of things what about data how do we
00:07:31.430
handle that we can do that courtesy of types and this is ruby of course so they're not going to be the capital T
00:07:37.910
types that we might expect another functional programming languages instead what I'm really talking about is
00:07:42.980
modeling these as value objects what is the value object it's just something
00:07:48.200
that holds a particular structure of data that's unique to our business domain and then once we have these
00:07:53.690
objects created we should treat them as immutable once they're initialized their state should never changed to and of
00:08:00.260
course we can add behavior to these objects in classical object owners style with extra methods working with the
00:08:06.140
values we already have and the nice thing about these being simple value objects is that we can then easily pass
00:08:12.560
them around all of our system and not have to worry about unexpected mutations or any sort of behavioral side effects
00:08:18.440
along the way and in this way the value objects become first-class objects
00:08:24.020
within our system all about functional objects can depend upon and work with these structures so in a ruby app built
00:08:32.840
with this style objects tend to break down into these two different things values and functions our values hold
00:08:40.730
data and those functions operate on the data our values are inert they're
00:08:47.300
passive but the functions they're active they go to work on those values and if the
00:08:53.720
values are the content in our system the functions form the pipeline through which the content flows in order for us
00:09:00.860
to achieve some kind of outcome so that's the breakdown values work out to
00:09:09.470
be pretty typical of the dieted code but let's take a closer look at those functions if we built an app around them
00:09:15.530
how does that design approach measure up well I think first thing we should acknowledge that with Ruby being
00:09:21.920
grounded in the object-oriented world and with just using objects to model our functions we should acknowledge that
00:09:27.800
what we're doing here is really more a blend of functional programming and object-oriented programming so with this in mind let's see how we measure up to
00:09:34.490
some of those long-standing object-oriented design principles and I did mention solid before so let's see
00:09:41.210
how that plays out here here we have those five familiar kind of dense little
00:09:46.730
principles there coined there from Robert Martin and they're all concerning class design and together they can
00:09:53.300
actually work as a decent indicator of what is well-designed object-oriented code so we'll step through them now we
00:10:00.320
start with a single responsibility principle and this one I'm sure we're all familiar with it says that a class should only have one reason to change
00:10:06.500
well how that our example here it's functional so it's named after a single verb it's got a single responsibility
00:10:12.560
running the import for our products so there's no room really for anything else there if you want to add other behavior
00:10:19.190
that goes somewhere else so I think we're off to a good start we'll give us all the tea the next one the open closed
00:10:26.420
principle says that incidence should be open for extension closed for
00:10:32.630
modification or in other words when we're building a system and you want to introduce new behavior what we should do
00:10:40.220
is rather than modifying the old objects we should create a new objects that work with the ones we already have so this
00:10:47.990
plays nicely with our single purpose functions let's say for example that we want to send an email notification at
00:10:53.300
the end of our import well given that our existing import products function is closed for modification
00:10:59.450
we can extend its behavior by writing a new standard import notification object and then wrapping them both in a
00:11:06.410
higher-level coordinating object that runs the input first and then sends a notification and the beautiful thing
00:11:12.530
about this approach is that the more of our code we leave untouched the more confident we can be that our system will
00:11:18.680
continue to run bug free even as we go and introduce new changes so that's
00:11:24.500
another tick and now we come to the list of substitution principle and this one
00:11:30.260
is really specifically about sub plotting and ensuring that a subclasses interface doesn't break the
00:11:35.900
compatibility with its parent interface and since we mostly rely on competition we don't subclass much at all I'm just
00:11:42.890
going to chalk this one up as an easy win I'll set those those base lines for
00:11:48.380
myself here so from now to the interface segregation principle and this one says
00:11:55.310
that many client specific interfaces are better than one general purpose interface or in other words when you
00:12:02.510
depend on an object and it has interfaces for many different users you wind up being affected by changes to
00:12:09.470
that object forced upon it by those other users well in practice let's see
00:12:14.900
how this plays out we have our import products function we've been working with and it has that download feed
00:12:20.090
dependency where it gets the product information from a remote feed source and this object at the bottom here has
00:12:28.160
effectively been working as an incoming product source but what if we wanted to go and add a different way of getting
00:12:34.580
product information say by allowing users to upload a feed file directly well since that is also about incoming
00:12:41.780
products should we go on add that extra behavior right down to our existing objects or we could but that would
00:12:47.990
violate this principle because it returning the object into a bigger general-purpose interface and that means
00:12:54.020
it's likely going to change for different reasons over time and upset the stability of our app so instead
00:12:59.990
because you've designed our objects to work really easily with different dependencies is much easier and much
00:13:05.180
more natural to model this as a separate object with a new client specific interface purely for the purpose of
00:13:11.300
handling dublin's and this means that other objects can work with it as required so
00:13:16.399
nothing should become unexpectedly unsettled by changes to either of these
00:13:21.449
dependencies so for ticks down one to go we've got the dependency inversion
00:13:27.089
principle and in some states that one should depend upon abstractions and not
00:13:32.160
concretion or in other words we should care more about interface rather than
00:13:37.680
implementation and this is another place where our functional objects really shine because they're re-entered around
00:13:44.250
dependency injection all those things do come in as abstract objects just like
00:13:50.040
this our import products function doesn't know the concrete implementation details of that downloader just its
00:13:56.550
interface just that it responds to call and that is except the feed object this is really Ruby's duck typing in a
00:14:02.910
nutshell because it gives us the flexibility to adjust the implementation details of this object whenever we need
00:14:09.600
or even replace it entirely and as long as we retain that interface everything
00:14:14.670
stays good so how did we do well it's looking like we're solid and what this
00:14:23.309
shows is that by following a functional approach we've actually created better
00:14:28.759
object-oriented code for ourselves and we've done this with a blindingly simple
00:14:33.930
approach really to our design model our behavior this functions I mean we
00:14:40.259
satisfy those principles so easily you just have to think about why they were there in the first place and I think
00:14:46.740
it's because it's so easy in classic object-oriented design to get off to what few like a good start and then go
00:14:53.759
down the wrong path and wound up with something this Vaid I'm specified hard to reason about or
00:14:59.370
just really complicated so we need these principles to try and keep us on track
00:15:04.490
whereas with our functions they're dead simple and they take care of so many of those design considerations for us and I
00:15:13.470
think this approach is confirmed by how we would test these as well let's take a quick look at that we start by recalling
00:15:21.000
those two dependencies who are using download feed and products repository and then we set them
00:15:27.110
up as mocks or test doubles then we can create our object under test the import
00:15:33.380
products object by passing those doubles to the constructor then create a real feed value for our input and then return
00:15:42.230
fixture data from a local file whenever our fake download object is called with the feed and then finally we get to our
00:15:48.740
test so we can call our importer and assert that our repository has been asked to create a record for each of the
00:15:54.200
products in that fixture file and that's it we could use these mocks so easily
00:16:00.500
because our class was designed around working with injected dependencies so
00:16:05.540
instead of having to interact with these two different external systems this remote HTTP datasource and local
00:16:12.649
database instead we could simulate their behavior focus on our one function under test and get the test done quickly in
00:16:19.490
real isolation and with a minimum of fuss I think there's been a strong theme
00:16:26.450
so far it's been about making our dependencies clear and I think this is
00:16:33.620
because it's one of the best things that we can do to enable well-designed code
00:16:39.339
making our defensive dependencies clear means that we can consider the stable dependencies principle as we go about
00:16:46.190
and build our apps and this one says that a stable object an object's
00:16:51.529
dependencies should be more stable than it is what does this actually mean what the state will mean here or a stable
00:16:57.649
object roughly means hard to change and an unstable one is one that's easier to change and every application will need
00:17:04.459
its share of unstable objects because applications do need to change but we want to avoid the situation where the
00:17:11.059
objects that we need to change often are the ones that have many users within our system so what we can do then is take
00:17:17.839
our dependencies and arrange them according to this principle and make sure the lines flow in the right direction from unstable to stable
00:17:27.530
and we can take this a step further once we start thinking out about our dependencies in this way we can extend
00:17:34.550
this thinking to our app as a whole and consider it as a graph of objects with the classes or objects as the nodes and
00:17:40.880
the dependency relationships at the edges and historically the way we built
00:17:46.790
our ruby apps has been really class focused that we consider those classes the nodes to be the primary determinants
00:17:52.430
of what is a well-designed app but I suggest we open things up a bit and take
00:17:58.520
a hard look at the edges in our graph those dependency relationships if we find the edges being arranged like this
00:18:04.190
so our application looks like a big directed acyclic graph this is a good
00:18:09.410
sign that this app is going to be easier to change whereas on the other hand if our graphs had edges flowing in the
00:18:16.400
wrong direction or becoming tangled or even becoming cyclic then it's a sign we could be in trouble that's an app that's
00:18:22.700
going to be more resistant to change and that's really why we have all these printables in the first place they're
00:18:28.670
there to help us achieve apps that are easier to change and well it seems like
00:18:35.090
a functional approach to design gives us this and it does so in a way that's easy
00:18:40.430
to follow based on that widespread use of functional objects and clear composition of dependencies and it's a
00:18:47.480
pretty neat trick I'd say but I don't think it's a tree not a party tree because it doesn't fall
00:18:53.330
down under pressure this is an approach we like so much at ice lab where our work that is now our preferred way to
00:18:59.240
build ruby apps and over the last two years we've built more than 10 apps like
00:19:04.640
this across different domains and with different levels of complexity and I can tell you this it works really well and
00:19:11.230
from this simple reorientation around functions we've started to see a new
00:19:16.250
high level architecture start to emerge because when we have many small single
00:19:22.970
responsibility objects well at that point we need to take time to devise a sensible and consistent approach to
00:19:29.240
naming them and organizing them and that leads to an emergent modularization of
00:19:35.420
code within our system as we see those modules emerge we can start to take note
00:19:41.210
of their boundaries and from this we can start to see you distinct subsystems
00:19:47.690
become more visible in our apps how did this actually play out well we start
00:19:54.200
with that graph of individual objects like we've been looking at and after a while we note some of them are clustered together because they all work towards a
00:20:01.190
shared high level goal so we can formalize that and turn it into a
00:20:06.230
distinct subsystem and as we go other subsystems start to emerge as we
00:20:11.539
develop the features of our app these are the things that make up our applications core behaviors and because
00:20:18.289
we've started paying attention to boundaries we can also take note of the applications own outer boundaries as
00:20:24.320
well so rather than being deeply tired into the app as a whole systems like the
00:20:30.559
HTTP interface the persistence layer and integrations with external services well
00:20:37.039
they can be all carved off and placed at the outer edges of our app and formalize with a clear public API and clear and
00:20:44.360
obvious points of integration and this arrangement this is what makes changes
00:20:49.640
to our app just as easy at the very high level as they should be down at the individual object by object level if all
00:20:58.909
of this sounds attractive to you and it's something you want to give a try well you don't have to worry about going
00:21:05.210
out on your own and forging your own path to this because we've seen a whole Ruby ecosystem that's grown up around
00:21:11.840
this approach we have Ramar be a persistence toolkit designed from the
00:21:17.419
ground up to work with a separate layer from your business logic and then we
00:21:23.419
have the drive-e project which is the collection of gems built to enable specifically this design I've been
00:21:29.179
looking at today driver gives us things like type definitions data validation
00:21:35.270
view rendering all models of functional objects it gives us the ability to
00:21:41.330
consistently model both in success and failure results of our functions which lets us compose them in interesting ways
00:21:47.980
and on top of all of this we get nice pattern matching support so we can elevate failure handling through their
00:21:53.450
first class concept within our system and we also get support for building our own value
00:21:59.190
objects with strict data attribute types so it can be confident about what they'll hold now all of those things are
00:22:06.570
worthy of their own talks but I just want to draw attention to one gem here drive system this is built specifically
00:22:12.510
to help us create acts centered around functional objects and what it does is
00:22:17.880
offer us a central container through which we can access all of those objects in our system that container populate
00:22:26.010
itself based on some simple convention that starts by scanning our source files an n for each file registers a matching
00:22:33.480
container identifier and then when we resolve that identifier we get a pre
00:22:39.060
initialized instance of that object ready for us to use with all of those dependencies automatically provided so
00:22:46.050
if you're looking at our examples before and wondering well how do I get everything into the objects this is something that will let you do it easily
00:22:52.410
and it let us do this by giving us this simple mixing that we can use in our
00:22:58.080
class files where we specify our dependencies by their container identifier so instead of having to
00:23:04.260
manually build that constructor and set the instance variables like we just did before we can now just declare our
00:23:09.390
dependencies upfront and the rest is done for us and with all that in place
00:23:14.510
we can now make an instance of our object directly without supplying any arguments at all that initializer and
00:23:22.010
again when we do this all those default dependencies get provided from the container now if you think about testing
00:23:30.720
this opens up to new possibilities for us because we can now choose which of the dependencies we want to leave as the
00:23:36.270
default and which we want to replace with something like a test double so instead of that arrangement like we've
00:23:42.420
had before where we had to provide a double for every single one of the dependencies what we can do now is we
00:23:48.690
could choose not to provide one of them just like here we can choose to skip passing our products repository as a
00:23:53.790
test double so the resulting object here will use just one double and then it
00:23:59.010
will use the real system object for the repository so if we went to test this object it would actually write all the
00:24:05.280
records to our test database and then we could go in a search for their presence afterwards now this is a
00:24:11.039
much less pure approach to testing but in certain situations it may be much
00:24:16.169
more practical and it's great that we have the choice to do one or the other so that was it pretty much a functional
00:24:24.059
architecture for Ruby apps how did we do it well we really created a hybrid of
00:24:30.690
functional and object-oriented programming based on some really simple rules we separate data and behavior and
00:24:37.200
then we provide that behavior as functional objects but we also drawn the best bits of object-oriented programming
00:24:43.679
like dependency injection and object composition and by doing this we found
00:24:48.869
an approach that's easy to follow and makes for apps that are easy to change
00:24:54.409
and I think this makes a functional architecture a real practical choice for any rubyist out there and thanks to
00:25:02.279
organizations like ROM are being drive ADA's already support in our community for following this approach and also by
00:25:08.549
choosing to stay with Ruby and take an approach like this rather than trying to follow it with some other programming
00:25:13.799
languages you get to continue to leverage all of your existing knowledge of our community our ecosystem and our
00:25:20.159
tools so given all that I think functional architecture is really worth
00:25:25.769
the try I think you can help you build better things because while solid might
00:25:31.440
be asking him for a collection of design principles I think it's a feeling too
00:25:36.690
and I know that since I've been working in this way I've been shipping apps that feel 100 percent solid absolute I'm
00:25:43.049
confident will work the way they shed an absolute I know I can go back and easily change later now I feel that taking this
00:25:49.649
journey has made me a better developer but most importantly it made me a happier developer I'd love for you to
00:25:55.769
join me and if you would like to join me now's a good time to check out this
00:26:01.679
repository because we're just getting started in building a best practice example app that follows all these
00:26:06.869
principles so it's fresh as of this week if you follow along you get to see all the work that we do to make it happen
00:26:13.460
and with that thanks very much for listening and I hope you give this a pitcher chance thank you very much
00:26:28.660
all right so do we have any questions for mr. timidly anyone yeah
00:26:46.510
hello first thank you for the talk it is really good so my question is how about
00:26:56.130
how do you develop this kind of component I mean for example did you
00:27:03.130
first draw some kind of diagrams before starting to create the objects like
00:27:09.370
import products download speeds and the repositories and you know in which order
00:27:15.460
do you go from bottom up like the protector ease first or you start top-down and putting in tests suppose
00:27:21.640
first things things like that I would like to know about the process which you
00:27:26.860
used to design and develop thank you thanks for the question I guess a top
00:27:33.040
down or bottom approach bottom-up approach is there for you to take depending I guess on your personal style
00:27:39.160
and how much you know about the requirements up front so if you were sort of doing exploratory development or
00:27:45.340
your requirements for fuzzy definitely you'd start with a top-down approach you'd make your highest level thing and
00:27:51.610
then you start to explore what it has to do and as you notice studying that objects starting to do too much that's
00:27:57.910
when you break it apart and build extra objects as dependencies and because we
00:28:03.010
we work with that auto-injector mix in is the way we work that's a really low
00:28:08.140
friction thing to do there's not much effort to make a new file and then check and identify for that file in there's a
00:28:13.330
dependency so that's some that's one way to take it or on the other hand if you really knew exactly what you wanted to
00:28:19.030
build you could start with yeah the solid underpinnings and then go upwards so either options there it just depends
00:28:26.320
on the situation of the app that you're developing I think can I have one more
00:28:33.070
question okay thank you so sometimes
00:28:39.400
when when going this way do you have the feeling that when you want to implement some features you have to change you
00:28:46.030
have to make change to the several files instead of one file for for example if I want to like add something to import
00:28:54.700
products like it needs a new behavior like aggregating data from repository but the repository doesn't
00:29:01.670
have that functionality yet and in the end adding one thing requires changing
00:29:07.820
in multiple files yeah do you have that clearly yeah this is something that
00:29:13.160
definitely happens but I think it's an advantage because think about the opposite if you had all of your behavior
00:29:20.030
clustered into one class and that means that much more of your system is all
00:29:26.030
using that one class and then it means that any change you make there is going to have ripple effects ones that you may
00:29:33.080
not even expect whereas with smaller responsibilities broken apart into a larger number of
00:29:40.490
individual files you can see much more clearly because of the dependency relationships what is using what and you
00:29:47.060
know what each one should be doing specifically because it has that single responsibility and in some some objects
00:29:54.290
that do have sort of wider api's like repositories where you might want to add lots of methods for different ways to
00:29:59.840
access your data because those methods are clearly named by you the developer you've explicitly made an API you should
00:30:06.350
be much more confident about where that's being used and you can make that change it is just a change in mindset that whenever you work on things you
00:30:13.070
jump across a few different files rather than the smaller number of larger bulkier files
00:30:21.730
there anyone else
00:30:27.870
no I'll write up there oh yes oh okay could you approach hold microphone
00:30:44.710
okay hello so my question is if I want
00:30:50.060
to migrate an existing application happen running production application so
00:30:55.250
what would put a complicity to move it from Opie to functional programming APIs
00:31:03.040
that is a tricky question I guess dealing with any legacy application comes with a whole bunch of nuance but I
00:31:10.730
think this is something you can do as long as you're willing to accept that you're going to live in this world where there are sort of two different
00:31:16.790
approaches to the design and I guess commit to the new approach whenever you
00:31:22.820
add new functionality I mean you can certainly use drive system within rails for instance as a rail pipe forward what
00:31:30.530
it would mean though within a rails app for example is that you're just going against the grain a bit so that may cause you a bit of friction but on the
00:31:38.690
other hand these are all making a web app with with dry web and any other web front-end these things are alright
00:31:44.810
compatible so you can put them together in various ways you could even choose to carve out the new stuff and have it in a
00:31:51.650
sort of separate recommendable app alongside but that's quite an extreme
00:31:56.780
approach so I think a more sensitive approach would probably be just to start
00:32:02.930
thinking about as you build new functionality think about how it can be modeled as verbs and put them put those
00:32:09.440
things those classes in your rails application wherever it fits and start working with those and you can hired for
00:32:15.620
instance active record queries behind query objects you could also hired
00:32:21.070
operations that write to the database behind their own objects and then your active record models for instance then
00:32:26.300
become a much lower level persistence related detail rather than something that you use as the primary API of your
00:32:32.330
app so that kind of mindset you can apply to any tools that you're using whether or not you use these gems or
00:32:37.700
something else so that's how I think you'd do it ok cool do we have more questions yeah
00:32:48.520
thanks for the talk to him and do you think that ruby would benefit from
00:32:54.430
adopting some of the patterns you were showing for example value objects could
00:32:59.480
be part of the Ruby core basically and people would probably pick pick up this
00:33:04.640
pattern way easier you know this thinking of like okay I have an immutable read-only value object if it
00:33:12.170
was in Ruby core directly what do you think should that kind of stuff be in Ruby or not because that's what my talk is about I'm happy to wait and find out
00:33:21.500
this afternoon no I think masters point about compatibility is a really good one
00:33:27.020
there um we can do these things in Ruby by convention an object can be immutable
00:33:32.480
within our system if we choose not to mutate it and if we choose not to create writers sure I think some some
00:33:41.320
facilities around first-class functions would help so that some of those
00:33:46.490
functional objects can feel a little bit more better situated within the language but you know we work with the tools we
00:33:53.330
have and you know we've probably all been writing with Ruby for a long time
00:33:58.730
and we're here because we still enjoy it as a language for all of its good features and all of its kind of quirks
00:34:04.880
and I think the fact that lets us model systems along these lines is great and
00:34:10.690
we can start to develop the same instincts for how to break things down that that other function languages give
00:34:15.919
us and I think the biggest thing that helped me in doing this was really
00:34:21.909
approaching this completely apart from the tools I was used to using and starting fresh on some new project so I
00:34:28.580
couldn't fall back to my old habits or those old shortcuts and that was what helps submit the change in mindset and
00:34:35.450
that can still all be done within Ruby
00:34:42.560
so the dry stack compact consists of a lot of different small libraries would
00:34:48.899
you agree that it is designed and it is meant for more advanced programmers I
00:34:53.909
feel that when beginners come and try to learn something the in difficult for them to decide what they actually want
00:35:00.840
they usually want to have a set of tools that that that is like you know like
00:35:06.270
pack together for them so I'm wondering if you think that this is meant for advanced programmers or do you think
00:35:11.550
that maybe the community will come up with some like no just the default stack that you only modified if you know what
00:35:17.220
you're doing yeah you're right in at the gems are fairly low on opinion they're meant to be flexible and they're meant
00:35:23.010
to integrate into many different situations which is why perhaps they don't guide you as much as other tools
00:35:28.580
but I would say that new developers can become productive with this we saw that at Ice lab we had someone who came on
00:35:36.930
board as a junior developer he done some online Rails courses and he was pretty productively working with this because
00:35:42.570
it really is a much simpler concept that is core you create objects you compose
00:35:47.580
them and that's how you get larger pieces of functionality it's actually a smaller number of things to learn and as
00:35:54.360
long as they're guided by some higher-level organizing structure with an app so if they're working with
00:36:00.180
someone else you can take care of that by having conventions within your app that you've established and I think as
00:36:05.730
part of doing all of this you get better at actually becoming a programmer so instead of being a programmer for one
00:36:10.770
framework for instance you just get better at modeling and solving problems in general and I think that's a great
00:36:15.990
thing for a junior developer or a less experienced developer to learn because they're going to be things that will
00:36:21.330
help them for the rest of their programming career even if these tools they'd away the ideas behind them are
00:36:26.490
enduring
00:36:33.140
anyone else oh sorry I'm interested by
00:36:41.700
your statement that the various dry dot RB gems are intended as atomic because
00:36:48.330
when I've looked at it before I feel almost like you're trying to build a functional DSL using Ruby as an
00:36:55.440
interpreter and while that isn't to my taste I think it's a reasonable project and so I guess how do you visualize
00:37:05.070
people just using individual piece bits and pieces of the drop in because it seems like a kind of coherent system
00:37:10.830
that you either buy into or don't buy into to me it's true that way you sort
00:37:16.110
of have built these to work in harmony magic collection because they share similar philosophy across all the gems
00:37:21.840
but a lot of them are intended your entire idea is to make one each something that solves an individual
00:37:27.720
problem so I didn't mention it here but a one of the ones I've seen the biggest uptake is dry validation which is a
00:37:33.990
standalone validation library and strict rigorous data validation is something
00:37:39.150
that everyone needs in their projects and dry validation is really just about creating schema objects that you can
00:37:44.730
call anywhere in your application so it doesn't really have any requirements beyond that your application can take
00:37:50.580
any shape people are using it in rails apps people using it in apps that are the full collection of drive idioms and
00:37:57.119
because it was done as a standalone thing it can find usefulness in a
00:38:02.640
broader context now some of the dryer B gems are a little bit more specific for following an architecture like drive
00:38:10.590
system if you're not going to want to build an app with a container to vend your object there's not really much
00:38:15.690
point in using drive system but that's the whole idea because we didn't bundle that into everything and make them tied
00:38:21.420
together you can just pick and choose what you'd like to use so the best ones that are that we've seen with standalone
00:38:27.240
usage dry validation and dry types and dry struct because everyone has a need to validate data and model data and and
00:38:36.600
treat data with rigor and that's something that can fit with any application
00:38:44.790
okay I think that's all the time we have for questions let's give him another round of applause again thanks very much