RubyConf 2022

In Defense of Ruby Metaprogramming

If you’ve learned Ruby recently, you’ve likely been told to avoid using Ruby’s metaprogramming features because they are “dangerous”. Here at RubyConf, we laugh at danger. Or at least chuckle nervously at it. Ruby’s flexibility is one of the features that makes Ruby powerful, and ignoring it limits what you can do with the language. Plus, metaprogramming is fun. Let’s talk about when it makes sense to metaprogram, what parts of Ruby to use, and how to do it safely. You’ll leave with the tools to effectively metaprogram in your code.

RubyConf 2022

00:00:00.000 ready for takeoff
00:00:16.920 I was just telling Craig that the first
00:00:20.340 time that I ever gave up talking public
00:00:22.439 was an academic conference when I was a
00:00:24.000 grad student and I was similarly in the
00:00:25.920 last session or the last day in a room
00:00:28.019 that was this big or possibly bigger and
00:00:30.660 like exactly three people showed up
00:00:33.480 so thank you for being more than three
00:00:35.820 people and uh thank you for spending
00:00:38.040 your time here this week uh I really
00:00:39.899 appreciate everybody coming out to be a
00:00:41.520 part of the Ruby community
00:00:43.140 so thank you uh let's start by looking
00:00:45.360 at some code Ruby fans here let's uh
00:00:48.000 let's look at some code this is real
00:00:50.100 code from a fake project it's a side
00:00:52.320 project that I do it's a project tracker
00:00:54.420 if you for some reason follow my
00:00:56.160 newsletter or blog you may have seen me
00:00:57.660 write about it
00:00:59.039 uh the important Point here is that this
00:01:01.620 is a project tracker every everything in
00:01:04.320 the tracker is a card every card has a
00:01:07.680 status and the status has been
00:01:09.479 abstracted out to its own object so we
00:01:12.299 have a parent object a parent abstract
00:01:13.920 class called status and a series of
00:01:16.680 subclasses that are the individual
00:01:18.479 status types done started unstarted
00:01:20.759 attic whatever
00:01:22.500 um everybody else everybody every client
00:01:25.140 of this deals with the abstract class
00:01:26.820 and obviously we have all of these
00:01:28.080 classes that have other functionality
00:01:29.880 too this is just sort of a simplified
00:01:31.400 schematic of the problem
00:01:33.540 now the parent class defines a bunch of
00:01:37.500 other services it defines creation
00:01:39.780 methods for each individual status it
00:01:42.180 defines uh strings
00:01:44.579 two strings for each individual status
00:01:46.560 sorry it defines predicate methods for
00:01:48.240 each individual status and it also
00:01:50.220 defines this is this is the main
00:01:52.079 mechanism by which we convert from the
00:01:54.060 active record data structure to our our
00:01:56.700 status comes in here so we have a case
00:01:59.040 statement right and you can quibble
00:02:01.439 about the various implementations of
00:02:02.820 this but let's assume for the point for
00:02:04.320 the sake of the problem this is actually
00:02:06.060 the business logic we need and so my
00:02:10.080 immediate question to you is how does
00:02:13.140 this code make you feel to look at it it
00:02:15.060 kind of shows up on the background there
00:02:16.379 you've got you know these subclasses
00:02:18.599 you've got all of these uh predicate
00:02:21.000 classes the Creator classes this is like
00:02:23.040 does this seem good does it seem right
00:02:25.379 to you or does it give you that kind of
00:02:27.480 unmatched parentheses this is ruining my
00:02:30.480 day I need to fix this immediately kind
00:02:32.220 of feeling
00:02:33.360 uh by the way if you've seen talks of
00:02:35.040 mine before you will know it is
00:02:36.180 extremely on brand that the only image I
00:02:38.040 use is just a bunch of text
00:02:39.959 uh
00:02:42.000 more to the point
00:02:44.099 the question is are put this in a
00:02:46.620 slightly more like domain specific
00:02:48.300 context maybe does this code have
00:02:50.099 duplication
00:02:51.780 right and on one sense the answer is
00:02:53.760 clearly no if I want to find out if I
00:02:57.000 want to find out
00:02:58.260 is this status done or not like there is
00:03:00.720 one place in the code and only one place
00:03:02.340 in the code that has that information
00:03:03.680 but in another way it kind of feels like
00:03:07.980 it has duplication right
00:03:09.720 so like what happens if the list of
00:03:12.840 statuses changes if we want to add a a a
00:03:17.480 status to say that it's been sent to
00:03:19.980 production a deployed status like what
00:03:22.019 do we need to do there lots of things
00:03:23.940 potentially so let's talk about that
00:03:27.000 so this is a talk called in defensive
00:03:30.000 meta programming we'll get there in a
00:03:31.500 second my name is Noel Rappin I work as
00:03:34.560 a staff engineer at chime Financial
00:03:36.300 there are several time people in the
00:03:38.159 audience here we would all be happy to
00:03:39.900 talk to you about chime or anything else
00:03:41.700 in the world you can find me at norwap
00:03:44.959 noradman.com and I promised myself I
00:03:47.099 would only get really self-promotional
00:03:48.480 if I finish the talk in under 30 minutes
00:03:50.760 so we'll get there at the end
00:03:53.459 so I want to start with a definition to
00:03:56.159 make sure we're all talking about the
00:03:57.540 same thing there is a formal definition
00:04:00.420 of meta programming that has to do with
00:04:02.400 changing Behavior at runtime and is only
00:04:05.099 sort of related to what we sort of think
00:04:07.560 of in Ruby the kinds of things in Ruby
00:04:10.019 that we call Meta programming what we're
00:04:12.540 really talking about here and what the
00:04:13.920 way this is frequently referred to in
00:04:15.659 the Ruby Community is Magic
00:04:18.419 and my definition here of magic is
00:04:21.720 anything in Ruby that is program
00:04:23.820 behavior that is not specified like
00:04:26.520 normally not specified the way somebody
00:04:28.800 from another language would come in to
00:04:30.600 know to look for it so normal is a class
00:04:33.720 definition with class a method
00:04:35.759 definition with deaf normal dot Syntax
00:04:38.400 for method for method dispatch that kind
00:04:42.720 of thing and anything else
00:04:44.639 we'll call Magic
00:04:47.340 Ruby is designed to make magic very easy
00:04:51.479 and so we have things like Define method
00:04:54.540 we have links like method missing both
00:04:56.759 of these things allow you to create
00:04:58.340 functionality at runtime without using
00:05:01.259 the normal explicit def keyword we have
00:05:03.600 things like instance eval which allows
00:05:05.460 you to specify the relationship between
00:05:07.080 a message and its receiver at runtime
00:05:09.840 again
00:05:10.919 uh somewhat magically we have all of
00:05:13.800 these features that allow us to do this
00:05:15.540 and it might be like the old maniest old
00:05:18.660 man thing for me to say but there did
00:05:20.160 used to be more magic in the world
00:05:22.440 um
00:05:23.699 rails used to have these long uh these
00:05:27.419 long method missing hacks find by email
00:05:30.120 and name where the the things were
00:05:32.220 arbitrary and it could go on forever and
00:05:34.380 they were method missing and they were
00:05:35.820 wonderful and fun and completely made
00:05:38.580 unnecessary once Ruby added keyword
00:05:40.380 arguments uh so we got rid of them our
00:05:43.259 spec used to have an even more magical
00:05:45.000 syntax if you can imagine people new to
00:05:46.860 our spec and can't imagine that our spec
00:05:48.360 was once like even more inscrutable
00:05:50.340 internally than it is now it was at one
00:05:52.979 point because of directly monkey patched
00:05:55.320 object and again a syntax that you know
00:05:58.320 had its advantages but had a major
00:06:00.000 disadvantage in that it triggered subtle
00:06:01.680 bugs from time to time for no reason and
00:06:04.139 so we got rid of it
00:06:05.699 uh so I think as a in a broader sense
00:06:09.539 this is these are just specific examples
00:06:11.280 and there were reasons for the making
00:06:12.780 these changes there were reasons why
00:06:14.160 these things existed and reasons why
00:06:15.479 they went away but the claim that I want
00:06:17.580 to make here or the Ruby Community is
00:06:19.199 sort of pulled back from Magic and from
00:06:22.139 being proud about it I think as a thing
00:06:24.600 that Ruby is
00:06:26.580 the very first Ruby Community event I
00:06:29.880 ever attended maybe the second oldest
00:06:32.160 man thing I'm going to say up here the
00:06:34.319 the first Ruby first Ruby Community
00:06:36.479 thing I ever attended was in 2008 and
00:06:38.699 the first speaker was Dave Thomas and he
00:06:40.860 was speaking about meta programming and
00:06:42.479 how wonderful it was that Ruby had all
00:06:44.160 of these wonderful tools and he
00:06:45.840 specifically said that
00:06:48.440 the problems that people have with meta
00:06:51.000 programming are not technical problems
00:06:52.620 they're people problems
00:06:54.660 soluble with training and I think that
00:06:57.419 for good reasons and for bad reasons I
00:06:59.460 think over the intervening what 15 15
00:07:02.100 years uh the Ruby Community has decided
00:07:05.100 that these are in fact technical
00:07:06.840 problems
00:07:08.039 uh and we hear from people within the
00:07:10.860 community from people outside the Ruby
00:07:12.360 Community we can't do this it's too
00:07:13.979 complicated it's too hard to maintain
00:07:16.160 developers from other languages won't
00:07:18.180 get it we won't be able to train people
00:07:20.520 and all of that is true to a point it
00:07:23.880 can be complicated especially when
00:07:25.319 misused it can be hard to maintain
00:07:27.120 certainly true that developers from
00:07:28.979 other languages have a learning curve
00:07:30.539 but my argument here is that we've over
00:07:34.319 corrected
00:07:36.000 that we've gone too far in the other
00:07:37.500 direction and we are too defensive about
00:07:39.360 the things that Ruby can do
00:07:42.000 and
00:07:43.259 as I have put together this talk as I've
00:07:45.360 been working on this talk over time I
00:07:47.400 have like felt this tension in myself as
00:07:50.580 to how I want to present this like do I
00:07:52.560 want to come out be like the hot takes
00:07:54.240 guy and be like meta program everything
00:07:56.039 better program all the things and just
00:07:57.960 like scorched Earth and everything
00:07:59.520 everything minor programming is the best
00:08:01.139 everything else is the worst or my like
00:08:04.560 other my more my other instinct is to
00:08:07.380 like be defensive and put everything in
00:08:10.080 maybes don't talk about the weird stuff
00:08:11.940 too loudly the other languages might
00:08:13.500 hear you uh you know maybe this stuff is
00:08:17.280 better sometimes like
00:08:19.400 and so I understand I feel this tension
00:08:22.259 in myself and I don't I don't really
00:08:24.120 like it honestly
00:08:26.099 um but I want to talk about it uh and I
00:08:28.560 want to talk about where uh what ruby
00:08:31.500 what these things that Ruby does well
00:08:33.839 are really is really good for and when
00:08:35.520 they can really be used super
00:08:37.020 effectively within your code base so to
00:08:40.320 put this kind of another way or to talk
00:08:42.180 about the way that Ruby's perceived this
00:08:44.700 completely to scale deeply thought out
00:08:46.680 very well researched chart suggests that
00:08:50.519 there is a small group of things that is
00:08:53.040 sort of encouraged in Java and for Java
00:08:55.500 say any sort of enterprising language or
00:08:57.540 tool set doesn't really matter there's a
00:08:59.880 small there's a subset of things that
00:09:01.380 are encouraged there and there is a
00:09:02.940 larger set of things that is encouraged
00:09:04.620 in Ruby
00:09:06.019 and the attitude that I have experienced
00:09:08.519 sometimes over the years over the last
00:09:10.860 several years is the idea that because
00:09:15.120 Ruby allows all of those extra things
00:09:17.220 it's not serious you can't do serious
00:09:19.800 work in it and um once upon a time I was
00:09:23.820 doing uh training I used to do training
00:09:25.680 when I worked I worked at Groupon and I
00:09:27.240 used to do internal training training
00:09:28.680 and for for whatever reason I was
00:09:30.300 training developers in Ruby who were
00:09:32.880 never ever going to use Ruby but the
00:09:35.339 onboarding had them go through four days
00:09:37.320 of Ruby training which they loved and I
00:09:39.660 loved
00:09:40.800 um and I remember very clearly bringing
00:09:43.800 up string Inquirer or one of the really
00:09:45.420 magical Ruby stuff and having people
00:09:47.519 laugh and not in like the this is
00:09:49.740 delightful programmer happiness kind of
00:09:51.540 way but more in like the here's a nickel
00:09:53.700 kid let me know when you got a real job
00:09:55.080 you know kind of way uh and there's
00:09:57.600 there's this sort of sense that because
00:10:00.720 you can do these these very Dynamic
00:10:03.240 things that it is somehow preventing you
00:10:05.160 from being able to do real work in Ruby
00:10:06.779 unless we don't do those things
00:10:09.000 um there's sort of the related claim
00:10:10.920 that going outside that minor that
00:10:13.740 bubble only has costs and never has
00:10:17.160 benefits and you sometimes see this
00:10:19.140 specifically with static typing the
00:10:21.120 claim that being stricter is always is
00:10:22.920 good you will seem time to see like
00:10:25.620 advantages of static typing without
00:10:27.480 seeing a corresponding disadvantages of
00:10:29.700 static typing I refuse to believe that
00:10:32.459 of all the things in programming and
00:10:34.019 development that have trade-offs and
00:10:36.000 good things and bad things that static
00:10:38.100 typing and uh and not doing Dynamic
00:10:41.040 things is the only thing that has costs
00:10:43.620 and never has benefits
00:10:46.440 um so I want to say like let Ruby do
00:10:48.839 what ruby is good at
00:10:51.000 and what do I think Ruby is good at in
00:10:53.519 this context
00:10:54.600 Ruby is extremely good at managing a
00:10:57.660 certain kind of complexity
00:11:00.899 what do I mean by complexity
00:11:04.200 if you go back to that original code if
00:11:06.779 you can remember it from 10 minutes ago
00:11:09.060 if you go back and you look at this
00:11:11.700 this code is not structurally complex if
00:11:14.100 you run it through a computational
00:11:15.360 complexity analyzer which I did not do
00:11:17.940 uh
00:11:19.560 it will probably not score very high it
00:11:21.899 has no Loops the only conditional is
00:11:24.240 that is that case statement it has a
00:11:26.700 bunch of one-line methods it is
00:11:28.980 generally like on a line by line basis
00:11:32.040 this code is very easy to understand
00:11:35.160 at the same time this code is very
00:11:37.800 organizationally complex
00:11:40.500 there are several Concepts in this code
00:11:43.440 that are actually related
00:11:45.899 that this code makes no effort to
00:11:49.140 enforce that relationship right
00:11:52.019 so there's a class name there's a string
00:11:54.480 representation there's a class method
00:11:56.100 there's a predicate method and there is
00:11:57.720 the branch in the at in the uh in the at
00:12:00.180 statement and those things are all tied
00:12:02.220 to each other
00:12:03.420 they are all they all have a
00:12:05.220 relationship
00:12:06.360 but this code does not that code this
00:12:09.720 code leaves that relationship implicit
00:12:12.600 and my argument here is that that makes
00:12:15.600 the code more complicated over time if I
00:12:18.180 were to come in and I wanted to add a
00:12:20.220 new deployed status there's nothing
00:12:22.380 preventing me from making the class name
00:12:24.839 deployed class and the string
00:12:26.399 representation production uh production
00:12:29.339 and the predicate method deployed in
00:12:31.260 production question mark and all of that
00:12:32.820 stuff and over time that kind of
00:12:35.160 inconsistency can make this code base
00:12:37.440 very hard to work with even though it is
00:12:40.260 not like notionally complicated I forget
00:12:43.260 which one is complicated and which one
00:12:44.579 is complex I always get that wrong it's
00:12:46.980 it's neither in both right
00:12:49.019 uh over time
00:12:51.899 uh this code base just exposes a lot
00:12:56.100 more surface area of the domain to the
00:12:58.920 developer in a way that will I look my
00:13:02.639 claim here is in a way that will make it
00:13:04.079 harder to work with over time
00:13:07.200 so let's look at some other code
00:13:09.480 here's a way around this one way
00:13:12.800 this way in this case I'm not replacing
00:13:15.540 the subclasses the subclasses still
00:13:17.220 exist but I've got a list of all the
00:13:19.139 statuses on the top line there are a
00:13:20.760 list of strings
00:13:21.860 and then I'm looping over each of them
00:13:24.180 and I am converting each string to a
00:13:26.339 class using the rails constantize active
00:13:28.440 support method I'm defining the class
00:13:30.600 method the Creator method to create a
00:13:32.940 new method of that class I'm defining
00:13:34.320 the predicate method using Define method
00:13:36.120 I am defining the two string directly as
00:13:39.779 the string status and then I'm using the
00:13:41.639 app method and using send to define the
00:13:43.440 app method in terms of the other ones is
00:13:45.180 that clear clearish mud mostly
00:13:49.320 uh
00:13:50.519 there's another way so this this uh
00:13:54.060 unifies all of the concepts except the
00:13:56.760 relationship between the class name and
00:13:59.399 the status name but we can actually do a
00:14:01.320 little bit better in Ruby by using
00:14:03.180 Ruby's hook method uh this is a code
00:14:05.639 base this is a version of this code that
00:14:07.620 uses Ruby's hook method inherited if you
00:14:10.980 don't know what inherited does inherited
00:14:12.839 every time a subclass is loaded created
00:14:15.720 at load time it calls this inherited
00:14:18.420 hook of the parent class with the
00:14:20.160 subclass as an argument so every time I
00:14:23.519 Define one of those done sub done
00:14:25.380 statuses uh started statuses whatever
00:14:27.899 this inherited Hook is called and it
00:14:30.300 takes the subclass and it we we extract
00:14:33.600 out the string and we do the same we
00:14:35.160 create the same methods we create the
00:14:36.420 class method we create the string method
00:14:38.579 we create the predicate method and we
00:14:39.899 create the app method
00:14:42.839 so this actually unifies all five of
00:14:45.240 those Concepts in one piece of the code
00:14:46.740 if I want to create a deployed status
00:14:48.959 all I need to do is create a class
00:14:51.000 deployed status and make it a subclass
00:14:52.800 of status and everything else falls out
00:14:55.680 I get the I get the predicate method I
00:14:57.660 get the class method I get the two
00:14:58.980 string I get the at everything comes
00:15:00.720 together
00:15:01.560 okay now
00:15:03.180 code is clearly more complicated than
00:15:06.000 the original code or complex it's one of
00:15:07.740 the two
00:15:08.699 right if you look at this it's got I've
00:15:10.440 got a loop I've got some fairly Advanced
00:15:12.480 Ruby methods in terms of Define method
00:15:14.459 like you need to know you need to
00:15:16.199 understand I'm not shying away from the
00:15:18.240 fact that this requires this is a higher
00:15:20.279 bar to entry
00:15:21.540 piece of code
00:15:24.600 but at the same time
00:15:27.000 it has fewer independent Concepts from
00:15:29.519 the outside if I go to CR if I need to
00:15:31.980 create a new status I have much much
00:15:33.779 less work to do I have separated data
00:15:37.620 and logic in a particular way that they
00:15:40.139 had this set of structural data in terms
00:15:42.480 of what all of these statuses are and
00:15:45.899 all of this logic in terms of how those
00:15:47.579 statuses play out in the actual API of
00:15:49.920 the code and I've now separated them so
00:15:53.040 that adding a new status the whole API
00:15:56.399 falls out
00:15:58.320 this argues to me that there are at
00:16:00.420 least potentially costs here of not meta
00:16:03.300 programming there is this particular
00:16:04.980 kind of complexity that the not meta
00:16:06.899 programming solution has not pretty not
00:16:09.540 then the original solution is also more
00:16:11.459 lines of code more code to maintain
00:16:13.920 again not so much not even just for bugs
00:16:16.980 but for the kind of repetition or
00:16:18.720 inconsistency sorry but for the kind of
00:16:20.399 inconsistency that you might get if
00:16:22.860 people if developers after you know a
00:16:25.079 certain amount of time with developers
00:16:26.699 adding potentially new statuses or
00:16:29.040 whatever and I understand that the
00:16:30.839 individual logic in this case is simple
00:16:32.579 but if you sort of extract this to say
00:16:34.740 shipping costs or tax law against 50
00:16:37.920 states like you can see a case where
00:16:39.920 these these inconsistencies from
00:16:42.860 structure to structure could really
00:16:45.120 build up and that the meta programming
00:16:47.220 is a way to get them under under control
00:16:51.959 so
00:16:53.279 hopefully I have convinced you that this
00:16:55.560 is a reasonable use of meta programming
00:16:57.120 if I haven't I'm sorry we're going to
00:16:59.339 pertune we're going to assume as though
00:17:00.899 I have
00:17:02.160 um but I do want to talk about how to
00:17:03.660 convince your skeptical co-worker that
00:17:05.280 you can do this that this is a valid
00:17:06.959 thing to do in your code base
00:17:09.179 um
00:17:10.280 this is
00:17:12.179 outside of the this is not just a
00:17:14.100 technical problem uh and I think
00:17:15.959 understandably the first thing that you
00:17:17.640 need to do is really convince yourself
00:17:19.079 that it's a good idea and in this
00:17:21.419 particular kind of meta programming that
00:17:23.819 I'm talking about here uh we're talking
00:17:26.579 about answering a few questions in
00:17:28.319 advance like is the code structure
00:17:30.000 driven by external data that's true here
00:17:32.340 it's also true for things like active
00:17:34.679 record active records meta programming
00:17:37.080 to to unify database columns and
00:17:40.559 attributes does the same thing the code
00:17:42.600 structure is driven by internal data
00:17:44.360 rails routes does the same thing to
00:17:47.940 enforce consistency with meta
00:17:50.100 programming to enforce the consistency
00:17:51.480 of URL patterns to controller methods
00:17:54.299 like all of those things have structure
00:17:55.919 that's driven by external data and
00:17:57.780 therefore to my mind are really good
00:17:58.980 candidates for meta programming
00:18:01.440 um Can the magic enforce the kind of
00:18:04.380 consistency that you want in your code
00:18:07.080 um you know before rails had uh
00:18:09.059 resources you had a sort of a
00:18:11.880 free-for-all in terms of what the names
00:18:13.260 of the methods were in individual
00:18:14.520 controllers and it definitely added to
00:18:16.559 the complexity of working with a rails
00:18:18.360 code base
00:18:20.220 is the code easier to use from the
00:18:22.380 outside if you're the meta programming
00:18:24.240 version in this case the user a user of
00:18:26.640 status shouldn't care one way or another
00:18:28.020 but somebody who's working on status
00:18:29.580 it's probably easier to work with and
00:18:31.200 it's definitely easier to change or at
00:18:32.760 least to make a certain kind of change
00:18:35.280 so from there
00:18:37.380 when you're trying to convince somebody
00:18:38.760 I think who is skeptical of this I think
00:18:40.980 it helps to come in humbly and not hot
00:18:43.799 and not with the meta program all your
00:18:45.299 thing all the things waving your arms
00:18:47.700 um but to understand the concerns that
00:18:50.340 they that they will have and some of the
00:18:52.919 things that are really commonly raised
00:18:55.380 as concerns here are you know how do we
00:18:58.200 know it's going to be correct how do we
00:19:00.299 know that people are going to be able to
00:19:01.260 read this how will we be able to
00:19:03.419 discover it will our tooling work with
00:19:05.580 it will people be able to search for it
00:19:07.500 like that that is a real these are real
00:19:09.539 genuine concerns uh that I don't want to
00:19:13.559 minimize I think we want to be able to
00:19:15.660 mitigate them but you have to understand
00:19:16.919 you have to in order to affect this
00:19:19.620 change in your code base and to to get
00:19:21.539 yourself to the place where you can use
00:19:23.580 these tools effectively you have to be
00:19:25.620 able to talk about the trade-offs here
00:19:27.720 and to talk about these genuine concerns
00:19:29.700 of
00:19:30.660 you know readability findability and
00:19:33.120 that kinds of things
00:19:35.039 there's a specific case argument here
00:19:38.160 where
00:19:39.780 the abstraction is such that the
00:19:42.960 argument of I won't be able to search
00:19:44.640 for this thing becomes sort of invalid
00:19:46.500 because the meta programming abstraction
00:19:48.059 is such that you won't need to search
00:19:49.799 for that thing I don't really know how
00:19:52.080 rails handles attributes internally I
00:19:54.360 just know that it matches the database
00:19:55.980 table it's not something I need to
00:19:57.660 understand to be able to use a rails
00:19:59.280 class I think this is true in many cases
00:20:02.160 in my experience is a very very hard
00:20:04.320 argument to make to somebody who has not
00:20:06.240 used meta programmed this kind of meta
00:20:08.340 programming code before and is like very
00:20:10.799 comfortable with the abstractions that
00:20:12.240 already exists
00:20:13.740 um the under the the idea that uh the
00:20:17.340 program structure might make you not
00:20:19.500 have to think about a level of
00:20:21.000 abstraction I think is a very hard sell
00:20:23.580 the first time through
00:20:26.059 later cases you might be able to make
00:20:28.260 that case but the first time through I
00:20:29.640 find I think it's challenging
00:20:32.520 um testing is really important uh for a
00:20:34.799 couple of reasons number one obviously
00:20:36.120 it proves correctness but if you write
00:20:38.039 the tests to be examples it also helps
00:20:40.500 with the discoverability and readability
00:20:41.940 issues because you can point people to
00:20:44.100 the tests as examples of how to use the
00:20:46.320 code and of the range of the kind of
00:20:48.000 behaviors that you're meta programming
00:20:52.440 um you need to document it like this is
00:20:54.299 always true but is especially true if
00:20:56.220 you're meta programming and it is
00:20:57.419 especially true if you're a meta
00:20:58.679 programming uh to a group of people that
00:21:00.840 are less familiar with some of these
00:21:02.580 structure with some of these Ruby code
00:21:03.900 structures
00:21:05.700 um specifically if you're using Define
00:21:07.380 method you need to have a comment that
00:21:09.299 shows a sample version of the method so
00:21:11.820 I didn't include these obviously in the
00:21:13.260 sample code bases but you can show
00:21:15.419 here's here's the predicate method with
00:21:16.919 the sample version of the predicate of
00:21:18.840 the predicate method
00:21:20.580 um you know all of these comments will
00:21:21.960 make the code longer which is fine we're
00:21:24.179 not meta programming to play code golf
00:21:25.679 or meta programming to simplify the
00:21:27.480 amount of Concepts you need to keep in
00:21:28.799 your head in this case the documentation
00:21:30.720 will simplify that even further if you
00:21:33.179 do it right it will also it will also
00:21:35.840 excuse me it will also manage some of
00:21:39.000 the searchability constraints because
00:21:40.260 the comments will have some of the
00:21:41.460 search items in some cases you may have
00:21:44.340 to give up on some of the IDE uh ID
00:21:46.980 issues and that is a potential problem
00:21:49.500 especially if if you're used to static
00:21:52.320 languages and you're used to editor
00:21:53.760 support for static languages obviously
00:21:55.980 that's a loss here like we want to make
00:21:58.380 this simple enough that it overcomes
00:22:00.780 that that Gap but we you can't pretend
00:22:03.960 that that Gap doesn't exist
00:22:06.120 if you're using method missing you need
00:22:09.059 to have a parallel it with with rubies
00:22:10.980 respond to missing and again also have a
00:22:13.320 comment here's uh here's a version of
00:22:15.299 the method here's a version of that code
00:22:16.559 that uses method missing for the
00:22:17.820 predicate
00:22:19.140 um
00:22:20.220 and again has a has a sample version of
00:22:23.700 what uh a real version of this method
00:22:25.679 would be like
00:22:27.659 uh so you really do need to allow for
00:22:29.580 Discovery
00:22:30.840 um
00:22:31.620 it's it's a genuine concern that you
00:22:33.960 that we need to make need to mitigate
00:22:36.539 and also if you're introducing this
00:22:39.059 stuff into a code base
00:22:40.860 um especially a code base where people
00:22:43.080 might be skeptical about it you need to
00:22:44.700 be prepared to teach it you need to be
00:22:46.140 prepared to be the local expert on it
00:22:47.820 for a while and that means that you need
00:22:49.799 to be able you need to be comfortable
00:22:51.120 with explaining it to people you need to
00:22:52.919 be comfortable with pairing with people
00:22:54.179 you need to be comfortable with guiding
00:22:56.100 people to why it's the right thing to do
00:22:58.620 when it's the right thing to do when
00:22:59.880 it's not the right thing to do uh code
00:23:02.340 review that kind of stuff like if you're
00:23:03.960 if you if you are bringing this in to
00:23:06.419 some extent you're taking an expert role
00:23:08.400 our leadership role and and you need to
00:23:10.980 sort of own that
00:23:14.100 this can be fun it can be fun both to
00:23:16.860 use this code both to write this kind of
00:23:18.780 code which is like the strength and the
00:23:20.700 weakness of it like it's fun so we
00:23:22.380 sometimes do it too much but it's also
00:23:24.120 fun so we enjoy doing it and we enjoy
00:23:25.980 talking about it and you know like I
00:23:27.900 think it's worth remembering that this
00:23:31.380 can be fun and it should be fun on some
00:23:33.900 level
00:23:35.159 um this is so uh to summarize uh let
00:23:40.500 Ruby do what ruby is good at
00:23:42.659 meta programming is really good at
00:23:44.520 reducing a certain kind of complexity
00:23:46.320 particularly where you can cleanly
00:23:48.240 separate the structure of the code from
00:23:49.679 the data that's driving that structure
00:23:51.860 stricter is not always better sometimes
00:23:54.659 it is just stricter
00:23:57.419 um I have talked extremely fast because
00:23:58.919 I did this about 10 faster than I
00:24:00.840 expected to but I have a couple uh I
00:24:04.100 therefore I get the promise
00:24:05.760 self-promotion uh this is uh version
00:24:09.000 five of the pickaxe book programming
00:24:10.860 Ruby uh it is available now in ebook
00:24:14.039 form for all of your favorite ebook
00:24:15.659 formats uh it is about two-thirds of the
00:24:18.840 way done you can get it at that URL and
00:24:21.240 with that coupon code the coupon code is
00:24:23.039 good I am told through mid-December
00:24:24.780 through December 15th so you don't need
00:24:27.600 to go out and rush and do this right now
00:24:30.179 um but and it's not like we're going to
00:24:31.860 run out of ebooks so uh uh you know you
00:24:35.760 have you have time on that uh the book's
00:24:37.620 about two-thirds done there should be a
00:24:39.240 print copy coming I would imagine spring
00:24:41.580 I'm hoping April we'll see how that goes
00:24:44.100 there's a lot of logistics involved in
00:24:45.480 that that I don't control uh my name is
00:24:47.880 Noel Rappin you can find me on Twitter
00:24:49.740 at Noel rap and on Mastodon at Knoll rap
00:24:52.260 Ruby social Ruby social normapin.com is
00:24:55.740 uh uh we can find my blog you can sign
00:24:58.440 up for a newsletter the newsletter is
00:24:59.820 sadly dormant right now because every
00:25:01.140 time I try to cite something from the
00:25:02.400 newsletter my brain says why aren't you
00:25:04.020 working on the book
00:25:05.640 um but once the book is done it should
00:25:07.080 come back I work at chime Financial
00:25:09.419 thank thank you to time for sponsoring
00:25:12.000 uh both this conference and my uh trip
00:25:14.340 here thank you all for coming out and
00:25:16.440 being a part of this community thank you
00:25:17.880 to the organizers and the people who
00:25:20.039 make all of this happen and thank you
00:25:22.080 for your time
00:25:26.700 foreign