00:00:06.820
afternoon everybody yes I'm Tim
00:00:13.330
and I did travel here from Canberra as my first time in kale I've had a really
00:00:27.820
I hope run a company called ice lab where mostly based in Australia we're a design studio that's the team right here
00:00:34.390
there's 16 of us and about 8 of us are writing Ruby day today and I just want
00:00:40.090
to say thanks to them because they've given me a lot of time to help put together some of the things I'll be sharing with you today also need to say
00:00:47.050
thank you to these people my family I consider them my number one sponsors um they've also given me a ton of support
00:00:54.539
now in the Ruby community you'll find me in places like these I'm a core team member on the dryer B and ROM RB
00:01:02.140
projects now with all that done before we dive into our topic today I want to
00:01:07.840
talk a little bit about classical art he's a painting for you this one's from
00:01:13.200
1893 and that's a pretty harrowing scene right here's the title program is at
00:01:20.200
work maintaining Ruby on Rails application oil-on-canvas this is actually from a very amusing
00:01:26.350
tumblr blog called classic programmer paintings and for someone who had worked
00:01:31.510
in Ruby for a long time this one hit really close to home I mean just look at
00:01:37.750
those eyes she has seen some things
00:01:43.310
and I think I think this hit me so hard because a lot of the time when we work
00:01:50.759
with the language aim towards programmer happiness our day to day life kind of feels the opposite and maintaining big
00:01:57.689
apps once apps get to a certain size or a certain age our efforts on them give
00:02:05.340
us diminishing returns everything feels tightly connected changes in one place
00:02:11.009
have unexpected ramifications in another every change I go to make on apps like
00:02:17.130
these takes longer than the one before now starting fresh on new apps may be a
00:02:22.350
reprieve from time to time but it's short-lived and repeat this for long enough then it's enough to make you feel
00:02:27.420
like it's time to change careers or maybe change programming languages as if that'll solve all your problems well it
00:02:35.100
turns out a lot of thinking has gone into this kind of issue and in fact martin fowler's wrapped it up quite
00:02:40.530
tidally in what he calls his design stamina hypothesis and this lets us
00:02:45.600
chart our work effectiveness over time so that pressing scene from before you
00:02:52.230
can sum it up in a line like this at the beginning we feel like we're making good progress but then over time our efforts
00:02:58.530
really flattened out and we become less effective and this is what happens when we build an app and find ourselves in
00:03:05.010
this place where we haven't put enough thought into its design and yes the rails way is not a remedy for this in
00:03:10.500
fact many could argue it focuses a lot on that initial spike but not enough for
00:03:16.590
you in the long run and this line here it's the one of sadness it's with the tired frustrated developer and for me
00:03:23.850
it's a line I and I sat on for a really long time whereas over here we have this
00:03:28.920
tantalizing red lion this lion you see it takes a bit of time to ramp up but then it shows work on an app continuing
00:03:35.430
at a nice steady clip at a sustainable pace and this is the line of good design it's a line that shows what can happen
00:03:42.090
when we make the decisions up front that'll allow us to more clearly arrange all the elements that go into our app
00:03:48.860
and this one is the line of happiness so when we consider these two lines and
00:03:54.650
where they intersect we see this design payoff moment or as they say the life
00:04:00.740
comes at you fast moment this pretty much is the point in time after which
00:04:05.840
you wish you'd gone back and made some different design choices and what I want to show you today is is one way to move
00:04:12.620
from the sad line up there to the happy line at least a way that's worked for me now in getting to this point I had tried
00:04:21.290
many times over to make this jump myself and what I'd always look to are these objects oriented design principles these
00:04:29.330
are the things that should guide us as rubyists right I know I'd go and watch
00:04:34.430
the conference talks about these sorts of principles and I'd see all that nicely arranged code and I'd say to
00:04:40.160
myself yes this is how I'm gonna write my applications but then I go back to
00:04:46.040
those apps and I really struggle to apply those principles to my actual living code so I found myself in this
00:04:54.590
gap between my desires and my realities between the way I wanted to write code
00:05:01.610
and the way my tools were seem to be encouraging me to write my code and I couldn't find a way to bridge it and
00:05:07.850
really all those principles just seem to be taunting me more than anything else so as you might guess I did find a way
00:05:16.280
out and and it happened by following a different kind of approach so everybody stand back is what I want to tell you
00:05:22.370
today here we go in a nutshell functional programming will save us here
00:05:30.200
we get to the actual title of my talk I'm not going to suggest your jump ship and this is the Ruby conference after all so I want to talk to you about
00:05:36.620
real-world functional ribbon and since we're here in Malaysia I thought maybe this is a better title functional Ruby
00:05:43.400
ken and I'll be showing you how we can take
00:05:50.560
a functional approach to working with Ruby and how we can actually go out and apply an approach like this in our real
00:05:56.620
working apps today so just art with well what a functional approach at all well
00:06:02.469
clearly it's because we're behind the times and we've got a catch-up me to stay on trend functional programming is
00:06:08.710
hot right now all right like and I've learned a bit about hot while I'm here in Malaysia now when it
00:06:15.099
comes to this though I think functional programming is actually hot for a good reason it gives us clarity and understanding
00:06:20.229
how something is pieced together it can let us easily understand the flow of data from place to place and it gives us
00:06:26.710
a manageable way to build big things out of smaller pieces so why shouldn't we
00:06:32.379
had that in Ruby - because it's a flexible language after all and some elements aren't too removed from
00:06:38.110
functional concepts so I think the first step we need to take towards a
00:06:43.449
functional approach in Ruby is a change in mindset it's about viewing your app as a series of transformations data goes
00:06:51.129
into our app in this many cases the data being a HTTP request and then it gets worked on over a number of steps and
00:06:58.139
transformed along the way until at the other end we get our HTML so if we think
00:07:04.330
about an app modeled as a series of transformations it's really an app modeled as a series of functions and
00:07:10.199
this is where we get to the functional part of functional review we can model these nicely as functional objects now I
00:07:17.949
want to take you through a tour of a functional object right now and here we go we're going to make a start today
00:07:23.860
will building a an import products class so if we were making some kind of online
00:07:28.960
store we'd use a class like this to populate our own product database from some feed of third-party product
00:07:35.379
information and even in the code we see here right now this is the first quality
00:07:40.629
of a functional object it can usually be named by a verb it's a verb as we saw in the NRP talk because it represents some
00:07:47.139
action we want to take with regard to our products and next we can give it a call method
00:07:53.560
just like Ruby's own language level function equivalents procs and Landers now occasionally we might want an object
00:08:00.220
with a bigger API than this but a lot of the time call is all we need and then we
00:08:06.460
want this call method to accept an input do some work and then return an output
00:08:11.910
now over the course of that method call that shouldn't mutate the object state and it shouldn't be take that input data
00:08:17.889
either and this is one of the big departures we make from a classical object-oriented approach because here
00:08:25.000
our functional objects separate data from behavior they don't keep that data
00:08:30.340
input data anywhere in their own State in fact we reserve the state there's something a bit more interesting for the
00:08:36.789
objects own dependencies or configuration things that will never need to change and effectively this
00:08:42.729
makes our functional objects immutable and this is a big part of the design approach we're taking because when we
00:08:48.580
make our objects immutable we take away the whole dimension of time from when it comes to understanding our objects we
00:08:55.660
know that once they have a certain state that's the state they'll keep always so we can pass that around pass those
00:09:01.270
objects anywhere around their application and now remain the same and this goes a long way to improving the
00:09:07.270
overall simplicity of our apps now before we go any further let's take a quick look at what this method is
00:09:12.850
actually going to be doing so we'll start by getting a list of all the product information records by
00:09:19.240
downloading a feed and then we'll loop over them and work with a product repository to create copies of those
00:09:25.930
products in our own database now this is a pretty clear and simple method to read isn't it and that's because it's
00:09:32.649
delegating a lot of its work to some dependencies and it's an approach like this which allows us to break our
00:09:38.920
objects down into smaller more useable and easier to understand units so here
00:09:44.260
are those dependencies again the download feed object and a product repository and here those dependencies can go and
00:09:51.709
show the next trait of a functional object they get passed in via the initialized method and then we capture
00:09:58.940
them in the object state and once they're said they'll never need to change and what we're seeing here in
00:10:05.269
fact is constructed a pendency injection which is a classical object-oriented technique that actually works to great
00:10:11.480
effect with our functional objects and the result of all this is that we can
00:10:17.510
now create our functional object just once passing in those dependencies and then we can use it many times over with
00:10:24.800
many different inputs and in varying contexts and once this object is constructed like this it can also be
00:10:31.339
passed around itself and go on to be the dependency of other objects in turn now
00:10:37.000
looking at this you might be thinking well this is just one of the service objects that were that we know we should
00:10:42.380
use in Ruby apps these days when we feel like we have more complex behaviors to model and yes this is exactly right but
00:10:49.550
what I'm proposing here is that we use this approach to build out the entirety of our applications functionality
00:10:55.390
because we want to set a comprehensive and consistent design approach one that's easier for us to follow as we go
00:11:02.810
and build our app so all of the crud objects and actions that we used to building well they can be functional
00:11:08.449
objects too and organized like this so that they're grouped by the context in
00:11:14.449
fact every single feature or piece of behavior in our apps can now be expressed as a functional object and the
00:11:20.779
more complex they are the more likely we'll want to break them bake break their behavior apart across multiple
00:11:26.149
objects which we can then bring back together and coordinate at a high level just like we have done with our example
00:11:31.819
here so that's how our functional objects take care of the behavior side of things
00:11:40.370
but how do we handle our data
00:11:49.209
but this we can turn the types and this is Ruby of course so these aren't really the capital T types that we might expect
00:11:56.470
to see in other functional programming languages instead I'm really talking about modeling our data as value objects
00:12:03.689
so a value object is just an object that holds a particular structure of data from our applications business domain
00:12:10.089
and just like our functions we treat these objects as immutable they get initialized with their data and from
00:12:15.639
that point on they should never change and of course we can add behavior to these objects in classical
00:12:20.980
object-oriented style by using extra methods that work with the valley's we already have now we saw before we're
00:12:28.899
making the verbs in our app these are the nouns we're looking at a product here and if we if we're used to working
00:12:34.929
with active record to provide the noun classes in our app well take note
00:12:40.569
because these are the complete opposite they are inactive and the nice thing about this is that we can now easily
00:12:46.179
pass them all around our application without having to worry about unexpected mutations or behavioral side effects
00:12:53.050
along the way and this allows the value objects to become first-class objects in
00:12:58.990
our system all of our functional objects can depend upon and work with these structures so in a ruby app built in
00:13:07.959
this style our objects tend to break down into these two categories values and functions the values hold data and
00:13:14.499
the functions operate on that data functions are active going to work on
00:13:21.549
inert passive values and if the values are the content in our system the
00:13:28.269
functions form the pipeline through which it flows in order for us to achieve some sort of outcome
00:13:34.220
so that's the functional design approach summed up we take these two elements
00:13:39.329
functions and data and model them both in Ruby as plain objects and we do use
00:13:45.870
objects because Ruby is still at heart an object-oriented language so we should acknowledge here that what we're really
00:13:51.060
doing is creating a blend a hybrid of functional and object-oriented programming styles but in doing this we
00:13:59.760
do escape many of the pitfalls that all of those object-oriented design principles were there to help us avoid
00:14:05.790
in the first place because if you look at them closely our functional objects already satisfy so
00:14:11.459
many of these principles out of the box they're already single responsibilities they are already open for extension that
00:14:19.050
closed for modification and they're dope from the ground up to prefer composition so our functional code ends up being
00:14:27.000
better object-oriented code too and we've done this with a blindingly simple approach and it doesn't leave us
00:14:33.480
wringing our hands at each point about which principles we need to conform to as we go and build an application and
00:14:41.630
this design approach is confirmed by the ease of testing as well so let's take our import products class and write a
00:14:48.449
unit test for it so we start by recalling these two dependencies we were using download feed objects and the
00:14:54.839
product repo and each of these represents an interaction with an external system either a third-party
00:15:00.810
remote URL or our own database and then
00:15:06.180
we take them and we set them up as test doubles or mock objects and then we can create our subject on
00:15:12.850
the test our import products object by creating the object and passing those doubles into the constructor then we
00:15:19.660
create a real feed value to act as our input and then we do one more thing we
00:15:25.389
set up our download feed object to return local fixture data whenever it's
00:15:31.509
called with our feed and with that setup done we can now call our importer and
00:15:37.180
then insert assert that our repository has been asked to create a record for each of the products in that fixture
00:15:42.939
file that's it and we can make this arrangement by working with this test
00:15:49.360
doubles so easily because we designed our class to act with those abstract
00:15:54.459
injected dependencies so instead of having to actually go and interact with those two different external systems the
00:16:01.329
third-party remote data feed as well as our own database or having to set up some sort of global stub for each of
00:16:07.389
those instead we could just simulate their behavior via these doubles pass them into our function and test it
00:16:13.509
quickly and in true isolation so there's been a strong theme so far it's been
00:16:20.410
about making our dependencies clear and I think this is because it's one of the best things we can do to enable
00:16:26.290
well-designed code once our dependencies are clear we can more easily recognize
00:16:32.050
that our app is really a graph of objects and we've seen this before with Alex's talk the classes all the objects
00:16:39.069
actors the nodes and those dependency relationships are the edges and if we take a hard look at those edges at those
00:16:45.699
dependency relationships we can get a sense for just how well I design their app is if those edges are all arranged
00:16:52.059
like this so our app looks like a big directed acyclic graph then it's a sign
00:16:57.129
that we're going to you know have a good time making change on the other hand if we had a graph where the arrows are all
00:17:04.240
flowing in different directions or even becoming cyclic then it's a sign we could be in trouble that's going to be something that's harder to change
00:17:10.760
and that's why we take the time to establish an approach upfront that'll help us better design our apps because
00:17:16.670
does these design approaches are there to make change easier and good design is
00:17:22.010
what gets us onto that happy upward sloping Lion of steady consistent feature delivery and it turns out that a
00:17:30.320
functional approach to design is what gives us all of this and it does so in a way that's really easy to follow based
00:17:35.750
around that widespread usage of functional objects and those clear composition of dependencies now I know
00:17:44.840
what you might be thinking right now this is just one weird trick and it might sound fine at a conference but
00:17:50.330
it'll never fly in the real world it's just too impractical you couldn't do this for a whole app well I am happy to
00:17:58.850
say that this is actually no weird trick and it really does hold up to real-world use it's an approach we experimented
00:18:05.480
with some years ago at ice lab and we liked it so much that it's now our preferred way to build ruby apps and
00:18:11.750
over the last two years we've shipped more than 10 apps built with this stack in this way across different domains and
00:18:18.440
with different levels of complexity and each of these apps was built by small teams just two or three people people
00:18:24.920
with varying levels of experience as review programmers and many of whom learnt this approach on the job and
00:18:30.350
still managed to get things done so this is definitely something that can work today and if it is sounding attractive
00:18:36.980
to you we don't need to worry about going out and forging your own path towards this kind of approach because we
00:18:42.530
now have a whole Ruby ecosystem that's grown up around this approach and I want
00:18:47.930
to introduce some of it to you now most of what I'll show you comes from the DRI RB project it's a project we founded
00:18:55.550
over two years ago now and we offer a collection of what we call next-generation ruby gems and we call
00:19:02.060
them this because yes they are informed by many lessons we've learned over the years building apps with Ruby but
00:19:07.190
they're also our real concerted attempt to nudge our ecosystem in a better
00:19:12.470
direction each gem solves a single problem and it can be used on its own but you can also
00:19:18.730
bring them all together to form a full web stack which is what we've done at ice lab and many of these gems are built
00:19:24.580
specifically to support and encourage the design approaches we've looked at so far today so let's take a look the first
00:19:31.360
gems I want to show you are the ones that help with dependency management now if you're looking at the code before and
00:19:36.640
wondering well how exactly would you go about doing this about initializing these functional objects at
00:19:42.370
the right place in the right time and then getting an orchestrating your that web of dependencies and making sure they're all available especially when
00:19:49.179
we're going to have more than hundreds of these things if we're building a full app in this way well we have some gems
00:19:55.390
to help with that we have dry system and dry Auto inject and the first step is to drop dry system into place and that it
00:20:02.230
offers a centralized container for accessing all of the functional objects in our app so when we boot an app that
00:20:10.330
works with dry system it populates can its container using a very simple approach it starts by scanning our files
00:20:16.510
like this and then for each file at a register of matching identifiers and it'll do this until we have an
00:20:23.290
identifier for every single functional object in our application and then with
00:20:28.299
all of that in place we can now hop over back to our file from perform our import products class and drop in this Auto
00:20:34.960
injection mix in which we use to straight up declare the dependencies
00:20:40.150
that this class wants to work with and we refer to them by their container identifiers and dropping this mix in
00:20:47.020
here takes care of all of the dependency related boilerplate that we had back in our original example so we don't need to
00:20:52.330
worry about an initializer instance variable assignment and attribute readers it's all taken care of for us
00:20:57.480
and then it will go on to do one more thing as well because now when you go
00:21:03.190
back to the container act and actually fetch that object we get back a pre-built instance with all the
00:21:09.160
dependencies resolved and provided automatically from our container so it's ready for us to use
00:21:15.500
so that's how dry system does its thing it gives us the container for accessing our objects and courtesy of the auto
00:21:21.860
injection mix in all of our dependency wiring gets taken care of for us and
00:21:27.159
with this in place it becomes really manageable to build an app that consists of hundreds of objects like these and it
00:21:34.190
also becomes really low friction to extract behavior and wrap them up in its own object whenever we notice things
00:21:40.789
becoming a bit too complex or when we notice that the need for some more reusability just one more thing on this
00:21:48.409
dome while the auto injection approaches helpful it doesn't mean we give up control because we can still choose to
00:21:55.309
manually instantiate our objects and manually pass in dependencies whenever we want and this is actually quite a
00:22:02.870
helpful approach for testing because we might now want to use a mix of dependencies with some being the system
00:22:08.480
defaults and some being our test doubles now that'll give us a less isolated test
00:22:13.520
them before but it might make certain kinds of testing much more practical so
00:22:18.650
could we have the choice all right next we come to result handling this is the other side of the functional object
00:22:24.500
story what do we do once we've called these and got some result well these objects can become much more flexible
00:22:30.470
and powerful if we make it so they all return the same kind of result object and for this we can turn to DRI monads
00:22:37.460
now these are another element from functional programming languages and we use them here simply to wrap up the
00:22:43.400
return values from our functional objects and we use it to signal whether their operations succeeded or failed now
00:22:50.900
without going any more into this as a subject of theory even just having this consistent result object allows us to
00:22:56.929
provide something like this this nice result matching API from dry matcher and this lets us just as easily act on both
00:23:04.309
the success and failure outcomes from our calls to our functional objects and
00:23:09.370
looking at this you can see we're improving the robustness of our apps by elevating failure handling to be a truly
00:23:15.409
first-class concept failure handing failures are handled in the very same way as successes and
00:23:21.010
matchup blocks like these won't even run unless you have all the cases covered
00:23:26.590
so those are some gems for powering out our functions but what about now values
00:23:35.090
our data the other half of functional application design but we have some gems to help you here too we can start by
00:23:41.330
looking at drive validation it helps us model our data validations with precision and safety and work with
00:23:47.720
any kind of input data and it's based around standalone validation schemas so
00:23:53.300
these can be tailored to suit each specific use case of our application and think we can also put them as close as
00:23:59.480
possible to the boundaries of our application and ensure only valid data makes it into our applications core and
00:24:06.700
then once we're in the core and we want to work with the important structures that we pass around between our
00:24:12.560
functional objects we have dry types and dry struct dry types helps us identify
00:24:19.420
name and reuse all the data types that exist inside our app and apply things
00:24:24.830
like coercion z' and constraints along the way and then dry struct helps us
00:24:30.920
define strictly typed value objects consisting of multiple attributes each with their own type definition now
00:24:38.300
working with types trucks like this means we can now be completely confident in the shape of the data that we receive
00:24:44.690
in our functional objects and we noticed very quickly if we encounter data along
00:24:49.730
the way that doesn't match our expectations all right so our building blocks are looking pretty strong right
00:24:55.580
now but if we're going to build a fully working web app we need to do a few more things view rendering for instance or
00:25:01.910
for this we have dry view and that helps us build our views as functional objects just like we've been doing so far today
00:25:07.940
so we get full support for auto-injector dependencies which means we can cleanly connect our views to the other parts of
00:25:15.080
the app that they need to work with in order to render themselves and we can then explicitly expose data to our
00:25:21.980
templates and we can also wrap that data up in custom view part classes for providing properly encapsulated reusable
00:25:29.570
and testable view logic and I really like working with dry view because so often the server end of view layer is
00:25:35.960
where a good design just falls apart get it out there but now we drive you we can extend our sound consistent design
00:25:42.490
approach all the way out to our views as well so if we can render some views how
00:25:47.650
do we get them to the user well obviously you'll need to take care of HTTP and routing concerns and for
00:25:53.140
this we have a very small gem dry web rotor and this integrates dry system and drive you with Jeremy Evans's wrote a
00:25:59.080
web framework and it makes it easy to do the few things that you'd want to do at the HTTP layer like rendering your views
00:26:05.710
and calling our functional objects and responding to their results and this
00:26:11.530
ends up being the only layer in our app where we ever have to deal with HTTP concerns which leads the core of our app
00:26:17.110
to focus on its own job and not be muddied up by having that HTTP live details leaked all the way in
00:26:23.040
try web browser also has project generator so you can run that and get started with a new app that has all
00:26:30.610
these gems working together now the one big thing that's missing still is database persistence and for that we can
00:26:38.140
turn to ROM RB it's a sister project of Dreyer beam and it shares all the same philosophies it's also designed the long
00:26:45.790
functional lines and it integrates really nicely into apps built with drive system as well and ROM gives us API is
00:26:52.090
to cleanly access every part of our database and it helps us embrace the database and put all of its features to
00:26:58.450
work for our application but then what it also does is help us hide away all
00:27:04.210
that persistence logic from the rest of our app because when we work with ROM we build up these repository classes just
00:27:10.870
look just like in our example before and these serve as the only interface to our persisted data and what they return are
00:27:18.040
properly typed value objects that are tailor-made to suit our applications business domain
00:27:25.580
so what have we looked at here well pretty much everything you need to build a fully working web app written in
00:27:32.550
functional ribbon and we satisfied each of these requirements with tools that encourage these good design choices
00:27:39.030
along the way and for me it was working like this with these tools that finally
00:27:46.050
made me feel like I jumped that gap I was finally building things that felt
00:27:51.270
solid from start to finish and I found myself finally being able to deliver
00:27:56.420
work at a much nicer steadier pace I'd finally hopped them to that Red Lion and
00:28:02.100
I found myself a happier developer again in fact it was really the moment working
00:28:07.950
with these tools that I rediscovered joy and Ruby after what felt like years of us of a long slog oh it - this ecosystem
00:28:14.370
of tools for making the approach this approach an easy one and a natural one
00:28:20.250
to take and I'm really excited right now because this idea of functional Ruby is
00:28:25.860
moving beyond just a small set of tools we're starting to see the beginning of what feels like a functional Ruby
00:28:32.130
movement and we can see this through a growing number of projects that are all gravitating around the same ideas we've
00:28:40.050
seen Dreyer being rama be today but there are more take trailblazer it
00:28:45.090
offers a higher level of business logic architecture for Ruby apps and it works with any web front-end as a project it's
00:28:50.730
been around for a long time but in their super no release they've adopted a real functional Ruby approach they offer
00:28:57.600
functional operation objects that offer some really advanced flow control behavior and these operations fully
00:29:03.750
support dependency auto injection and apps built around containers like dry system as well and then we have hanami
00:29:10.560
it's a modern integrated web map framework and they've made a big milestone as recently it's now hit 1.0
00:29:16.320
so it's ready for you to use and it's also oriented around single purpose stateless objects for all the different
00:29:22.020
components that you'd expect to see in a web app and there's already been some really
00:29:27.490
interesting thinking that's already started to happen towards her Nami is 2.0 evolution just a few weeks ago at
00:29:33.580
rails Club conference in Moscow Luke we D the lead developer shared how they'd like to take things in an even more
00:29:38.950
functional direction basing the framework entirely around functional objects and building up processing
00:29:44.380
pipelines for handling web requests so all of this makes me feel that the Ruby
00:29:49.990
community is ready for a change like this and all these groups hanami DRI be Trailblazer we're all working hard and
00:29:56.679
together to help make this happen Victor Hugo said that there's nothing
00:30:02.860
more powerful than an idea whose time has come now I did joke earlier about functional
00:30:09.429
programming being hot right now and it is fun to poke at the flightiness of programming trends but I really do think
00:30:15.309
it's trending for a reason it's an idea whose time has come again and again
00:30:21.159
through the history of invention we see that when the world is ready for an idea when all those foundations have been
00:30:26.649
laid that idea won't come to just one person it'll come to numerous people in
00:30:31.659
numerous places and when that happens just like we're seeing with functional Ruby well then you know it's an idea
00:30:38.259
worth paying attention to and in this way I think we're starting to bridge a
00:30:43.389
real gap that's existed for a long time within our own community I haven't
00:30:48.669
forgotten how much we owe to Rails it's the thing that it's the thing that got us most of us our jobs and ultimately brought us to places like this but I
00:30:55.870
think for the longest time rails has been perceived as the start and the finish of the Ruby story people who
00:31:01.419
wanted something different didn't really have a real place to go and for people who felt like they wanted
00:31:06.519
something different well they didn't really know where to look and now we're
00:31:11.649
starting to see such place start to form around these communities and these tools and this makes functional Ruby a real
00:31:19.029
world thing and as we've seen it's something that can bring big improvements to your apps and your own
00:31:24.190
real world situations as app developers as well because when we follow that approach
00:31:30.340
that hybrid approach of functional and object-oriented programming in Ruby we strike this amazing balance that really
00:31:36.910
does help us build better designed more maintainable applications and then when
00:31:43.059
we take this formula and had in our own Ruby community our generous welcoming thoroughly decent community things get
00:31:50.500
even better because as rubyists we're all about making technology approachable
00:31:55.750
and fun regardless at the paradigm we want to follow and we want to help
00:32:01.030
people level up and we don't want to put barriers between people and the things they want to learn and with Ruby with
00:32:07.240
all of its flexibility as our community shared mode of expression there's really
00:32:12.669
nowhere we can't go and if functional Ruby is a place you'd like to go or
00:32:18.820
trust me that you'll be supported their projects like Dreyer B and Roma B trailblazer and hanami they're all here
00:32:24.400
to help and you can also feel confident that this is a thoroughly practical choice if you want to explore these
00:32:30.250
approaches within Ruby not only because the language is pragmatic and flexible and I'll help you get things done but
00:32:36.429
also because you get to continue to leverage all of your existing knowledge of the language and our ecosystem so I
00:32:43.780
think this makes functional Ruby really worth a try it can help you build better apps and expand your mind at the same
00:32:49.990
time and if you would like to explore this with me I suggest you check out
00:32:55.240
this repository on github we're just getting started and building your best practices example app using the dryer B
00:33:00.520
tools so now it'd be a great time to start following along and I've also gathered up a bunch of notes about
00:33:07.000
today's talk on this link here so if you want you can refer back to that later to learn more but besides that thank you
00:33:12.520
all so much for your time today and I really hope you'll give this a chance the next time you start thinking about the way you build apps thank you very
00:33:18.730
much thank you so much Tim one more thing Tim
00:33:25.500
is going to be hosting a workshop this Saturday can you tell us a bit more about the workshop and what what we can
00:33:31.050
expect well I guess the tricky thing about entire stacks of gems like the
00:33:37.380
ones I showed you here is that is very hard to convey in you know 20 minutes just how they fit together in just the kind of benefits that can bring your app
00:33:43.500
so in the workshop we'll have a whole day as a group then we're going to build the typical blog everyone knows how blog
00:33:48.630
works but we'll do it with this entirely alternative ecosystem of tools and we'll get to understand all the details and
00:33:54.690
all the nuances of how they fit together and how they can help you make more maintainable apps sure thank you very much so I think we have run out of
00:34:02.340
tickets for the for the workshop yes producer yes and time for questions or
00:34:08.130
questions do you guys have please first
00:34:21.290
no it's wonderful magical everyone should do it now there's a learning
00:34:26.630
curve because it's an approach that I guess as a community we haven't followed so you do need to consider those things
00:34:32.270
from a different angle it is a bunch of different tools to learn and I guess our emphasis in
00:34:38.090
building these tools is we've been working from the bottom up so we build the the smaller logical units on their
00:34:43.550
own first and then we think about how to tie together so you see a bit more of that integration happening at the surface level of your app so you sort of
00:34:51.800
it's not so much like dropping exceptional attributes for and then everything working right so it's you you
00:34:56.840
you build a little bit one of the machinery but I think it's a good approach because it means you have more
00:35:02.240
control around that machinery and you end up with places you have these hand holds in your app where if we need to
00:35:07.340
make a change that affects just one part without having flaw and ramifications you've got that one place ready there
00:35:12.530
for you yeah so it's really just the learning curve and the app the gems are relatively young still we're hoping to
00:35:20.060
hit 1.0 on the next sort of four ish months with a lot of them but yeah I
00:35:25.850
guess if you're if you're keen you can definitely work with them and put them all the way through the productions it's what we've done and I feel like that
00:35:32.210
really helped cold spell the other questions that's a pleasure
00:35:40.080
and that would be my closet
00:35:47.869
it's for the termination this is what you're describing
00:35:58.360
michail said I did another talk last month in India where I introduced these
00:36:03.790
as a way of helping you be able to change positive application and really changes the biggest part of our job as
00:36:09.880
programmers so I think we owe it to ourselves to pick tools that allow us to make the decisions that enable easier
00:36:17.350
change later on like Alex was talking about that the dhih dhih dhih approaches
00:36:22.570
but also just how we think about how we organize our objects and how they relate to each other and what I found is that
00:36:28.390
working with tools like dry B and dry system is that those approaches actually become doable rather than having this
00:36:36.760
big three buckets of MVC and if you speak murky pool inside each one with no
00:36:41.890
clear connections between them so I feel like these gems make this approach something that's feasible and realistic
00:36:47.020
and that was the thing I needed to finally make that jump and build apps
00:36:53.170
that felt change positive easy to maintain it's a good point
00:37:00.420
it's obvious eh ah oh yes
00:37:06.029
I don't remember a lot of Haskell but I did some of it during my uni days so
00:37:11.940
what I do remember as the strengths of Haskell is one is higher-order functions
00:37:17.940
I can combine multiple I can pass functions as arguments to other
00:37:22.950
functions and I have absolute confidence that what I combine regardless of how
00:37:30.210
deep I combine it it will always work because of the method signature so that
00:37:36.029
is strong typing there is something that Ruby doesn't have so is there anything
00:37:41.220
that the the DRI framework can help with reliability that to ensure that I don't
00:37:47.130
I don't have a now object somewhere somewhere in inside the chain which will
00:37:52.319
blow up on me later on yeah I guess firstly we have to recognize that Ruby
00:37:57.779
is in high school so I don't have that sort of functional purity but I think we can go a long way by following some
00:38:03.359
conventions and I only hinted at it really quickly but by wrapping up all of
00:38:08.490
the results from our functional operations in instance of the ether monad for instance that means that we'll
00:38:15.420
always have these result objects that require us to do extra steps to like get
00:38:21.450
out the value which adds to the safety of working on them so you can say I want
00:38:28.500
to transform this value but only if it was previously success and that means if it was a failure it just skips that
00:38:34.109
transformation nothing blows up so if it was like a random nil result somewhere you don't get that that Neil area that
00:38:40.680
would get soften and Ruby and that's what lets us build together whole pipelines operations that all work on the same value this gets passed from one
00:38:46.799
to the other and they'll safely operate from start to finish and you know that's once you start to have that in your tool
00:38:52.200
belt it's amazingly powerful and it really helps you break like big sequences of logic down into individual
00:38:58.049
units and each of those units is like a screen full of code so it's really easy to understand each one at a time which
00:39:03.329
really is is freeing as an application developer I think because you're no longer having to keep all that state in
00:39:08.369
your head does that answer the question Larry yeah
00:39:15.469
of course any last questions Oh yep go
00:39:23.959
ahead and be in 500 words or less all
00:39:29.390
right so as I mean normally we use breo's right we have all these you know
00:39:35.539
preview jams preview libraries that we can use to build application you know as
00:39:41.930
fast as possible so is there any practices or any way to integrate try RB
00:39:48.499
into rails and at the same time we can have the you know we can use those
00:39:54.349
libraries that we have been using for example device and activerecord
00:40:01.609
activerecord and stuff like that that is like you know building a hybrid between
00:40:06.969
rails and drabby oh well all of the driver gems you can drop straight into a rails app so dry validation drive types
00:40:13.700
try struct drive monads all of those we drop straight into a rails application
00:40:19.339
and you could start sort of getting the benefits there because they're all
00:40:24.739
things that everyone has to do no matter what their web framework is everyone's gotta validate data everyone's got to think about the way they're modeling the
00:40:30.469
values in their system and passing them around so I think there could help a lot with improving some of the I guess
00:40:35.809
correctness of rails apps on the other
00:40:40.819
hand if you're building an app entirely out of this alternative stack then yeah there'll be gems out there in our
00:40:46.489
ecosystem that don't drop right in like you couldn't drop devising sits a rails engine but what what we can do still is
00:40:53.839
we can use a lot of the gems that underpinning things like devise so warden for instance is the authentication framework that it rests
00:40:59.479
on that works at any rack app and a lot of our gems out there do work with any rack app but the thing that becomes
00:41:05.209
really clear once you stop working within rails is just how much of our ecosystem is built to be dropped into a
00:41:11.209
rails app and doesn't have a useful core on its own and so it's made me really
00:41:16.249
aware of what I feel like the best approaches we're building gems in the Ruby community which is to build the
00:41:21.769
core of our offering first free of any integrations so anyone can use it and then wrap around optionally those
00:41:28.230
integrations with frameworks so I think that will be a thing that keeps our community more healthy because we're not tired to it like a a single monoculture
00:41:35.130
and a single big framework together but yeah so you can use a ton of the gems
00:41:40.170
and drop them straight into a rails app even even things like ROM which is a completely different persistence system
00:41:46.680
can be used within rails as well and I think using using wrong within rails could be one of the best things you best
00:41:52.740
decisions you make because it really is built from the ground up to separate application logic from the persistence
00:41:58.830
layer which really untangles a whole lot of the things that do make life bit difficult when you have a like a long
00:42:04.980
live rails app all right thank you cool we'll take one last question and right
00:42:12.420
before there we go and right after that we're gonna do the lucky draw mm-hmm one last question please
00:42:22.710
sure have you tried the idea of CQRS in
00:42:28.410
rails it's a command key responsibility subrogation yes that's that's basically
00:42:34.800
the founding patent of ROM so command inquiries in database language
00:42:40.590
effectively mapped to reads and writes and ROM has this model than both of separate objects so we have relations
00:42:47.280
which basically are the things that match database tables and in our relation classes we write all the
00:42:52.890
low-level reusable query logic and then we have commands and commands are about riding back to tables and commands are
00:42:59.100
actually the low-level thing underneath change sets which are a higher level abstraction for working with data that
00:43:05.250
we want to send back to our persistence layer and yeah that's been a really good pattern to follow because reading and
00:43:12.600
writing are distinctly different activities and they don't need to be modeled together in single classes and again that's helped us untangle a whole
00:43:19.590
lot of persistence related logic and have a clear pathway for each of those different activities thank you Thanks