RailsConf 2013

Simple and Elegant Rails Code with Functional Style

By Attila Domokos

Do you have to look at Rails models with 2500 lines of code? Or 200 line methods loaded with iterators, conditionals and instance variables? Not only you, even the code author does not understand what's going on in there.
I'll show you how you can craft simple and beautiful Rails application by adopting functional programming inspired ideas. Say goodbye to the mess you have by constructing tiny classes and functions that you can use to build up a complex system.

Help us caption & translate this video!

http://amara.org/v/FG9y/

RailsConf 2013

00:00:16.320 all right so uh simple and elegant rails code with functional style is the name of this talk
00:00:22.560 i've been working professionally for three years now i spent eight years in the dotnet space there's
00:00:28.960 a little bit of a feedback can you help us with that thank you can you guys hear me
00:00:34.239 cool so i spent uh eight years in the dot-net space and i i was lucky and fortunate to switch over to ruby and
00:00:41.280 ruby on rails i was laid off to uh two months ago from my previous job
00:00:46.640 and i found a new job in chicago so i'm moving from northeast ohio to
00:00:52.559 to chicago
00:00:59.199 are we cool okay anybody here from chicago all right see you guys there hopefully
00:01:05.680 soon um this is the company i work for i am the only developer right now we are
00:01:11.360 looking for other people um we are really big in the franchise space and we make um
00:01:17.759 we actually give numeric results uh for hiring decisions so instead of
00:01:23.360 just making a instead of a gut feel you basically have a numerical results and you can pick
00:01:29.119 your best candidates based on that i'm not going to
00:01:34.560 teach you functional programming in this talk and i'm not going to try to bend ruby to be a functional one either
00:01:42.079 hopefully i'm going to show you some simple and elegant rails code
00:01:49.680 in my previous job shouldn't move right
00:01:55.600 all right i won't i promise you uh so at my previous job i had uh 25 minutes
00:02:00.719 commute um to work and i listened to the radio but i got sick and tired of the
00:02:05.759 of the commercials and i decided to listen to audiobooks and the book e-myth revisited was recommended to me by a
00:02:12.480 friend of mine and i remember the moment when i heard that sentence the work you do is a reflection of who
00:02:18.239 you are you know when i see somebody does a crappy job i i don't think about the job he does i kind of think about
00:02:24.480 what kind of person he is or she is if you can translate it to our own profession
00:02:29.680 the kind of code you write it's it describes what kind of person you are
00:02:35.200 two weeks ago i went bowling with my son and i drove through um this road and i thought
00:02:41.200 uh i'm going to lose my one of the wheels on my car i stepped out and you see the car is passing right there but i
00:02:46.560 took a photo i think it took more than one or two years to end up a road like this and you
00:02:51.920 can see that they try to try to fix it but how successful that is right i call
00:02:57.280 this road refactored you know they they put the tar in it you know and it's
00:03:02.800 good probably for like a winter half the winter and then the spring comes and and this fix is going to be um pretty much
00:03:09.040 as big or maybe bigger this pothole is going to be bigger uh than what it was before
00:03:14.239 uh late last year i went through the uh the news and i i found this story from from china
00:03:20.239 the person refused to sell his uh his apartment and the government just couldn't wait to
00:03:25.760 build the highway so what they did actually they built a highway around it
00:03:31.840 yeah no kidding uh two weeks later i think they agreed on some kind of price and they they
00:03:37.200 finished the highway property but still so i think this is an awesome story and i thought nothing could nothing could top
00:03:44.080 this but i was wrong i actually a couple of weeks later i found this a family refused to remove the remains
00:03:50.400 of the relatives and they had to build this building they put down the foundation well they couldn't wait you
00:03:56.480 know they just started to do it around the graveside here's another angle
00:04:03.599 do you remember what your room looked like when you were 15 years old you know mine looked probably something like this
00:04:08.799 i spent i spent probably hours looking for my textbook my jeans or whatnot
00:04:15.599 yeah this is this is what this is what it looked like when i grow up and i'm not proud of it but that's what it is
00:04:22.160 so let me show you this puppy here this this is a model from
00:04:27.360 one of the rails apps that i had i had the privilege to work on this is actually an e-commerce
00:04:32.400 application this is the orders model 2700 lines of code
00:04:39.360 i'm not uh kidding the calculate shipping method in it it's uh i unfortunately don't have my notes
00:04:45.600 it's on my cell phone uh but the calculator chipping method is is somewhere around 206 lines of code uh
00:04:52.240 and right below it there's actually a recalculate shipping method 197 lines of code
00:04:58.400 untested yep so we tried to tackle it uh we
00:05:05.120 looked at it and like just screw that it's just it's just too much too big of a work
00:05:11.360 when you see code like this think about companies actually that has code like something like this i was laid out from
00:05:16.960 this company because of financial reasons this code actually can bring down a company think about it that way
00:05:23.280 and it and i i would like to give them the excuse that actually this code was written by contractors no actually it
00:05:29.120 was written by employees but before i got there so i wanted to find a tool a good tool
00:05:34.800 that i could use to analyze code complexity and i bumped into the flock jam does anybody know the flock jam here
00:05:41.680 awesome um i talked to actually jim weirich at a different conference early january and he said hey i use actually
00:05:48.240 flog to run it against a project that i haven't seen i don't even have to crack open the classes it just gives me a
00:05:53.919 value and based on that i can tell how big of a mess or how clean the code is so
00:05:59.120 the way it works is that you run it against a class or a group of classes and you're going to get
00:06:04.160 you're going to get a number and what you need to know about the number is that the higher the score uh the more pain the code is in or i
00:06:10.639 could say uh the higher the higher the number the harder to test it okay this is really central in my in my talk
00:06:17.759 so uh please check it out installing it is super simple you you
00:06:24.240 have to add it to your gem file i usually edit in my rails app i add it to uh development or the test group
00:06:30.000 and um you can install it through rubygems jams running it is super simple it's going to
00:06:37.120 give you a numeric results you can run it against one class or a group of classes what i usually do i just run it against controllers and
00:06:44.000 and models and i 95 i can tell what kind of code i'm looking at
00:06:49.680 so uh the video that you saw earlier in in in the previous slide
00:06:55.360 it has 25902 flock point
00:07:01.039 imagine that so just just so you can you can you can the the number hopefully that i'm going to show you here is going to have some
00:07:06.960 kind of sense to you or it's going to make sense um the ideas that i'm going to talk about
00:07:12.400 here um were born um through working on different uh rails applications uh in order to kind of
00:07:19.199 retell the story i wanted to come up with uh one application and this is a tracking application where you can
00:07:24.880 provide the category the amount and description it's key that it's not just a simple save you know just get the
00:07:30.319 value and save it in the database it has to do some kind of parsing logic right so when you provide running 3.2.12 it's
00:07:37.120 going to save it into a category table with the value of running and then the
00:07:42.160 track amount and the json data basically with the amount and the kind of description
00:07:47.759 around it it's going to file the track with that with today's date if you want
00:07:53.199 to override that that date you can actually use you can actually use the uh the date
00:08:00.479 prepend it to your input let me ask you a question um where do
00:08:06.879 you put your domain logic do you put it in controller raise your hand please if you if you put in your controller
00:08:13.039 come on guys how about models what do you do you put domain logic in the models
00:08:20.319 okay so that's like one third of the room how about you get how about the two-third of the room where do you guys put domain
00:08:25.440 logic okay all right
00:08:35.519 yes yes so i i thought actually this is history but
00:08:41.440 the the code base i inherited from contractors uh or consultants actually i don't i don't call them consultants i
00:08:46.959 call them contractors uh the code base i inherited from uh from contractors at hierology uh it's controller heavy
00:08:55.040 so uh 1750 lines of code actually in a controller is not uncommon
00:09:01.200 yes oh and by the way i when i was interviewing i asked the contractor hey how many units do you
00:09:07.440 have you can guess the number right zero i'm sorry
00:09:14.720 i i did because yeah good point i did join them because the business idea is great and i think
00:09:20.560 they have a future yeah we just have to clean up that uh clean up that application and i'm i hope i can come
00:09:26.399 back and tell you guys the story how what we did about that so basically uh what i try to do is i
00:09:33.040 try to code this parsing logic into the controller action and this is what pretty much what the code base i'm
00:09:38.720 working right now looks like i don't want you to spend and understand basically what it does um it basically
00:09:46.000 just has the stamp on it right this 48 lines of code are really bad
00:09:51.680 this is how the flag looks the flag values actually are trending uh this is our initial state i'm comparing black is
00:09:58.240 the controller in case you can't see it you cannot see it and green is the model right the controller has a higher value
00:10:04.000 because it does the parsing right the the model has some additional logic but but not all that much
00:10:09.920 all right so what i did i used um our favorite refactoring pattern extract method instead of using uh comments i
00:10:17.360 use the method names to describe that particular routine what it does i went from 48
00:10:22.560 lines to 25 lines and
00:10:27.760 yep this is actually how i ended up with the refactoring and this is what the flock
00:10:33.040 values are after this refactoring exercise flock total went up slightly you can see it's 71 and it was around
00:10:39.600 65-ish however the method with highest flog in the controller dropped down to health
00:10:45.200 right so instead of looking at that huge action you know with like 40 something flock value 46
00:10:51.279 point it's not 20.6 just by using extract method a pretty good sign
00:11:00.560 and uh this is uh this is where we went right we figured out that uh reusing logic from the controller is not all
00:11:05.760 that easy so what we did we went from fat controller to fat models
00:11:11.040 um i tried to follow this trend as well i moved the parsing logic from the controller action put it into uh the
00:11:18.000 model and you can see now that the controller looks pretty nice pretty clean you know instead of doing the logic itself i'm
00:11:24.480 actually doing the parsing in the model and i'm just sending the message to them to the model
00:11:29.600 and look look how we are trending here the model went up to 84
00:11:37.360 and and then the controller actually dropped down to 25.6 pretty clean you know i i can tell you
00:11:43.600 that the class with 20 30 flock point you can you can pretty much grasp and understand
00:11:49.600 what it does and always think back you know that that example that i showed you that was 2500
00:11:54.959 right 2500 points
00:12:01.040 and this is where i joined the party three years ago when i when i started working on the rails application that i
00:12:08.160 that i had the pleasure to work on it was a by that time it was a four year four-year-old app
00:12:13.200 and when i joined the company i asked the fellow developers uh how many unit tests do you guys have oh we have zero
00:12:18.880 that's why we hired you we wanted you to help us with that that's it's cool and why don't you guys running it and the
00:12:24.720 answer i got was is that it takes forever to run it it was 17 seconds actually on that code
00:12:30.399 base to run one spec so imagine doing tdd by that
00:12:35.920 so what i decided to do early on is move my business logic out into services and uh i had a blog post out there on it it
00:12:42.800 got uh quite a bit of hits um
00:12:48.000 and i was i was stubbing actually a whole lot of stuff out of rails that i don't do anymore but with these
00:12:53.040 techniques i was able to go and run execute extra specs under one second it was a totally
00:12:59.440 different feeling all right so the the code really doesn't
00:13:04.560 change all that much after this change instead of calling the the the model i'm calling the service
00:13:12.320 and the service itself is a poor object it doesn't inherit from any kind of active record or action controller
00:13:18.399 anything anything rails related so i can easily test it as just like a pure plain
00:13:23.519 old ruby object do you guys do you guys actually write services this way
00:13:30.079 using poros raise your hand if you if you ride those sweet
00:13:36.320 all right so i'm switching extra gears here with my um uh the graph that i'm using actually to
00:13:41.839 represent the flag values instead of comparing the controller and the model now i'm actually comparing model to
00:13:48.160 services because that's where i'm shifting the code you can see that the tool for the model
00:13:53.279 went back to 38.4 uh where it was before and uh and this and the service actually
00:13:59.680 is around 71 points and i'm using only one service class so that's why you see
00:14:04.880 that the floc tool actually and the flock class average are the same
00:14:13.040 this is how i wrote service classes at the beginning i had an entry method in this case actually it's four track
00:14:19.440 um that red reddish kind of circle represents the controller and
00:14:25.120 that's the service the four track is my entry method it calls other methods on the service
00:14:30.800 itself and by the end of the call chain i have an instantiated track object available
00:14:36.560 and this was beautiful because i was testing actually all the methods i made all methods private i killed many
00:14:43.279 unicorns i'm proud of it but basically what happened was that uh this was one object and when i changed
00:14:48.959 the signature let's say the builds category for the builds category method went from two arguments to three arguments all of a sudden my unit
00:14:55.120 started breaking like why i mean this shouldn't of course because i was testing uh private supposedly private
00:15:00.800 methods i made them public just to just so it's easier to test so i changed it back i'm gonna i use
00:15:08.000 actually a one public method on the service class four track everything else was
00:15:13.680 private and i was able to change now the the signature of the method however uh
00:15:19.920 setting up the test were really really hard just because that service object was violating single responsibility
00:15:26.079 principle and it was really hard for me to test those and the question comes what do you do
00:15:31.279 when your business customer or your customer comes back to you with additional requirements where are you going to put
00:15:37.279 that code how are you going to grow this service right are you going to add another method are you going to increase
00:15:42.720 the the effort that it takes actually to run one single test yep just think about that
00:15:49.839 i was sitting at this coffee shop a year and a half ago in january helping a co-worker actually with the problem
00:15:57.360 and um we called it a service this way and it took me i remember 10 minutes
00:16:03.120 trying to understand why i cannot run as a spec why spec is failing what is the dependency there it was obvious
00:16:09.440 that the specs are telling me something and i wasn't listening
00:16:15.040 before i continue the story i'll take a look at how i name my service instead of using objects physical
00:16:21.199 objects like user or employee or door or car i'm using actually verbs they define action
00:16:27.920 and what i've what i learned is that i can follow single responsibility by naming my services this way so when i call a
00:16:35.120 service parties feed i know exactly what it's going to do i know it's not going to save a category into the database
00:16:40.480 table i know it's going to send it's not going to send an email to the customer or anything like that it's going to do one and only one thing called uh
00:16:48.000 parser's feed it's just going to parse that feed that i'm i'm passing to it i attended code retreat um pretty much
00:16:55.040 at the same time when i was sitting at that coffee shop and somebody recommended reading this blog post
00:17:00.480 please do yourself a favor and read this this is actually written by a java developer it's called execution in the
00:17:05.679 kingdom of nouns read that blog post and you're not going to name your uh your
00:17:12.240 your object the same way or your service is the same way
00:17:23.679 so as complexity grew i saw that my methods actually grew from five lines of code to eight lines to ten
00:17:30.640 lines of code instead of doing that what i did i created sub classes as i went and i created subclasses for
00:17:37.600 all these methods that i refactored early on and used extract method for
00:17:43.360 what i gained with that is that it was so much easier to test it because all i had to do is just stop and mock the dependencies i didn't have to go and set
00:17:50.160 up all the requirements that it needed what i what i cared about is that they were called in order uh so i was it was a whole lot happier
00:17:57.600 experience but still i didn't feel it wasn't perfect what i was striving for actually was
00:18:03.280 this i really wanted to have a code that looks like something like this i wanted a uniform interface i wanted a i wanted
00:18:09.600 a method actually with context as an argument to add it to it and uh the reason i wanted to do that is
00:18:16.400 because it was super simple to test this right it was only one argument that it had to take in it was only the the context
00:18:22.880 method that i had to stub out so this is what i was striving for
00:18:28.640 as i mentioned i spent eight years in the java.net space and i learned design patterns or tried to learn design
00:18:33.919 patterns quite well which design pattern is this
00:18:39.360 there you go chain of responsibility i loved i love this design pattern the reason i loved it is because uh
00:18:46.480 whatever i had to do my work it was uh i had it was not only one thing that i had to do it was like five things just like
00:18:52.320 in this case you know i received the arguments i had to split it i had to sparse it i had to check if data was best in front of it i had to validate it
00:18:59.600 i had to save it in the database every kind of test that i do has at least six steps five or six steps to it
00:19:06.080 um and i and i i believe actually the chain of responsibilities is a pretty good solution for it i tried to build
00:19:11.520 chain of responsibility in ruby but it was just too heavy it just it just took too much effort i think chain of
00:19:16.960 responsibility makes a lot of sense in java you know in the statically typed languages but
00:19:22.160 but in ruby it was just an overkill so as i as as i went through this exercise and i showed you what i was try
00:19:28.640 striving for uh two types of objects emerged one was actually the organizer object that you see here in in blue
00:19:35.520 and uh little actions that i'm going to talk about later so the the role of the organizer object
00:19:41.520 is uh telling you a story so when you look at an organizer object you can you can pretty much figure out what that
00:19:46.799 particular process does in my case it starts with the splitting the feed to parts apart sorry
00:19:53.200 parts is the recorded at validate speed so on and so forth and when you put code around it
00:20:00.480 you could still read it you see that's what's so beautiful about this you can still read it out you don't have to kind
00:20:05.600 of hand down what it really does it has step one step two step three step four so on and so forth
00:20:13.039 so the organizer object tells you the story that's what it does nothing else it doesn't execute business logic or
00:20:18.799 anything like that it just tells you the story however the actions the actions are the
00:20:24.160 the atomic building blocks of this process or series of actions i call them
00:20:30.559 and what they do is uh one action represents one business logic right in there
00:20:38.320 the actions are called in order they are called by the by the by the organizer object and data
00:20:46.080 is passed into it through the context so let's look at one of these actions
00:20:51.520 one of these actions this is what my class looks like you see it has an execute method that
00:20:57.360 takes a context in it is a guard condition it pulls the data out it has to work on it runs the business logic
00:21:04.320 puts the shoves that's the data in back into it and at the very end it returns a context
00:21:10.799 so after i refactored that large service class with multiple multiple private methods this is what i ended up with
00:21:17.840 look at how my flock last average for the service i should drop down from somewhere around 70 to 13.9
00:21:26.799 i can tell you you can understand a class actually with with a log value of 13.9 very easily it's just super simple
00:21:33.760 to understand you could ask me what is so functional about this well i'm not maintaining
00:21:40.799 state all my actions are stateless and functions are wrapped in a class object
00:21:48.000 i could have used module but i to be honest with you sometimes i do use actually a little bit of a private class
00:21:54.400 i'm sorry private method and and that's that's pretty much it you know it cannot be simpler than that
00:22:04.080 the context itself is like a conveyor belt in an assembly line it's um just
00:22:09.120 like the the way uh cars are being built goes from one station to the other there
00:22:14.159 are workers adding stuff to it or altering things on it that's exactly how the context works
00:22:21.120 and the objects actually has a well-defined structure
00:22:29.200 yep the context actually you can see that it's instantiated by the organizer object
00:22:36.640 and they are being used actually to pull the data out just like i i use the analogy
00:22:43.120 with the assembly line and they are pushing
00:22:48.320 they are pushing uh the contacts into a failure state because i need a signal if something failed i don't want the third
00:22:54.880 and the fourth step for example to execute so in this
00:23:00.159 slide i'm describing that the first action passed the second one failed and then the third and the fourth did not
00:23:06.400 even execute as i was going from one job to the other
00:23:11.840 and one project to the other i ended up copying files and
00:23:17.039 referring back to david's keynote necessity actually brought me almost to a framework or some kind of gem and that
00:23:22.960 gem is called light service i didn't sit down and just write you know light write service i extracted it
00:23:29.039 out and it's very simple and the reason i call it light service is because it has only two classes in it and i'm proud of
00:23:35.600 it and i don't want to make it more complex than that i want to give people the freedom to do any any way they want want to use it
00:23:42.640 the organizer object has its own structure feeds the data
00:23:47.919 builds the data actually uh with the in the form of context uh iterates over the actions uh and
00:23:54.400 calls the execute method on it and then injects in the context into it and
00:23:59.440 return the returns the context at the very end um the action itself has um an execute
00:24:06.480 method returns the context if there's a failure there that's the guard condition
00:24:11.520 extract the data out of it this is where you put your business logic basically and at the very end you
00:24:17.440 return the context so a friend of mine a friend of mine who
00:24:24.080 was working with me at the time asked me you know it's really annoying that i have to remember the guard condition and the execute method at the very end
00:24:31.120 sure very good uh observation what we decided to do instead of uh using and
00:24:36.400 make you know you have to remember that you have to edit the car at the car condition instead of doing that what we
00:24:41.760 did we actually created a macro so you don't have to remember to add the
00:24:47.360 guard condition return the execute at the very end executed is going to give you actually the execute method and then
00:24:54.159 the block is going to be called whatever you pass in there yep hopefully it's so much
00:25:00.480 easier to use you can go ahead and take a look at it install it through rubygems or
00:25:06.400 download it yourself and clone it the question comes though is what
00:25:12.400 happens when you have to grow software you see every project starts out so beautiful the first two months everything just flies so fast right and
00:25:19.120 two years later it's like one tiny change that would that should take half an hour takes three days right
00:25:24.480 so the question is how are you going to grow your software i think that's that's that's a crucial question here
00:25:30.240 in order to uh kind of see how i could progress to a model that that has 27 lines of code
00:25:36.559 in it uh i decided to make an experiment what i did i actually had the controller
00:25:42.080 action with you know with the extracted method in it and i'm comparing the services with the
00:25:48.240 organizer and the actions so that's what you see left hand side is the controller with the with the parsing logic in it
00:25:55.039 and then on the right hand side with the red color you can see the series of actions right there
00:26:00.480 and this is our initial state uh the the complexity uh on the right hand side for
00:26:06.080 flog class average is 71 and the actions are at 14 points
00:26:12.240 all right what i did actually i since we were talking about growing software right what i did i duplicated the methods so and i uh appended the
00:26:21.120 one to the very end of the method names so i had not only parsers feed but i had parsers feed one parser's feed
00:26:27.520 and you get the picture and i did the same thing for the classes i just duplicated the classes as it is
00:26:33.120 you know so instead of having six actions i had now 12 and these are the numbers i had uh it
00:26:39.200 went to 124.2 uh for the for the controller because i had only one controller right
00:26:45.679 uh and the method i'm sorry the flag class average was around 13 still
00:26:51.520 and i tripled that and this is what happened you see how it starts growing and i believe if i if i'd
00:26:57.520 if i'd done it long enough i would have probably ended up with a vlog value of 27 or 2500
00:27:04.240 but the key point here is that the class average is at 13 point
00:27:12.960 so this is the trend that i noticed uh if you keep growing your software just in one class you know that even if
00:27:19.200 you had multiple methods in it it's going to be on you know and uh and and the class average flag class
00:27:26.960 average is going to be around 13 or 14 if you keep and stick to that style
00:27:34.240 what a warning um when would you use this i found in my ass so would you do actually a series of actions with light
00:27:40.159 service all the time uh no actually i wouldn't if the complexity or the
00:27:45.279 business logic doesn't require it i wouldn't do it i would actually take advantage of rails i would use it for
00:27:51.120 that and i don't do it you know i mean whenever i have update attributes and it works perfect just do it
00:27:56.640 but as soon as i have a conditional maybe i keep it in the controller as when i have the second conditional or
00:28:02.640 maybe a conditional and an iterator i'll break it out into a service and if that service actually is doing more than one
00:28:08.399 thing i'm breaking it up into two actions and one organizer object
00:28:13.760 so that's the principle that i've been following in the last couple of months and this is how i show you that take
00:28:20.240 advantage of updater attributes if the case is simple please use please use rails it's pretty
00:28:25.760 good at pretty good at that what if you haven't worked on this code for let's say six months and uh and the
00:28:32.960 customer comes back that hey um the babies initialize the the category i want to do something else there as well
00:28:38.880 what do you do well since i'm not using observers i'm not using concerns
00:28:45.360 basically what i have to do is just look at either the routes or just execute the action
00:28:50.880 figure out which action and controller i have to go into i find the controller and in the controller i see that okay
00:28:57.120 the logic is not coded there actually it's externalized into a service very good i follow that and i easily
00:29:03.360 follow the service i go into the rails independent service and i notice that the logic is not there it's an organizer
00:29:09.039 object from a series of patterns a series of actions sorry and i look at since it's really easy to
00:29:15.840 read i look at the actions and i find actually that the category is the fourth action
00:29:21.520 i open up that action and from the 13 lines of or 50 lines of code i can easily find the line where
00:29:26.640 the category is being initialized super simple actually to find the code i remember actually pairing with a
00:29:32.880 developer at a shop in chicago and they had a build failure and we stared at the code for an hour trying to find why we
00:29:39.919 can initialize an object through a factory how's it going
00:29:45.919 the other advantage that i found was actually code reuse this was about a month ago i had to work
00:29:51.760 on uh one of our interview guides when we load it we have to go through a
00:29:57.520 series of different tasks and i uh put it in into this code this is actually from our
00:30:03.600 production system you can see how i built an organizer object with seven different
00:30:09.600 actions and admins actually can edit the same questions they can delete questions in
00:30:15.919 order to load it for edit in the admin section i was able to reuse four out of those seven actions easily
00:30:22.960 huge reuse all i had to do was just create a new organizer object and i was on my way
00:30:28.480 beautiful code reuse and that's what i ended up with
00:30:33.919 and unit testing it i didn't have to unit test you know the actions i was able to unit as just the organizer object boom done
00:30:42.240 and i also found out that i'm not alone with this kind of this kind of thinking i paired with a developer at hash rocket
00:30:48.000 in chicago and they were using actually strategies they didn't have a gem or didn't have a best practice for this you
00:30:53.440 know but i noticed that they are actually weaving actions together here in this particular code
00:31:02.320 so my summary um get out of the framework that's what i try to do all the time and put my
00:31:07.679 business logic outside of rails so i can unit test it really fast and i can reuse it anyway i want i can move it from
00:31:13.120 rails to a background worker anywhere i want i can put in a gem if i want to the coach should tell the story you
00:31:19.200 you'd look at it and you should it should read it like a paragraph in a book don't use state if you don't have to i
00:31:25.440 think it gives you complexity and it's just going to make your code more complex that's what i found
00:31:31.760 behavior from the data my data is actually the model in the context and that goes and flows through
00:31:39.120 the commands or actions and grow your code horizontally instead
00:31:46.320 of adding another method to a class to a model or a controller
00:31:51.519 create a new class please just grow horizontally what do you do when you have a change you encapsulate that
00:31:56.559 change actually in a new class and most of it will make it simple
00:32:03.440 so when you remember um this this actually a 2500 lines of code that i try to represent with this messy
00:32:09.760 room i'd like you to think about this hotel room in japan this is actually a hotel room without a tv without a
00:32:16.320 furniture or anything like that look at the simplicity of this hotel room so when you see actually an action like
00:32:22.080 this i want you to imagine that hotel room without any access any access furniture anything
00:32:27.200 anything anything unneeded here are my social links
00:32:32.399 i'm gonna have it up there in a moment thank you for your attention
00:32:38.000 i actually you can find the slides it's an older version but you can find it actually through this link if you want
00:32:44.159 to write that down it's bitly ad at railsconf i constructed that link this
00:32:49.519 morning and thank you for your attention
00:33:30.960 you