 So, before we get too far, I just want to take the opportunity to set kind of the expectation because if you've been to one of my talks before, they tend to be quite interactive. This is not going to be as interactive, and I had sent out a tweet if you wanted to have a chance to read through it real fast, but basically it's a primer of just what to expect from this talk, because I know there's a bunch of other talks that are happening. Not that I don't think this is a wonderful talk. This is basically a walk-through of how to extract small libraries, put them into Ruby Gems, encapsulate them, and publish them. So if you feel like it's still suited for you, if you've done a lot of gem publishing before, this is probably going to be a little bit too cursory for you, but if this is something you really want to learn and so forth, then it's going to be perfect and ideal. But I just want to say that I'm not going to be offended at all if you're like, yeah, maybe. Yeah, thank you. First candidates. Yeah, I'm not going to be offended whatsoever because I totally understand all this is going to be recorded anyway, so. Oh, I'm going. Okay, so my name is Adam Cuppey. I am a principal at this consultancy, we're a web and mobile consultancy called Zeal. We're actually based in Oregon, so on the other side of the planet, in a very smallish town. But anyway, so we kind of specialize in a lot of the stuff I'm talking about. We do work for hire, so if you have any companies that would really like some training or just some development of some kind, we would love to work with you. But if not, totally cool. My Twitter profile is on here as well. Please feel free to tweet at me. I absolutely love working with people, especially helping educate and fill in the gaps. The next thing I'm going to ask is that we are really spread out. I'm going to ask that you actually come forward. There is a ton of chairs, so come forward. There's a lot of space right here, there's space over there. Don't be shy. We are all friends, hopefully. Come on forward, yeah. Wondrous. The other thing I'm going to say is, and I say this a lot during the talks too, is everything you see is going to be published online. So don't feel like you have to take copious notes. In fact, it's much easier for a presenter, just so you know, when we see eyeballs instead of Apple logos. So just kind of keep that in mind that 100% of what you see is going to be available online. Of course, this talk is going to be recorded, so you can always reference back to it later, but please feel free to engage. If you have questions during the talk, just keep a mental note of it, because I'm more than happy to answer those. Like I said, you can find me on the Interwebs. I'm on GitHub at A-Cuppie. All of this stuff, all of the code you're about to see has been published either under my name or under Coding Zeal, so you'll find it all there. Then my Twitter profile, I just spelled my whole name out there. But anyway, by all means feel free to tweet like crazy. And then, like I also said, this is going to be available on SpeakerDeck. I'm going to publish it here within the next half hour or so after this talk is completed. Once I figure out what areas of the talk didn't work and I will remove them. All right, so here's what this talk is. Is it is affectionately titled Plucket, which is about extracting micro libraries and building Ruby gems. So this track is about less code. And so this is done in conjunction with that, that more specifically, throughout our time as a consultancy and my time as a Ruby engineer, we found that there's a lot of really awesome opportunities to pull out gems that are less than 100 lines of code. They don't need to be big at all. And it's really beneficial for a multitude of reasons that I'll get into later. But this talk is focusing around those two things. But here's what we're going to do is we're going to start with a basic Rails app. Now, I know this is RubyConf, so please forgive me. You can throw food at me later. But the reality is that even though I'm utilizing a Rails app, I want to point out the fact that this can actually be a Sinatra app, Lotus now, which is a cool framework that's, I think there's a talk on that this time, this RubyConf, Volt. Any framework or any Ruby library that you're utilizing that can tap into Ruby gems, which is basically all of them, can take advantage of this. Just in this example, I'm going to use a Rails app. So like most Rails apps, we have a models directory. And inside the models directory, we have a couple of models. This is generally where we're going to find source material for extracting microlibraries. Oftentimes, microlibraries center around services of some kind. It might be some sort of factory or builder code library that you might utilize. But this is really where we're going to find a lot of this stuff. Another place that you're going to find it often, we're not going to refer to that here, is inside your controllers. So especially inside of controller code where you're handling interactions, it's very likely they're going to have a lot of duplication. And there's a huge opportunity to extract microlibraries out of that, too. If we take a closer look at, let's say, an example user model, we have this just kind of basic functionality that's baked into here. You're going to notice that it just handles a, there's an attribute on the user model that is to pull a gravatar URL, right? And so just to walk through the code very briefly, we've got this constant that specifies effectively like a URL template. This is the gravatar URL from their documentation. We've got this built in at the very end of that string. You see that there's the ability to put in a hash value that represents the user's token. We've got a gravatar URL public method on the object that we can use. And then we're going to, if you just see, we're just going to build out that URL and return that back, right? It's really pretty basic. And then we have this privatized method that is baked into the user object that hashes, that creates a hash, a hex value of that hash email address for the user. So it's really pretty small, right? But here's the thing. How many, raise your hand if you're familiar with the single responsibility principle. Excellent, right? So basically that's what we're talking about as being problematic here. And so this is a big no, right? We're effectively taking some functionality that seems trivial, yet we're placing it inside the responsibility of an object that doesn't really care about how that URL is built. It just needs to know that it can be, right? So this is a little problematic. So pretty much a common pattern is that we're going to then start to extract this and maybe put this into its own class. And what we might do to do that is we might open up the lib directory and create a new class in the lib directory. It's maybe called gravatar. And then we're going to move what is affectionately the code from the user object right into this new class. Very basic, really kind of small. And maybe we want to build this out, maybe add some features that support different sized gravatars and so forth. But that's effectively what we could do very easily with this code. Then if we look back at our user model, we just start to reutilize this and it can be really helpful, right? So we require in, we just inject that requirement for the gravatar and then we just simply replace the functionality that we have inside of that attribute reader to call to the gravatar library that we made. So this is a good and simple fix for that, right? So this is very common. We'll see this a lot of times, especially in Rails applications. And we do this a fair amount that whenever you have a library of code or functionality that's essentially agnostic to the application itself or the domain, it is often a really good idea to extract that out so that you can control that a little bit more and you can build in some testing around it that does not interact with the user model. If you're familiar or if you've done a lot of testing, especially with ActiveRecord and testing ActiveRecord objects, this is really a problem real fast, right? Because we can easily in our test suite start to test things that aren't necessary and then we slow down this gravatar functionality and our test suite as a whole, so. But then we kind of open up to this question. And this is the convening question of ultimately this talk, and it's this. How many times, and I'll throw this out as actually a question, how many times have you written the same small bits of code over and over and thought, if this was only big enough to create a gem with it? Has anyone ever done that? Totally. And then what happens is there's a little bit of a problem, right? Which is like, well, in this little bit of code, let's talk about our gravatar little class here for a second is. What we often find happens is that we end up just maybe creating a single file gist of some kind, right? I mean, have you ever done that, like one file that you just kind of like reference back to, and you're like, I'm gonna copy this into my code base, you know, something like that? Or we start to pass it around, right? I mean, we work on a dozen or more applications in a given period of time. And there's a lot of code that isn't shared but is common amongst them. And so either we rewrite it again or we like, hey, open up that code again and don't tell anybody you did it and you snag it a little bit. Let's pull anything out that's critical and go again. Right, none of that works. The other thing is, what do you do about updates, right? How many of you have written code that is now in production? You lose control of the application that it was on and you find a huge bug in it. You ever done that? Totally, it happens all the time, right? I mean, you write this code, it gets into the code base, you're like, whoa. And then you've got to go back and try and fix it. I mean, it can be really problematic. And especially in our world where we are a consultancy, where we work with other companies, it is very likely it's actually inevitable that eventually we're going to lose access to that code base. And so what do we do now? There's not an easy way for us to add in updates to that without the clunkiness of communicating that to the team. So let's talk about the common solution to that. One of those problems is RubyGems. So as many of you, raise your hand if you're intimately familiar with what RubyGems are. Totally, everybody is. Now, why is that? Because basically any project these days that utilizes external libraries will utilize RubyGems to collect those dependencies into the application itself. I mean, basically all of them. Now, for those of you who may not be very familiar with what RubyGems are, I can give you a very simple explanation. And basically, a RubyGem is just a package. And RubyGems, as a utility, is a package manager, right? And rubygems.org, which is the website we're looking at right here, is a resource, a collection of, as you can see, what, six billion? Or no, no, no, how many different, yeah, I mean, just a multitude of gems and downloads that have occurred, right? So this is an incredible resource to be able to access public gems. So, effectively, darn near open source entirely resources. Now, that may not always be the case. I don't know if you know this, but you can create privatized gems that, and you can use them in privatized servers so that you don't have to expose maybe some critical or intellectually protected material, but RubyGems is a great resource just in general. Now, this is what's really common, is that with RubyGem specifically is that we often don't really know what's going on under the hood, like what's actually happening. And again, going back to how many times have you written code, very small bits of code that ultimately you're like, I wish if it was only big enough, right? It was only big enough for me to make it into something more. And the reality is, is that it doesn't have to be any more than a single file, right? Because a RubyGem is, just remember this. It is a very simple package of files, that's it. It's a self-contained collection of one or more files. The operative here is one or more, and it only needs a single file. In fact, I'm gonna show you here in a minute when we generate the gem, that it actually only puts in the equivalent of like one file. And you can actually build the gem in its default state on that single file, and it will totally work, right? Now, part of the magic under the hood, and you may not know this, with RubyGems is that one of the key functions that it has is that it pre-pends to the load path of your lib directory, or it pre-pends to the load path for your Ruby application, the lib directory of the gem itself, right? So that, remember the example where we had the require statement that added in the gravatar lib? You can do the same because it is appended to the load path, the lib directory of the gem, and it's kind of encapsulated form. So that's part of the magic under the hood that allows it to do what it does. But other than that, it's really not doing a whole lot, other than there's some sort of sugar on top, but that's about it. Now, for those of you who might not be familiar, that this is a utility that generally is synonymous, goes hand in hand with RubyGems, and that is bundler. Even though they work in harmony pretty much 100% of the time, they are actually two separate things. Where RubyGems is a package manager, what bundler is, is bundler is a dependency manager, right? So as you know, every RubyGem is versioned. One rails, 4.2 point, whatever, right? Soon to be 5.0 or rake, one point, blah, blah, blah, blah, blah, or 10 point, excuse me, right? So all of them are versioned well oftentimes, as you can imagine, you've got different versions that are dependent on one another. Well, bundler helps manage those dependencies. Before bundler became mainstream, when we were working on apps in Rails 2, for example, you'd have to manually run gem install, such and such, with a version number, and you had to manage those dependencies, and it was the most serious pain in the ass possible. It was horrible, right? And especially if you had a wrong patch number, and it just caused issues, and then if you had a multitude of servers out there, it was just a real pain. Well, bundler effectively solved all of that. And what most of us are accustomed to when we interact with RubyGems in the context of our application is actually through bundler. What we think of as RubyGems is actually bundler functionality. RubyGems is just the package side of it. The interaction side is what we're most accustomed to. And more specifically, we're probably pretty accustomed to this file, which is a gem file. This is just a sample gem file that's extracted out of the Rails app we're just talking about. And this is, in essence, a dependency manifest, right? So it's saying that in context with this application, we need to have Rails version 4.2.4, the PGGems, Ass Rails, so on and so forth. And even down to the groupings, you see about line 15, where it's talking about the development versus test groups. This is all functionality that's built surrounding bundler specifically, okay? And when we run the bundle command, bundle install as an example, or just straight bundle, we generally will see an output like this, right? Where we see that it's utilizing these gems and these versions. And this is coming from the manifest that is the dependency manifest that is that gem file, right? But this is all that's happening is bundler is managing the dependencies and then it's reaching out to the remote resources which more often than not is rubygems.org and it's API and it's pulling those dependencies in. So to give a little bit of a visual to this, I'm gonna kinda show you very, very simply what this sort of looks like, right? So we start with rubygems.org, which is a resource that has these gem packages, right? So we have Rails 4.2, maybe RSpec Core, whatever it happens to be, right? And then like I mentioned before, you may have a private gem server as well, where you have non-public gems, right? Totally separate resources. And within the gem file, we specify what goes where and what's attached to where, right? Where to look for this information. And then we have our applications bundle, right? And the bundle of gems that, and the dependencies that it requires. So when we run bundle install, what it's gonna do is like I said, it's gonna go out, it's gonna pull those gems and it's gonna pull it into, pull it down locally and it's going to inject that, binding in the proper paths and so forth, and it's gonna pull it into the application itself. Once that process is done, it no longer needs to communicate with rubygems. So that's basically a one-time deal. Now you can do this process prior to deployment and in many situations, it's actually a smart idea to do that so that you never have to rely on your production or staging instances to actually reach out for any reason. They actually, it's just totally self-contained. It's encapsulated in one effectively application bundle and it goes from there. Okay. So that is the explanation of, from a high level, what's happening, right? But let's get down to the less code part and what that relates to and just give some examples. So when I started this talk, there was an example that has been one of the most helpful and a huge shout out to James Edward Gray. He was, he curated this entire track and it was incredibly helpful in identifying some holes in some kind of theories around this topic, but also this actual gem itself, he contributed greatly to. So huge massive appreciation and thank you to him. So if we look a little closer at this class, we've got just a simple page class and this is not the exact example, but this is pretty close to where this came from. So it's just a basic active record model and there was a method, a public method on it basically this diff method and effectively what it was doing was it was finding the differences between hashes, the original hash representation of the page object itself and comparing that to a modified version and in context what it was for was to determine like, oh, what has changed and more specifically, we wanna update the two and report that out to a different process just so that it could be visually seen or post-process in some way. So we had again this public method and if you look down below right around line 12, relative line one, there was all of this functionality that had been added in or all this implementation detail to do that work. So it's passing into hash representations, it's parsing those, comparing those, doing all this sort of stuff and the bottom line is that it had nothing to do with the page itself. Like other than they were related, ultimately there was no real dependence on one another. So this is a perfect example, this is a great sign that we can pull this out and extract this into something else. But also this example specifically is something that we were finding ourselves doing at various times in various ways. Especially with the use of a lot of front end applications and the exchange of JSON data which ultimately we're using hashes to compare. This became something that was like, well heck we can use this in a multitude of places but like I said in the beginning it was small enough, like it's not a lot of code. I mean we're talking about like 60 lines maybe. It just was not a lot and that was something that was like well Ruby gems are like big and we don't need like all of that stuff right. So we didn't but then we were like, well we wanna share it so let's give it a whirl and see what it's like. So I'll walk you through our process. So this is the process now of how to take those little blocks of code and fairly rapidly convert that into a Ruby gem that you can publish, get out in the world and utilize. So step by step. So the first thing is is that Bundler itself actually has a really nice utility baked into the Bundler library that will generate effectively a gem template. You do not need to utilize Bundler to do this but there's a compelling enough reason to use it because it includes all the right files, it includes all the right detail and templated data inside those files and it's kind of a why not sort of scenario. So in this example we're gonna run the command bundle gem and then the next argument after gem is the whatever you're gonna call it. So hash diff was the name of the gem that we're gonna utilize, okay. And then include the flag test. Now you can see the files that were generated so I'm gonna point out only a few of these. So one of them if you notice right here is that it's actually gonna create a lib directory inside of the hash diff gem and it's gonna pop in two files. The hash diff file which we're ultimately gonna use as a form of a manifest and I'll show you that here in a minute and it also sets up a namespace for our gem. And then the second is a version file. The version file is obviously very critical because as we version our gem it's going to utilize that version to track what version you're on, right. That's how versioning works, right. The next thing that I'm gonna point out is it generates a bunch of kind of text readme markdown files. The readme file is, a lot of this is sort of tailored I guess you could say to use case on GitHub but again it doesn't have to be there. You could use Bitbucket or something other than that. But it generates a templated readme file and it quite literally puts in place like to do, right, how you use this. Like it puts all that detail in there. There's a newer addition which is the second item on the list which is a code of conduct file. You can modify it if you like, you can exclude it if you like but it's kind of, I think it's very telling of the trend right now especially in the Ruby industry to be really mindful of that and I think that's very cool. So I just wanted to point that out. And then it also includes a default license which the default is the MIT license. Again, something you could remove, modify however you like. And then the last bit is this test flag I think is very important because what it includes is it will include a Travis CI YAML file as well as spec, specifically R spec related files. So it creates the spec directory, creates a spec helper and then it creates a default spec for that hash diff file. And if you run the spec at this state, it will intentionally fail which is good because there's nothing there to pass, right? Now I wanna point out that all of this is controllable via configuration flags like that test flag that's in there, you could exclude that and it will not include test related implementation. It will, there's a code of conduct one you could remove, you could do all of that, even get. You'll even notice that, I didn't point this out but it initializes a default get repository as see that as the very last line. You could even exclude that if you like. So this builder is incredibly helpful to just create the default gem and I highly recommend that you use it for everything. But here's the important thing to remember and I go back to this, is that it's just a collection of files. That's all that's happening here, right? That's all that this is. Now something that's not in this example but is very helpful is some of the other things that you can use to configure is you can configure things like some sort of executable if you'd like, right? That you could utilize for, we see them all the time like the RSpec executable for example is just a part of this as well, right? So that could be included in here. But I wanna point out that this is probably the most helpful resource if you wanna figure out what you can and can't do. If you just use help like many executables if you put help before the command that you wanna utilize it'll give you a really great breakdown of what you can and can't do. Okay, so let's actually walk through what this creates and how we're gonna make this change. So the first thing I'm gonna point out is this default file in the lib directory. And again, it's kind of a great template. So the first thing it's gonna do is require the hashdiff version file. Makes a lot of sense why we do that because it's gonna need that. And then it sets up a module for our hashdiff gem. This is another kind of nice little byproduct. So let's take that gravitar example that I pointed out just a little bit ago. What if we're utilizing another gem that has a conflicting class? Well, we obviously run into a problem. So this is kind of an encouragement pattern to say hey, make sure that your gem is actually scoped to itself. So that if you wanna create classes and so forth like this is just kind of a natural byproduct of utilizing all of this tool, right? If we take a look at the version file, like I mentioned, it kind of makes sense what it's gonna do but this is an important file to make sure that you don't remove because again we need to track the versions that exist. And more specifically, our gem is gonna be tracking this version constant within the default namespace or this module that we have. So you can't move it without making other changes. It can be moved but there's no real, I don't think there's an overly compelling reason to do that. Another thing to note is that it's gonna, it's going to follow semantic versioning. So this is also quite important and just to see that. Okay, now we're gonna start to make our changes, right? So here's what those changes started to look like. So we just go into that lib directory that I pointed out before. There is a sub folder in that lib directory that is hash diff, right? This is a common pattern to include a hash or include effectively a manifest file which is this file back there, right? We can treat it like that, like a manifest, okay? And inside that sub directory we're gonna include the classes that are oriented to our code, right? So again, we're gonna utilize the module that we have, that hash diff module. And in this situation we have a class called a comparison class and it has an initializer and you can just see just that what we've ultimately done is we've been able to really encapsulate the code that came from that other source inside of our gem, right? The other nice thing is that this really helps us follow better patterns and practices. So if you can recall in that page, the page model that we had before, there was, we had a left and a right attribute, right? That were actually being injected inside of the find differences method, right? Well, now we can follow a better pattern and we can say, well, we're gonna introduce this comparison object and we're gonna actually pass that into the initializer. And anyway, it just encourages that we think differently about the code that we're utilizing and we take it out of the context of its parent domain and the domain being the page or the user or whatever that happens to be. So this is another great byproduct of that. So we've put in all of our code, right? This is pretty important. I wanna say don't forget your tests. Been there, done that and failed miserably at it to exclude that really important little bit. And so, okay, so we've done all that. We've put in our classes and our specs and so forth. And then our last steps to publish our gem is number one, we're gonna run our tests. And this is kind of an important thing to note that you're gonna run this in the contact, you're gonna run rake or your spec runner in the context of the gem itself. Seen this a few times before where, you know, in the process of it, we forget that, no, no, no, no. When you generate your gem, your gem is a totally separate thing from your application. So don't accidentally generate your gem inside of your application somewhere. No, that's not the intention. They're actually two separate libraries, right? So when you're running your test suite, you're running it on your gem and not your application itself. Now, another kind of nice added benefit is that the default rake file inside of the gem itself, the default task is to run your test suite. So all we have to do is run rake. This is a good, I think this is a good pattern in practice in general, but it's totally reinforced in here too. So in this example, you can see we're just utilizing rake. It's running all our tests. We have 10 examples and no failures. Big win, big win. Okay, so very last things we have to do. Second to last thing is that we have to make some modifications to a file called whatever the name of the gem is, dot gem spec. And basically this is the specification manifest effectively of what is the details for this gem. So what is, like you're gonna see here, what's the name of the gem? This, you're gonna see relative line five, little ways up, that the version of it, this is where that constant gets passed in. Like I said, there's no real reason to change that, but if you were to change it for some reason, this is where you could do that. I've just changed the reference to a different constant. You specify authors for this gem, email addresses, and then there's two that are the description and summary. These get utilized. You'll see this in a moment on rubygems.org to explain what this whole thing is. What's really cool about this, in my opinion, is that it means that 100% of what this gem is about and does in the documentation and all of that, all of that is encapsulated in the gem itself. And rubygems is gonna pull that data out of it. Instead of you having to go back to rubygems and manually updating the site or something along those lines. So those could theoretically get out of sync. So we are avoiding that. Then pointing out a couple last things. So the homepage, in this example, we're pointing to the GitHub source code, but you could point to anywhere you want, maybe a more detailed, like some sort of docs or something of the kind. And then of course we've got some other files in here that are being generated, right? Now I wanna point out one important thing is you're gonna notice at the very bottom of this gem spec is that there is use of development dependencies. So you're gonna see that inside the gem file because it generates one for this gem that there's this note and this reference to the gem spec. So this is the only real important difference and it's kind of ironic, in my opinion, that ironically you're gonna use a different manifest for your dependencies than the one that is really designed to be built around gems. But you're not gonna want to, there's a few exceptions in this, go online to see the exceptions, but by and large you're not going to put your dependencies inside the gem file for the gem itself, right? That's actually going to be placed inside of the gem spec, right, at the very bottom. Okay, and similarly it's gonna squawk when there are issues, so that's kinda nice. Now, to note, you're still gonna run bundle install. So the reference to gem spec in the gem file, so it's just gonna simply tell bundler when it's running and trying to pull out the dependencies to, hey, look over there. So you're still gonna run bundler, bundle install, you're gonna do the exact same process, just know that this is where you're gonna put your dependencies. And I also wanna note that these were all dynamically injected, so again, part of the advantage of utilizing the template. Okay, so we've got our very minimal amount of code, very small code, we've wrapped it up into the gem and so forth, so what's the next steps? Well, there's really only two more, which is really pretty quick. So the first one is we're gonna actually build the gem or the package itself. And it's very, very easy to do that. So we're gonna go directly to the gem, and then the next step is simply run the command gem build hashdiff.gem spec. Wanna point out this is not bundle gem build gem spec, this is actually the gem executable that you're running on, right? So this is baked into the library itself, right? And it generates this .gem file, which is the package. So from that point, we have only one step left, and that is just simply to push it up to RubyGems. Really quite easy. And so similarly, gem push, and then you're gonna push up whatever that gem file is and it's done. Then when you go visit rubygems.org, looks like that, right? It's really that simple. So we're gonna see a couple of important things. Like I said, it's gonna extract out of that gem spec all of that detail, right? So it's gonna utilize, you're gonna see the name of the gem up at the top, version number, current version number, the description that I pointed out before, it's gonna be listed in there. The other nice thing is it's gonna track various versions, dependencies, so on and so forth. But you're not gonna have to come here to edit anything, which is really kind of nice. And this becomes kind of like the default for the gem. But from that point, we can now utilize it inside of our code, right? Cause it's on RubyGems, it's usable. So first thing we're gonna do is go back to our application. So again, this is a Rails application. We're gonna add in the dependency that we're gonna utilize, right? To our gem file, so there's hashdiff and more specifically the version number we're gonna use. Then we're simply gonna run bundle install. Ah, look, I'm famous now. If you didn't know, the ZenSpider, he has created something close to like 100 different gems. So yeah, he's done some serious work. But anyway, so this is what we're now gonna see, is we're gonna say that it's installing our gem. And again, what's happening is exactly in that diagram before, is it's reaching out to the various remotes, it's grabbing those resources and their specific version numbers, it's pulling it back into the application and utilizing it. So even though you can make a reference inside your gem file to a local gem, which I did not cover at all and don't recommend in general, but you can, this is quite literally taking the gem, which may be local, reaching out to grab the version of it and pulling it back down and in, okay? Now once it's here, it's now on the local system and it's not gonna keep reaching out for that. So it's kinda nice. Now just to change the adjustments that we made, it's pretty simple, just like that gravitar example that I gave, right? So now we're gonna require the hash diff gem. Like I said, it's adding in that lib directory, the hash diff lib directory into the load path. So it's gonna know where to look when it's looking for that. And now we're gonna just simply replace that diffing functionality and it's that simple, right? There's not a lot more complexity to it. So this is a great way for us to basically have a big win in terms of being able to utilize this. And like I said before, so whenever you want to create a new release, right? You're gonna follow the very similar process, right? You're gonna modify your code. You're gonna increment the version constant. This is an important thing. You actually do have a new version now, right? We're gonna rebuild the gem via the same commands we utilized before. We're gonna publish the new version of that gem and then we're gonna update our apps. And it's really quite simple, right? It doesn't get too much more complicated than that. Okay, so bottom line is, is that there's a lot of pros and a lot of cons to utilizing this process and to walk through those really quickly. So the pros to doing this and taking it out of the lib directory, the pros to that are, one, you have great sense of isolation from your app code. I think this is a great thing. If you read the primer that I had thrown out there before that even though this is not a talk on monolith applications or single responsibility, I personally am a fan of it and I find that this is a great advantage to utilizing gems in a certain way, is that you have a great sense of isolation. The other is that you can now manage upgrades. This is a big win, right? So I can now increment to version 1.1 or 1.2 and the upgrade process is really easy. Now, like in our case where we're a dev shop, we can contact the CTOs or the engineering team and say, hey, just so you know this new version is out, we found a patch release and they can handle it on their own or make their own decisions. And then last, and I find this and the support that I got from James was totally a part of this and that is the community support. So this is a huge advantage of it. We have built a lot of our engineering careers on open source software. This is a great way to give back. You can do really small incremental things. Like you don't need to contribute our spec to the world or Rails to the world to be a great contributor. You can produce small code chunks. You can put those out into the world and you can get feedback on them and they can be greatly beneficial and helpful to everybody else in the industry, right? So keep that in mind, this is a big thing. So the thing, the last couple of things I wanna leave with is that, is this idea that extraction encourages isolation. Isolation encourages a simple interface. We talked about the simple interface before. And the greatest benefit is that a simple interface is far more maintainable, right? We have a much more ease of use. Now, the operative here is encourages. It doesn't mean it will happen all the time. In fact, a lot of the time it doesn't, but it encourages it. Now the cons, and this is a very fair list too. Keep in mind that now by introducing a gem, you now have another external dependency that you have to manage. Keep that in mind, right? If you wanna make a change to the code, it's not as easy as going like, oh, I'm now gonna change this word to that word and it's done, right? Which you can generally do in your applications. Well, to actually get it out in the wild, you gotta go through the whole build process again. Similarly, if you don't follow a good pattern of semantic versioning that can confuse people in the community that are utilizing the gem, so keep that in mind. That's a really important thing. And as a result of all of that, you inadvertently introduce a lot of additional development overhead, right? This is probably one of the arguments against doing this and keeping it in the lib directory is that I've now introduced a bunch of overhead that I now have to manage, and that's totally fair. In the gravatar example that I showed in the very beginning, I think that it's a totally fair argument to say that is not something that I'm gonna extract out into a gem right away. It's not maybe until I start to utilize it across many applications that I'd even consider that because of this overhead. And of course, community support can be a double-edged sword. There's a really great talk by Justin Searles who talks about the contracts, like an open-source contract and the relationship that exists. It's totally worth listening to and watching because he speaks specifically to the challenges of being an open-source contributor and maintainer, and the challenges of interacting with the community that can be positively and negatively supportive. So keep that in mind that the community support is a double-edged sword. And then the last thing is this more fundamental question which is, when is it the right time? When is the marker in time in which I go, yes, now is the best opportunity to do this? And I can boil it down to just simply this. It's when the cost of maintaining an internal library exceeds the cost of maintaining an external dependency, when those two relate. Oftentimes I've found that when you have multiple files at play, when they're becoming more and more intertwined, or more importantly, when the engineering team has to know too much about that particular library to be effective, and instead what we wanna do is say, no, no, no, that's not something that you need to worry about. Like that's, yes, currently it's a part of this application, but it doesn't need to be a part of the kind of domain knowledge that's at play. Then we can extract that out, we can maintain it separately, especially as a team, and it just keeps that isolated kind of like team dynamic going. And that I have found to be very, very helpful. Couple of gems I wanna point out that totally follow this pattern. So one of them is a Truman, and this is, check this out, this code I think is like 30 lines of code, it's a gem. And basically all this is, is this is a truthy and falsely values manager, and that's all it is. It's a very basic simple library. This was loosely extracted from some active support, active support. Anyway, some code that was written in there that managed like true is also the same as the integer one, is the same as the string one, is the same as... Right, and so this is a very, very small gem, which we're taking a look at just to see that you can make them very, very small. And then I did in fact convert that hex, a gravitar hex generator into this really cute gem called gravosaurus hex. And again, it's super small, it's like 20 lines of code, but I found it actually really helpful in generating the talk. Like it was like, oh cool, it does work that easily. So this is another example. And then the one that we just went over, which is hash diff. This is actually, if you deal with a lot of diffing of hashes, I highly encourage you to actually check this gem out, especially if it can be very helpful, but also totally open to community support and contributions. I would love to hear any thoughts, contribute back to it, so on and so forth. And then the last thing I'm gonna point out is that there is a great guides on rubygems.org that walks through in fantastic detail, step by step process on how to do everything I just said times 10. And there you have it. Like I said, you can find me online. Feel free to find me on GitHub and then tweet the heck out of me. I'd love to hear from, get feedback. Good, positive. I mean, I wanna know if this went well for you, but also if you have any questions at all, I am an open book and I'm more than happy to help. Well, there you have it, ladies and gents. My gem, my name is Adam Cuppey. I hope you learned a lot from this. Is there any questions before we go? What is my recommendation for private gems? So there's a bunch of different services out there that are great because they actually, they effectively are a rubygems, but they go through a process, they require authentication first. I haven't used a lot of them as of late, but you can definitely go online and find them. Other ways to do that if you need more of an ad hoc solution to it is actually to mount the gem from a local directory that is encapsulated in the application. Don't know if I would advise that all of the time, but it is a way to handle that so that in essence you can mount it from a subdirectory that's like, okay, I'm gonna utilize this and then effectively disregard that directory when it's done. I don't love that by any means, but so probably the better solution is to actually go towards a gem server that allows for authentication first. Anyone else? Sweet. Well, I'm glad. I hope you had a good chance. I hope you learned something. Other than that, have a really good rest of the conference. I'm glad I could be your number one for this other than the keynotes. All right, thank you.