Summarized using AI

Real-World Functional Ruby

Tim Riley • October 12, 2017 • Selangor, Malaysia • Talk

In his talk titled "Real-World Functional Ruby" at RubyConf MY 2017, Tim Riley discusses the integration of functional programming principles within Ruby to improve the design and maintainability of applications. He highlights the struggles developers face when managing large Ruby on Rails applications and introduces the concept of 'design stamina hypothesis,' which explains how developers can become less effective over time due to poorly designed applications.

Key Points:

  • Functional Programming Introduction: Tim stresses that adopting a functional approach can lead to clearer, more manageable code that enhances overall application structure.
  • Design Stamina Hypothesis: This concept illustrates the diminishing returns in productivity as applications age, making it crucial to invest time in proper design upfront.
  • Functional Objects: He introduces functional objects in Ruby, emphasizing their immutability and independence from state, which simplifies reasoning about the application’s behavior.
  • Dependency Injection: Tim explains how injecting dependencies into functional objects helps in creating modular code, allowing for easier testing and modification.
  • Testing with Functional Objects: He describes how the design of functional objects can facilitate efficient unit testing by using mock objects to simulate interactions with external systems without altering the underlying functionality.
  • DRI RB Project: Tim presents the DRI RB project and its associated gems, which help developers implement functional programming principles in Ruby applications. Key tools include Dry System for dependency management, Dry Validation for data validation, and ROM RB for data mapping and persistence.
  • Integration with Rails: He discusses how these gems can be integrated into existing Rails applications, providing developers with the flexibility to enhance their applications while maintaining their current infrastructure.

Conclusion and Takeaways:

Tim concludes by encouraging developers to embrace functional programming paradigms within Ruby to achieve better-designed, more maintainable software. He conveys that the journey towards functional Ruby is not only feasible but also productive, allowing developers to enhance their experience and joy working with the Ruby programming language. The talk emphasizes a community-driven approach to developing tools that support functional Ruby practices, paving the way for a functional Ruby movement in the larger programming community.

Real-World Functional Ruby
Tim Riley • October 12, 2017 • Selangor, Malaysia • Talk

Speaker: Tim Riley (@timriley)

Website: http://rubyconf.my

Produced by Engineers.SG

RubyConf MY 2017

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
Explore all talks recorded at RubyConf MY 2017
+16