Wednesday, October 05, 2016

RubyConf 2015 - Seven Habits of Highly Effective Gems by Mat Brown

] Alright, what's up everyone.
How's it going?
So who among you has ever released a Gem?
Okay, good, I like it.
Okay who has released a popular ass Gem?
Like, tons of contributors, tons of users, tons of love?
Okay, alright so we wanna get from like group one,
and not group one, everyone into group two.
Okay, so that's what's we're gonna do today.
Before I get started, quick intro,
my name is Mat, what's going on?
If you wanna tweet insults, that's a zero.
I live in Brooklyn, looks like this,
I work for Genius, we're a platform for annotations.
One time John Resig used our platform it was really cool,
and here's my talk.
So, I'm gonna talk about seven specific things.
That are going to make your Gem more appealing,
it's to make your users happy.
Right, so your Gem should make users happy,
of course, this is a Ruby conference so,
we're gonna talk about first how to get
your users up and running quickly.
We'll talk about how to write really good documentation.
We'll talk about how to change your Gem
without causing your applications pain.
We'll talk about how to coexist with your users
applications environment, in a nice way.
We'll talk about how abstractions can lock people
in and how we can prevent that.
And we'll talk about how to make it easy
on your contributors by giving them
an easy to run test suite, by giving them
automatic feedback on their contributions.
So, I'm gonna start by talking about quick start.
So Sinatra, great Gem, really great micro
probably the best microframework I think,
Sinatra, really great Gem.
And take a look at this, the top
this is the top of the Sinatra readme.
This is the quick start, it's four lines long.
Which is amazing, there's four lines of Ruby.
And then you know, like the Gem install,
which doesn't even count, and one line
to type into your shell, and you're good to go.
And this is what we should all aspire to, right?
We need a quick start that's this easy.
And that's what as Ruby programmers we expect.
And we don't expect that because we're not smart,
or because we're lazy, we expect it because
we wanna spend our time building
beautiful, functional, wonderful products,
not installing things and configuring them.
Having a really short good quick start
is actually a feature of your code
not of your readme, right?
You can't write a short quick start
unless your Gem allows it
so how do we get to that point?
Well let's think about how we
we usually write a Gem, right?
So, probably what happens is I am
working on my application, I have
some code that I think, ah I should
open source this, this would be useful to some other people.
So I take the little bit of code out
and I you know create a new directory for my Gem
and I probably stick something like this
into my Gem file so that my application
points at the local version of the Gem
while I'm developing it.
And then I go on, you know I might
write some tests in my Gem,
might flesh out the interface a little bit
start writing documentation, and at some point
I'll probably go back to my application
and say okay well does this all still work
with this Gem that it's now pointing
at that I've been developing?
But what I've never done at this point
is actually feel what it's like to start
using the Gem from scratch.
To start it in an application that
doesn't use it already.
So something that's worked really well for me
is to just basically make a, like an example app.
Doesn't have to be a rails app,
whatever makes the most sense
for the problem that you're solving.
But make some sort of example app
and really think okay, if I wanted
to do this, if I wanted to use this,
for some plausible use case,
what does it feel like, what does it look like?
I have always found at least one pinpoint
that I can solve to make it easier to get started
using this technique so,
getting that quick start down is all about just
putting yourself in the position of a new user,
which is something that doesn't necessarily come natural.
now, once you got the user hooked,
once things are installed they want to learn more.
They want to be able to easily
find out everything that your gem has to offer.
So that's where documentation comes in.
And we're back to Sinatra.
Sinatra not only has a great quick start
but check this out.
If we start scrolling down,
like we're still in the Table of Contents right now.
Okay, still in the table of contents
and then finally this'll take about a minute
to get through the whole thing.
Sinatra has an incredibly long readme.
And that is a very very good thing.
So there is nowhere that is more discoverable
for documentation than the readme, right?
It's there front and center in Github,
it's there front and center when you
have generated code documentation,
it's there on airplanes, it's there
if you don't have the internet
because it comes with the gem when you install it.
So the readme is a really important place
to give, to lay out a full map
of what your Gem is capable of doing.
And in order to do that,
I recommend making the readme a part
of your development process just like say
testing is a part of your development process.
So you wouldn't, you wouldn't submit a poll request
or you wouldn't necessarily make a commit
with new code that doesn't have some new tests.
And you can take that a step further
and say I'm also going to submit
any time I add something new to my application
I'm also gonna add something new to the readme.
And you can take that a step further
and write the readme first.
So actually think about before you lay down
any tests or code think about how
how am I going to explain this to my users.
And you might end up writing a better interface
once you think about in that term
than those terms, then if you document after writing.
So the readme is really good it's really important.
Again, sort of every feature that your Gem has,
every major thing you can do with it,
I think should appear in the readme.
Very searchable, Command+F great tool.
But of course the readme can't be totally exhaustive.
The readme can't take you through
tons of examples of every method,
it can't take you through all the possible options
you can pass and that's what
inline code documentation is for.
So what we've got here is from Addressable.
Another great Gem, and Addressable is using
this param and return tag you can see here.
And that is not built into standard RDoc.
That is actually a documentation tool called YARD.
So that stands for Yay A Ruby Documenter.
And YARD adds a bunch of extra structure
to Ruby code documentation that isn't
in the built-in documentation for Ruby.
And what's nice about this is that
you know, Ruby doesn't have a lot of structure.
As a language you know, it's not statically typed.
Everything's mutable at runtime,
there's all this meta programming.
And that's great you know that's really good for us
as programmers, but it does make it difficult
to communicate the nuance of power code works
to users who are experiencing it for the first time.
So basically this is sort of the YARD tags
act as a counterpoint, which have a lot of structure.
That could really explicitly communicate
hey this is the type we're expecting here.
You know, there's no type enforcement,
but this is what we expect you to pass us
this is what we're gonna pass back to you.
And then it generates really nice
looking documentation like this.
So YARD has dozens of tags,
these are some of my favorites.
Of particular importance I would say,
the @api tag, so Ruby visibility we can do some
stuff with it but we can't say, make a class private.
So the @api tag allows us to say hey
this is not part of the public api very simply.
@deprecated is another good one.
Just one line and you can mark a method.
Don't use this if you're not already.
Two of my other favorites are @!attributes
and @!method, so, we like to meta program
and sometimes we define a method
in a sense by not actually defining the method.
So maybe we use def_delegator.
or activesupport delegation
or any number of other things.
Well that's not gonna automatically
show up in our code documentation
as being a method that somebody can call.
But we can tell YARD using this @!method,
pretend there's a method here
and I'm gonna document it for you
and then it just shows up as if it's
a method of the documentation.
So the effect is that YARD documentation
can actually be in a sense more authoritative
than your code itself, believe it or not.
So the other advantage of YARD,
kind of a freebie bonus type thing
is that is a site that hosts
for free documentation for Ruby projects.
It'll just pull the code off of GitHub
or out of a Gem and it uses YARD
so if you do you get this
extra benefit basically for nothing.
Okay so, your users are now fully able
to get started with and understand your code
but we wanna make sure also that your Gem
is not going to cause any unpleasant surprises.
So I should be able to do,
if I'm the user of your Gem I should be able
to do this without a great deal of fear.
And that means that I may be updating
to a new version of your Gem, I need
to know what sort of pain that could possibly cause.
And then ideally not feel any of that pain.
So the most basic way to communicate
that information very concisely
and in a way that is widely understood
is to use Semantic Versioning.
Semantic Versioning divides,
divides versions into three numbers
like most versions look like this.
Let's start from the back, so if I bump
that green number, if I bump it up
from Bugfix, or if I bump the Bugfix number
it's called a patch level, that's communicating
to my users that nothing outward-facing is changing.
So this is a Bugfix, it's a patch to the code
that maybe refactors it or makes it faster,
but there's no outward-facing change
so you've really nothing to worry about here.
Everybody upgrade at will, you're gonna get
some sort of invisible benefit,
but no outward-facing change.
The middle number, the minor version,
means I've added something.
But I've not changed anything that was already there.
And I've not removed anything that was already there.
So again, you are totally clear
to upgrade to say 4.3 here, as long,
you might not be able to downgrade
because that might mean the future goes away
but you can upgrade a minor version safely.
And finally the major version,
the red one, is a breaking change.
So any time you rename a method,
you get rid of a method,
you change the types of the arguments
that a method expects or the return value,
just anything where your Gem behaves differently
for existing, an existing public interface,
you gotta bump that major version.
But, my claim is that in fact
when we think about breaking changes,
we're often maybe thinking a little bit
too much about ourselves and not enough about our users.
So typically we wanna keep things nice and clean.
We realize that oh, there's a better way
to design this interface, and I wanna make
a beautiful interface for my users
so I'm gonna change the way this method works,
and maybe I'm just gonna get rid
of the old methods and write new ones.
Well that's nice for me, as the developer of the Gem,
but my users are almost certainly feeling more pain
having to go through their code
and change from my admittedly worse old interface
to my better new one than they would
just not having to change anything.
So I'm not saying don't make better interfaces
I'm saying don't get rid of the bad ones.
We can take some inspiration from Javascript here,
the language itself.
So ES6 is the newest version of the language
that's actually beginning to exist in the world.
And one of the things that they changed in ES6
was the scoping of variables.
So basically we're all used to declaring variables
with VAR, the scoping is kind of wack.
It doesn't respect stuff like for loops or if statements
although that's the same in Ruby.
But the point is they decided they don't like the way
variables are scoped, and so they wanted to change it.
Now they could've just changed it, right?
But that would've broken existing Javascript code.
And it would've meant that you needed to opt in
and say, and explicitly say I'm now in ES6 mode,
and so you can scope variables in the ES6 way
and that's a common understanding we have.
But instead thanks to this blog post
from a few years ago, and the idea of one Javascript.
Javascript community basically decided,
we are going to always support
every old version of Javascript.
In every future, sorry all old Javascript code
will be supported in every future version of Javascript.
The way they solved the VAR problem
is they just made a new keyword
for declaring variables that have
better scoping, which is let.
So now basically you're not supposed to use VAR,
you should never use VAR, it's deprecated.
I mean you can if you want, you'll always be able to.
But Javascript solved this problem
by dragging this crust along with it.
And so it is very crafty to have two different ways
of declaring a variable only one of which
you're actually supposed to use.
But, in the end they're doing a real service
to everyone who's written Javascript code to do date.
Because they're not breaking anyone's code.
So we can take some inspiration from that.
Sometimes you gotta make breaking changes
but probably not as often as you think.
Now let's think about the environment
that our Gem exists in right?
We're not gonna be the only library
that our users are using so, it's important
that we play nice in the larger environment.
We have at least one dependency ourselves,
which is Ruby, right?
So we depend on Ruby, we probably depend on some
Ruby version or we're compatible with certain Ruby versions.
And chances are we probably have one
or two Gems that we depend on.
Maybe we do maybe we don't.
But on average we do.
So it's important to think about
how tightly we're specifying what our dependencies are.
So this is something that we could
put in a gemspec, but that would be
a bit horrifying.
So essentially, an exact version of active_support.
That means if you wanna use a different version
of active support, and you wanna use my Gem,
you are out of luck.
And it's very unlikely that this is necessary
so you'd have to really really really not trust
the developers of active_support
to use semantic versioning and not
make random breaking changes to be justified
in using such an exact version constraint.
So we can get a little looser and we can say
okay well, any 4.2 will do as long as it's at least 4.2.4
but again, semantic versioning,
if we all agree on this it tells us
4.3 is fine, right, 4.3 will only add features
it won't remove or change them.
So what I can do is I can say
okay I'm now gonna depend on at least 4.2,
but any 4.x is okay, not I don't
know that 5 is gonna be okay.
I don't know what 5 is gonna have
and I know that 5 will break things
because that's the definition of being 5.
But I can at least, this is as far into the future
as I can look with my dependencies.
And still be safe knowing that my Gem
won't be broken by changing my dependencies.
So that's fine and now we're as future-proofed as we can get
but in fact, the truth is not everyone
is using active_support 4.2 right now.
So you're still saying, to your users
you have to be on the latest
version of Rails for this to work.
And it's unlikely that you really need to say that.
So for instance, 4.0's probably fine.
That's good, and maybe you have to do
a little bit of extra work to support 4.0,
but the truth of the matter is,
a lot of shops, a lot of applications
and projects aren't always able
to keep up with the latest versions of things all the time,
and so you're gonna make your users lives much easier
if you can be as loose as possible
about your version requirements.
And I would even say, you know,
if we're talking about Rails right now today,
it's likely you can do this.
Because things haven't changed that much
in active support between 3 and 4.
So do what you can to support as far back as is reasonable.
And that is far forward as you know something won't break.
And like I said before we, you know
even in this constraint we don't support
Rails 5, we don't support active_support 5.
So how can we know when that is a problem?
So I, I could release this today,
and that's fine, but then at some point
in the future Rails 5 is gonna come out,
and maybe I'm not totally totally paying attention
to that, and so I could suddenly
have a Gem that has dependencies that are locked in.
Happily, some kind soul or souls,
has created a service called Gemnasium.
Which will automatically audit your Gem's dependencies
and it will send you an email alert
if you are out of date now.
So here's the, here's part of the report
for the MULTI_JSON Gem, great Gem.
And Gemnasium makes it easy
it means you don't have to worry about it
you can be, you can respect the future,
because in the future you're gonna know right away
oh hey I gotta you know, try this out
with Rails 5 and see if anything's broken
and then bump the dependencies.
But that see if anything's broken,
that's kind of the hard part right,
I mean it's one thing to say I support
lots of different versions of the same dependency
but does it actually work?
So of course we want to run our tests.
Against all of the things we say we support
so all of the versions of Ruby we want to support,
all of the versions of other core dependencies
we want to support, stuff like Rails, Rack,
Event Machine, whatever it happens to be.
But particularly we want to be careful about these
very popular, very important Gems
that almost everyone's using.
And so Travis is a great tool to do that.
Travis is hosted continuous integration.
It will fill lines of configuration
and it's gonna run your Gem's test suite
against whatever Ruby versions you want.
Including jruby rubinius, it's not limited to MRI.
It will run it against a set of Gem files,
so you could have different Gem files,
different bundler Gem files that specify
different Gem dependencies, and you could
even have it just pick arbitrary environment variables
that your test suite understands.
So here you can see this devise ORM
it's a little hard to see but you can see this devise ORM
that devise is using to run it
against Mongoid and ActiveRecord.
So Travis is really nice, Travis is hosted,
Travis integrates really well with GitHub.
So when somebody makes a poll request
it will automatically put in that poll request
whether or not the test suite passed on Travis.
If you have it hooked up.
Of course you still might wanna run your test locally.
wwtd is a great Gem for doing that.
So that basically reads your Travis configuration,
and then does the same thing,
running the tests on your computer.
It'll use RBM, or RVM, or Ruby to do the different Rubys.
So that's very nice so now you have both the local copy
for when you're on airplanes and the cloud-hosted copy.
Now I mentioned just a minute ago
that Travis is really good at running
against different Gem files but you probably
don't wanna maintain a bunch of Gem files
by hand, so I recommend another tool
called Appraisal, which allows you
to just write one file that lists
all of the variants of your Gem dependencies
you wanna run against.
So for instance here, you've got
four different versions of ActiveRecord.
That are specific in the Appraisals
and this will actually generate
four different full Gem files
that you can then give to Travis.
So it just varies the part that you want to vary.
That is put that all together right,
you get the Appraisal Gem files,
put them into Travis, and you suddenly
have a very robust system for ensuring
that you actually support this stuff,
you say you support, and that when you change
a feature or change some internals,
you're not breaking it on any of the platforms you support.
So, that is dependencies, inversions,
and not breaking things.
There is a little code in this talk.
Here we go.
So let's think about social networks.
Two social networks you might be familiar
with are Twitter and Facebook.
There are great Gems for each of them.
So there's a Gem for talking to Twitter called Twitter,
and there's a Gem for talking to Facebook called Facebook.
And I want to talk about those Gems.
When we're thinking about designing public interfaces
so the public interface is the part that we
basically when we say we're not gonna break stuff
that's the stuff we're not gonna break.
Let's look at Twitter first, so,
if I wanna write a tweet,
this is the method I'm going to call.
So it's a method called update.
I pass it a string, that's the body of the tweet,
I can pass it some options if I want,
and that's really nice.
That is you know a fully nice
little wrapped up extraction for me.
But if I wanna poke my friend on Twitter
using the new Twitter poke feature
that begins to exist next week,
that is actually not something
that the Twitter Gem supports because it doesn't exist yet.
So in that case I might wanna go down
to a lower level, and in this case
I'm looking at the, looking at the
code for update, and I see that there's
this performer quest with object.
I'm sorry perform post with object.
And that looks like a nice level interface
so I can dig a little deeper
and get to this perfectly nice
generic perform request method.
And all this is doing is sending an authenticated
request on behalf of a particular user
to the Twitter API and kinda giving me a nice response.
So this is a much lower level thing
than that update method we were looking at a minute ago.
So this would be perfect, right?
I can make a poke request through
the using perform request here, except
this is not part of the Twitter Gem's
public API this is a private method.
So we kinda have this, call trace
that looks like this, we've got
a nice public update method to do
one specific thing, that the author
of the Twitter Gem expected that I would want to do.
And then we have some private methods
that are at decreasing levels of extractions.
Lower and lower, more generic,
less wrapped up and packaged up nicely.
But another way that one might think
of this kind of Gem when you're writing it,
is first I'm just gonna write a Gem
that lets me make authenticated requests
to Twitter without any real high level knowledge
of what the Twitter API, what the resources are,
what the endpoints are.
And in that case perform request would actually become
one of the main interfaces to that layer of the Gem.
And then, on top of that I would essentially
use my lower level library, which is fully
tested, has a public interface that's stable,
to write a nice high level bunch of code
and really the effort that must've
gone into this Gem is incredible.
Because it does support basically
everything you could do with the Twitter API
is explicity contemplated in this Gem.
I can go crazy like that.
So this is sometimes referred to as a layered architecture.
Another way to think of it is essentially,
I'm eating my own dog food but I'm also
just letting you have the dog food if you want.
So dog or dog food.
Either way.
That makes perfect sense.
Another way I might choose to approach
this problem though is to think, well
can I just get away with this, can I
just get away with perform_request?
Do users really need this, high level
kind of domain model, which again is really beautiful
but is that necessary, the Twitter API
is pretty easy to understand.
And that is the choice that Koala makes,
that's the Facebook Gem.
So Koala has this put_connections method.
And put_connections basically is the equivalent
of this last method we were looking at.
And this is the highest level of extraction Koala has.
So Koala does not know what resources
are available in the Facebook API
and that lets it be first pretty lean,
and second when Facebook introduces
some new features in its API,
as long as it's not some totally new structure
for the API, which it pretty much never is,
Koala is instantly up to date.
So, I still prefer this one, really,
I mean this is the best if you've got that kinda time.
But you can also maybe do your users
a lot of favor, a big favor, by just
giving them a low level API that they can work with
that takes the, boilerplate out,
but doesn't necessarily provide the full extraction.
So, the quick start is to your users
what the test suite is to your contributors.
If I wanna contribute to your Gem
the first thing I'm gonna do is check it out
and try to run the test suite.
And if I can't if I get frustrated,
I'm not going to have a ton of patience for that.
And it's pretty likely that I might just
keep my branch and never contribute it back
because I can't prove that it works
with the test suite etc. etc.
So it's really important for your contributors
if you wanna have good contributions
to make sure that your test suite
is really really easy to run.
So it's unlikely that you can just do this.
It's unlikely that rake test alone will just work,
but it's definitely possible that bundle
and then rake test, is sufficient.
And this I think, you know, most Gems
will be able to provide this.
So the key here, is you already used bundler
to manage your applications runtime dependencies,
just use it to maintain your Gem's test dependencies
at runtime in the same way.
Very simple way to do this,
you have a Gem file,
you can just say, use the gemspec,
just this one line, gemspec.
Use the same, gemspec that's
in the directory we're in right now.
And bundler knows what to do.
Then in your test code, in your test helper
or spec helper, you can just, that first line
require 'bundler/setup'
and you're good to go, and bundler
loads in the Gem environment, and installs
everything for your users and so
if you don't have any external dependencies
if you're you know just sort of like a Ruby
self-contained library here, then now your users
can very consistently and nicely run tests.
But if you do have external dependencies,
say you need Postgres,
then bundler can't do that for you, right?
Bundler can give you the Postgres library,
but it can't give you an actual Postgres
instance to test against.
My favorite method of getting this
to my users, to my potential contributors
is using vagrant.
So vagrant is a tool for managing virtual machines.
Like for toolbox, specifically for development environments.
So it's mostly used to sort of have a repeatable
development environment for a team
that's working on an application.
But it's actually really good for having
a repeatable test environment too.
For a library, so, if I wanted,
if my tests require Postgres, then I can ship
a Vagrant file that could be as simple as this.
Basically we're using Ubuntu,
we are installing Postgres when we
first spin up the machine,
and then we're gonna forward the Postgres port
to the host computer so my test suite
can actually interface with it.
And that's it, and now instead of having
to go through a bunch of instructions
saying okay well we expect Postgres to be on this port
so go ahead and just deal with it.
Potential contributors can run Vagrant up,
and they've got the environment
that allows them to run the tests.
That's really nice.
Now of course, being able to run the tests
is one part, actually writing the code is another part.
If I have contributors to my project,
and few things are more heartbreaking to me
than getting a poll request, that you know
it's a good new feature say, it has
a nicely factored code, really just everything I want
except maybe I see something like this.
Now I know this is hard to look at
but I would never put a multiline block with curly braces.
But, I respect the decisions of those who do.
And I would hate to be in the situation
where I've got a really good poll request
where there's some style nitpick I have
and so instead of saying, hey thanks
and accepting the poll request
I have to say, can you change that to a do end
and then I'll take your free work
that you're giving me for my library?
So can we avoid this, yes.
RuboCop is a tool for style checking and linting
you can set up rules like these, there are more.
To your preferences, right?
It's your library, it's your piece of software.
So you get to decide what the style is
and the nice thing about RuboCop
is that it's automatic, it's not coming
from a human, it doesn't feel like a rejection
it just feels like a cold impersonal robot
being cold and impersonal.
And it's very quick.
So you can take the RuboCop, you just run RuboCop
basically, once you've set up these rules.
And you can put that in your Travis configuration
so that when somebody submits a poll request
they'll see feedback right in the poll request saying
hey the build didn't pass, go look at the build report.
And then that shows where the style,
style doesn't match your style,
or you know there are various linting problems.
So, then you get kinda, you get to have your cake, right?
You don't have to have weird confrontations
with contributors, about things
that are completely a matter of opinion,
but you do get to have nice consistent style
in your library.
So that was number seven, and we are at the end.
So real quick, just to recap,
write a Gem, that has a really short quick start.
And the way to do that is try it yourself.
Write a really long readme.
Use YARD for code documentation.
Try not to ever ever do breaking
changes if you can avoid it.
If you cannot avoid it, be sure
to use semantic versioning to communicate
what's going on to your users.
Understand that your users are probably using
old versions of things at least some of them are,
and support the past as much as you can
as well as supporting the future as much as you can.
So keep track of new versions of things
with Gemnasium, run your test suite
against lots of different versions.
Use Travis for that.
Avoid abstractions that can lock people
into your assumptions about how they're gonna use your code.
So consider providing multiple layer sof public interface.
A nice high level one, but also an equally valid
equally public low level one.
Make it easy to run the test suite
by using tools like Bundler and Vagrant.
And finally use RuboCop to give instant
and non-confrontational feedback
on code style to your contributors.
That's it, got plenty of time for questions here.
Right, right.
So the question was, first part of the question was
you're wrong about RuboCop,
and the second part of the question
was what about a contributing document.
That is a great one, so, in terms
of the contributing document,
basically you can make a file in your repo
all capital contributing, I'm
not sure if that actually matters.
And GitHub will put a banner at the top
of the form where people submit
poll requests and issues that links to that document.
So it's kind of in peoples' face right when they begin
to actually attempt to contribute
and you can write whatever you want
such as follow my style.
On the question of RuboCop,
yeah sure opinions may differ,
I guess I would be interested maybe
after we finish here to hear what the objections are.
If you're uncomfortable with the idea
that the build should break because of style issues,
then RuboCop can also not be a part
of the build but still be there for people
who are trying to match your style.
Do I have a suggestion on which
license we should use?
MIT, seems like the normal one.
Yeah, Copyleft doesn't seem to be enforceable.
But I'm also not a lawyer, so, yeah.
I guess I don't really have an opinion
but I do MIT because that's what everyone
else does, and that usually is a good idea.
Okay, for those of you on the other side of the room,
avoid multi license Gems,
pick a license have that be the one true license.
In my experience, what is the best way
to publicize a Gem?
RubyFlow is good, had good luck with that.
Depending on you know, I'm not gonna say anything
that, isn't probably pretty obvious.
I mean Hacker News, Reddit Ruby subreddit.
If you're into Reddit, uh, Twitter.
But RubyFlow is probably the only one
that may be is a little under the radar
but I've had pretty good responses from that.
Yeah that's a good question.
So, the question is for versioning,
what is a good practice for the first release?
I mean when you see like 0.0.1 it's like come on.
You know, like actually out there in the real world.
I would say like okay, let me just back up
like a thousand slides here.
So if you are at this point,
where you like haven't pushed it,
then an 0. is cool.
I would say after that, just go for it you know?
1.0, like when you're going on RubyFlow and Twitter,
you can always make a 2.0.
It's not gonna hurt anyone.
Sure, that's a great question,
the question was if I release a new version
of my Gem, that supports Rails 5,
what kind of release is that for my Gem?
So I haven't made any other changes,
but I have you know let's say
for instance I actually don't have to change
my Gem to support Rails 5.
Then I would say yes, that is a patch level release,
I guess it's hard to imagine a situation in which,
I mean you can imagine sort of augmenting
an API in some cases so that okay
now I can take a new type as an argument
for a particular method.
And I guess that would technically
fall under the minor version release
you're like adding functionality
to the public interface.
So yeah I would basically sort of evaluate it
on the merits, if there's no change
to the public interface at all,
then it's patch level, otherwise maybe it's a minor.
Okay so the question is if another
Gem maker defines a particular namespace
like uses a module to define a namespace,
should you use that namespace or should you define your own?
I assume we're talking about a case where your Gem
is kind of an addition to this
plug in of some sort to theirs.
Right so I think in most cases where that comes up,
certainly the initial developer of a Gem
can establish a convention that you know,
this area of my Gem's namespace
is for you to put your stuff in.
I think they have like Rescue here
has some good conventions around that.
I would say if there is not a really
well-defined convention by the
sort of upstream library that you're building against,
there is very little downside to just respecting
the general rule that like, the top level
namespace of everything in my code
is the name of my Gem in camelcase.
Can I say a few words about the underscore
versus the dash in the naming?
Mostly use underscore, underscore
is how we name our files obviously.
In the Gem file when we put Gem whatever,
Ruby Gems is gonna look for the underscored version
like, or it's gonna look for the same thing
that the Gem is called, basically.
So, dashes are a bit suspect.
I would say actually the scenario
we were just talking about though
where your Gem is building on the namespace
of another one, that's a situation in which I would
probably go with the dash.
So I might, if I have like you know,
rescue tea party, then I would probably
do like rescue-tea_party and then you know
like this sort of root of my library
would be rescue-tea_party in the file system.
But I don't know, it's the Wild West
out there with those dashes.
You gotta fend for yourself, what's up?
How do I test my Gem's compatibility
with dependencies?
Do you mean like Ruby dependencies
or external ones?
Oh so that's what Appraisal's for.
Oh, right past it.
So Appraisal allows us
to just list all the different versions
of dependencies that we wanna test against.
And it generates an exhaustive set of Gem files
that we can then using Travis run our tests against.
Yeah so the question is if you have a Gem
that depends on Rails, and it's sort of like baked it
it's really a part of Rails is a tight part of using it,
how do you test that, do you generate a full Rails app?
I personally have written a lot of Gems
that sort of hang out at the Model layer,
and I will say there is absolutely no need to do that.
If you're doing it at the Model layer,
like ActiveRecord is its own thing
and you can just test against ActiveRecord.
And I don't have any great advice
for if you're writing like,
if you're writing a view layer thing
that has a bunch of helpers and you wanna test
those helpers, there may be no way to get around
actually doing that in a real Rails runtime.
I'm a little embarrassed I don't have any
good advice for that cause it sounds horrible
and I would never wanna do it.
But maybe there is a good practice out there
and maybe the Internet knows.
Cool, so the question is, whole
Bundle Gem, Ruby Gems task,
Jeweler, these are all tools for bootstrapping a Gem.
And my feeling is basically,
definitely not Hoe, definitely not Jeweler
basically like the level zero thing
is writing your own gemspec is really easy.
It's just Ruby code, and there's definitely
no need for anything that generates a gemspec.
Like you don't need code that looks
almost exactly like the code it generates.
I actually skipped this slide,
but I do like bundle Gem's pretty good.
Where did I put it.
Bundle gem is a command that just generates
a nice skeleton of your whole Gem environment.
Including all the stuff about, there it is,
Including all the stuff about, you know,
integrating Bundler into it.
So yeah I think you know,
you don't wanna literally have to sit there
and make the lib directory every time
and Bundler Gem's nice for that.
But I would avoid anything
that is trying to add a level of indirection
on top of say, making your Gem file.
Like your Gem file can just be your Gem file.
Alright should we call it?
Let's call it.
Thank you everyone.