Wednesday, October 05, 2016
RubyConf 2015 - Making it on your own... by Nikki Murray and Maggie Epps
- And I'm Nikki.
- So this came about because Nikki and I,
we are both former social workers
who found ourselves working together about a year ago
at a small software consultancy,
where we were responsible for maintaining
a few different projects,
and we were also responsible for billable hours.
We were really in a tightly driven, efficient environment.
And we saw some of the challenges that came up
both in this environment and as a result
that we wanted to talk to you guys about.
- So welcome to
Gem use or Misuse and Going Your Own Way.
I'm Nikki. You can find me on Twitter @NikkiLizMurray.
On github @jdax.
My cats are on Twitter @nikkisCats.
I'm a developer with Democrats.
I work a lot making fun, interactive tools
for voters to use.
I'm owned and operated entirely by my cats.
From left to right, Stormageddon, Dark Lord of All,
Tom Waits, Didi, Destroyer of All Things Good and Pure.
- I'm Maggie. You can find all my handles there.
Github, and then there's a blog that I used to write on,
and may someday again.
So I'm a software engineer at LaborVoices.
LaborVoices provides global brands and their supply chains
what has been missing, an early warning system based on
direct feedback from workers by
repeatedly polling workers through their mobile phones.
We help our customers obtain strong safety standards
and decent working conditions,
empowering workers through their own voices.
I'm bad at elevator speeches,
so I took that from our website.
But what's really important for you guys to know
is that I'm hiring, so if you have any interest in
improving global labor conditions,
and you happen to like Rails, maybe,
feel free to find me or Tweet at me.
And this is Dolly, who you'll see again.
- So the overview of what we're going over today is
the importance of assessment is really key.
What is needs assessment, how do you do
Important in that is why we use gems.
And how and why do we misuse gems?
How should we go about assessing gems for fit?
And what do we do if we find there is no gem that
fits our needs?
Importantly, that means how to do it yourself.
- So we're starting with the importance of assessment
because this is really the thing
that if you took nothing else away, we'd love you
to take away.
So it's remembering to accurately assess
what your problem is and what your needs are
before installing a gem into your system.
And we have this lovely quote,
"Assessment is an ongoing process,
"which is participatory,
"that seeks to understand the service user and
"their situation, and sets a basis for planning
"how change or improvement can be achieved."
And so we didn't take that from a
software development textbook.
We took it from a social work textbook.
- So models of assessment is really common,
and if you're going through social work school,
how to do assessment with your users,
the users of the service you're providing,
and how to do assessment in your own team.
So the assessment process operates by being purposeful
Figuring out what is appropriate for your situations.
It needs to be dynamic and responsive.
So you need to be flexible in your assessment.
It needs to be based one engagement from individuals,
and inclusive engagement at that.
So that means when you're doing the assessment
of what you need your app or your gem to do for you,
you need to have every stakeholder
in the room with you.
So that means users, that means design,
that means marketing, that means
whoever you think is going to have
a hand in this project
or is going to touch it at one point or another
needs to be in the room.
Not only that, but it needs to be ethical and skilled.
So your solution needs to find a way that
achieves your goal ethically for everybody
that touches it.
It needs to be grounded in legal and policy context too.
So if you were doing something with a healthcare
company, if you're doing something with a
policy company, you need to know the context
in which your solution needs to be found.
So does it need to be HIPAA compliant?
Does it need to be compliant with whatever rules
a foreign country might have?
It needs to be also empowering,
so everybody needs to feel empowered to
make the assessment, to make the calls.
They need to feel that their voices are being heard
in the assessment process.
It needs to highlight protection and safeguarding.
So as you've probably heard in a few other talks,
making sure that everybody involved
has their privacy protected,
has their anonymity protected,
anything that your users or anybody else involved
might find a key thing that they need to hold onto,
make sure that that's protected in the assessment process.
It needs to be holistic and comprehensive,
so think of every end case, every edge case,
and think about any other cases
that people might be using this service or product in.
There needs to have support for decision making.
So the people that are making the final decisions
need to feel supported in that.
So if you're the programmer and you're
making the final call on which gem you're using,
or what gem you're gonna be building,
you need to feel empowered that your bosses
aren't going to come back and go,
"Why did you use this?"
So make sure you have those discussions
and that they go both ways.
And it also in the end, needs to lead to future action.
So don't have this meeting for weeks on end.
Make sure that the meetings that you're
doing this assessment in are focused,
and that they come to a conclusion that ends with
a final plan of action.
- So what's a needs assessment?
As you saw from the beginning of our talk,
what really matters about this talk is that
we want to avoid using the wrong gems
or using gems recklessly.
So the first thing you need to do is
really know what you need before you use a gem.
So what does this look like?
So it looks like concretely defining your problem.
And it means thinking of the problem from
as many angles as possible.
Asking why it's a problem.
Is it a problem for your users?
Is it a problem for somebody else on your team?
Who is this a problem for and why does this matter?
This goes back to getting a lot of opinions on it.
Whether it's having everybody in a real room,
having everybody in a slack channel,
but just making sure that you really know
who the stakeholders are
and what they think about this problem.
And then considering your users,
because they're always gonna be your stakeholders.
So how will different solutions impact them?
How will it change their lives?
How will they react to this?
And then sometimes we're approaching a problem,
and we think of it as just one problem,
but really it's five or six.
So it's breaking it down and then
approaching it from each problem
and deciding which one is the most important
and solving that first.
So that means writing out different solutions
and looking to different people for feedback
on those solutions.
And once you've determined the best solution,
it means starting to look for ways to implement it.
You could use an existing gem or gems,
write your own gem or gems,
or build in that functionality directly into your project.
So I would evaluate each of these and ask yourself
which is the best one.
So the first question is why do we use gems.
This might seem obvious, but obviously it's easy,
so that means you get to go pet your cat more quickly.
So you don't want to solve a problem that's
already been solved.
You want to be as dry as possible,
or you want to be not repeating other people's code
just in your own way.
And then everybody uses them,
and this leads to a sense of shared responsibility
and community, so you're not alone
in being responsible for maintaining that work.
- Also, everybody uses, like,
there's a few gems out there that people might use
that has a lot of, not necessarily their own documentation,
but a crap ton of stack overflow questions like devise.
So this leads to how do we misuse gems?
Misuse of gems can sometimes look like
150 gems installed, and you have no clue why.
For comparison, the average gem file dot lock
has about 118, with a standard deviation of 58.
So on average, your project will have 50
to about 175 gems installed.
And the upper limits of that is a lot of gems,
and that's a lot of code that you're pulling into a project
that you didn't write and that you have no control over.
So the pitfalls of gem misuse is unknown dependencies.
If you didn't read the dependency list before you ran
gem install, you might be sitting there looking at
bundler going, "Why is it installing that?"
This can also lead to breaks on upgrades.
If anybody has ever taken an app through an
upgrade process, you know how time consuming
that can be, and this time can really be cut down
by not relying so much on gems.
So you upgrade one gem and then suddenly
50 other things don't work.
This can also lead you to looking at your gem file
and going, "Why did I install that?"
And so you remove it and then nothing works again.
Also the gem might not be the best solution
to your problem.
It might only be a partial solution.
- So why can this happen?
Some of you probably come to projects and are like,
"What's happening here?
"I'm staring at the gem file and I don't know
"how it came to be this way."
So you know startup culture,
and I don't just mean at startups,
I mean this idea of we have to get this out the door now.
We have to be first.
All that really matters is that it works.
So you just say, "Oh there's a gem for that. Let's go."
And then you throw it in there and you think
you're good to go.
There's the idea of groupthink,
so there's some gems that people go,
"Oh everybody uses this for that solution,
"so obviously I should use it."
There's just sometimes poor planning.
You've thought out all the most obvious
use cases, but you really haven't thought out
the more minute ones,
and your gem might cover those obvious ones,
but really it's not as relevant to some
more edge cases that might actually be
really crucial to what you're trying to do.
And then there's this idea of imposter syndrome.
I think it's often easy to go,
"Can I really do better than this gem out there
"that's supposed to be the best?"
Even though maybe you can do better
for your problem.
It might not be that you can do better
in this global sense,
but you might know your problem
way better than whoever wrote that gem.
- In addition to the pitfalls of not knowing
why your app is doing what it's doing
and it's really because of that gem,
there's some other risks that you run into
when using gems.
A lot of people have talked about
hacking in the past and how you can hack.
There was a Ruby Nation a few years ago
where somebody passed out cards that said,
"Gem install Ruby Nation,"
and then gave a speech about how he
could have just taken all of the information
on your computer with that because
nobody thought anything of it.
So any gems that, especially aren't on
rubygems.org, are potential security risks.
According to Hakiri, 66% of gems
that are even on rubygems.org have
at one point or another had a version
that had a security risk in it.
Those might have been really small security risks,
they might have been SQL injection risks.
So making sure that you're doing the assessment
of the gem beforehand
to see if you see anything that might stick out to you
as a possible security risk.
We talked earlier about the average number of
gems in a gem file. 118.
On that average gem file, about four of them
currently have a security risk in them.
So maybe you've used Sprockets
in some of your projects, as early as a few weeks ago,
it had a known security vulnerability on it.
Arbitrary file existence disclosure.
Maybe that doesn't concern you.
You don't use Sprockets or you don't care
about those kind of security risks.
But you've probably used Active Record at one point
or another, and this summer it had a
SQL injection vulnerability.
So you don't use Rails.
You don't care that Active Record
had a security vulnerability in it,
because you use Lotus or something other
that's cool and hip.
But you've probably used Bundler.
And this summer, it arbitrarily installed gems
that you didn't want or ask for.
There's also memory risks.
If any of you have ever bumped your head really hard
against where is all my memory going,
why is all this happening to me,
it's because a lot of gems,
a few common gems, have known memory leaks
in some of those versions.
So Redcarpet, sidekiq, therubyracer,
all have documented, and now fixed, memory leaks.
But there are still versions out there that might be
on your gem files that have these memory leak problems.
Currently there are suspected leaks in
newrelic_rpm and delayed_job.
If you want to make a pull request that fixes these,
that would be great.
- So you also run the risk of claustrophobia.
You've installed this gem, and you realized that
as we talked about, it solves some but not all of
your problems, and you find yourself
kind of hedged in by the problems that the
original gem author tried to solve.
So what you end up doing is you redesign your feature
around this gem rather than redesigning your code
to match your feature.
You also can wind up with hundreds of lines of code for only
half of a fix, in this case.
So you have all these lines of codes.
You're rewriting your code to keep up with this gem.
And there's all this code that really is pretty wasteful.
And you can figure this out after you get it installed.
So you think, "Okay great, this gem is awesome,
"it solves most of my problem."
But you got it installed, and it's set up,
and you realize it doesn't even really do the thing you
wanted it to do, and it has compatibility issues with
other gems in your system.
So it's a really fun process from there, right?
- So that last example happened to me,
where I was trying to write an API,
and I decided I would just use a gem for that,
and halfway through getting the gem all set up,
I'd wasted an entire day trying to get grape
to work with my app, and it asked me to
turn off strong params, and I threw it out.
And wasted another day seam ripping it.
So gem assessment.
So what should you look for beforehand
before you have to go in there with a seam ripper?
You want to look for stuff like how well is it maintained.
When was the last commit?
Since that last commit, were there any major updates
to Ruby that might cause it to not work with Ruby?
Are you using the version of Ruby that has since
been updated to no longer work with this gem?
You also want to look at how often there is
So stuff like github watchers or stars.
You want to check the rubygems.org downloads.
You want to see what the community commitment is
to this gem and the community support for it
and how much community trust has been put there.
You also want to look at the issue trackers.
Are there a lot in there that have been
sitting there for years unaddressed?
Not even commented on? Not even a won't fix on it?
You want to see what kinds of issues they close
and what kinds of issues they close quickly.
If somebody submitted a security vulnerability patch
did it sit there in the PRs for weeks,
or was it merged in pretty quickly?
You also want to look at what the contribution process
is like, what kinds of tests are run before
a PR is accepted?
Are these automated tests, or are these tests that the
gem author is asking you to run yourself?
And you want to look at that test suite itself, too.
Is it testing for stuff that you would want to see it
Is it testing for edge cases that you strongly think
should be tested for?
If you have the time, read the source code.
If you don't have the time, read the tests.
Especially when me and Maggie were doing billable hours,
the desire was there to not read the source code
because we're billing a lot of money for
every minute that we spend reading.
But it's actually worth it, and if you spend a day
reading source code, you're not gonna be spending a week
redesigning your entire app.
So read the documentation. How well is it documented?
Read the source code. Is the source code dry?
Does it follow single responsibility principle?
Is it easy to understand what it's doing?
Are there really clever trickS that the gem author
put in there that you have no clue how they work,
and so therefore you trying to write code around
that would be difficult?
Is it well commented?
You want to look at the tests and read the tests and
trying to figure out what the gem author was
attempting to achieve.
And figure out if they were testing for edge cases
that you think are important.
Were they testing for edge cases that you
hadn't even thought of before?
You also want to look at if it has a code of conduct.
If you're using the gem,
you might need to interact with the gem maintainers
or contributors at one point or another,
whether that's just submitting a PR or
asking them for clarification of something.
Does the code of conduct or lack thereof
lead you to believe that interaction
would be a positive one?
Does it make you want to work with these people?
So you've decided that it fits not all of your needs,
but most of them, and you kind of want to use it.
Consider contributing to the gem.
You could add the exact functionality that you're looking
for and submit it in a pull request.
As previously discussed, if those are people that you
want to have that interaction with.
Unless and until it is merged, you can use a local copy
or point your gem file to your branch on github.
You could fix the memory leak or security issues
you found yourself,
and hopefully they will respond to that PR quicker than
your added functionality one.
Does it solve your problems in a way that the
users of the project will be happy with?
Because at the end of the day,
you want to make sure that your users are happy.
Is it an accessible solution?
Is it a solution that you believe will make you happy
to work with it and also the users happy?
- So you're done assessing,
and none of the gems out there really fit
what you're trying to do.
So it's trying to do it yourself,
but the real question is how.
Since we're programmers, I think we all like
kind of a method.
This is what I came up with just for approaching
I just say overcome, assess, research,
Of course we're gonna do this in the workflow
that fits your company and all of that,
but this is just some ways to think about this.
So I put in Overcome, because every time I'm
approaching a project, I have to kind of tell myself,
"Hey, it's okay that I'm really freaked out by
"what I'm about to approach."
That my solution might not be perfect, but I can
come up with something good for the problem at hand.
And this is where all great things begin under the yoga mat.
So we go back to our needs assessment,
we're defining that problem concretely again.
But we're coming back because we didn't have a good
So we're looking at what the current behavior of
our system is,
what the behavior we're trying to achieve is,
and why we want that behavior.
We want to slow down and ask ourselves,
what are some possible edge cases?
What are some things that the gems I already looked at
don't address that I need to address now?
And what are the risks of building this
the way I want to build it?
What are the security risks?
Do I understand how performance is gonna be impacted?
Do I understand how my users are gonna be impacted?
And then, why hasn't somebody else solved this problem?
So you've looked at all these gems, you've looked at
all this code, why hasn't somebody else figured this out yet
and why haven't they approached it the way you're
So we're gonna go back to this research.
You found some gems before,
so now you're gonna look back at this,
and you're gonna read some of their code again.
But this time you're not just reading it to assess
whether or not it works for you.
You're reading it to figure out what they did well
that you might want to build upon.
And also why it is you originally dismissed the gem
as a solution to your problem,
and what it is you need to change.
So you can look at their tests again,
think about what they're testing for,
what you're gonna want to test for.
And then you might want to look at their dependency list.
Because this gem might not have worked for you,
but they might have built on a gem
that you could use to build out your solution.
So it's, again, figuring out which parts work
and which ones don't and again,
why they work the way they do.
So then you want to look at what other people have
thought about this problem.
So did any of the gem authors write about
how they approached their problem and their process?
And why they made their decisions?
They could've talked about some other research they did
that might be really useful to you.
For example, there might be a blog out there
where somebody else approached your same problem
and documented exactly how they solved it.
Maybe they didn't write a gem,
but maybe they did a tutorial
or just kind of a thought process blog
on how they solved this same problem.
So it's really just learning as much as you can
before you even start to approach this.
So now you're gonna build.
The way you're gonna approach this is the way you'd approach
anything else in your app, right,
is you want to map out your solution.
You want to model every part out
and figure out its architecture.
You want to use whatever your best practices are,
whether that's TDD or Behavior Driven Development.
But you want to continue using your best practices
as much as you can.
And you really want to document it.
I think what's really important here is,
same as when you're looking at other people's gems,
you want somebody else to come back and look at your code
and feel really comfortable knowing why you
approached the problem the way that you did.
They may not think your solution is right for them,
but you want them to understand what process
you went through.
I like the headache test for most of the work I do.
I say that if I really get sick of working on something,
and if I'm getting a headache day to day working on it,
usually something's not going well.
So that goes back to, you know,
have fun while you're working on this.
If you're not having fun,
why would anybody else have fun with what you end up with?
So to start with, consider that you may not need a gem.
You may just, you're gonna ask yourself,
"What's the most basic problem I'm trying to solve?"
I might just want to build something into my app.
This might be a really quick fix.
Maybe I really thought this was huge,
but sometimes the biggest fixes
come from one or two lines of code.
So start there, because that's gonna be
the easiest thing to maintain and the
easiest thing to work with later.
Again, it's that headache test.
Don't make yourself do too much work,
because if you're miserable,
everybody else who comes after you
is probably gonna be somewhat miserable as well.
So what if it does make sense as a separate gem?
So then you're gonna want to think about,
"How abstract can I make this?
"How can I make it such that somebody else
"might be able to use this for their own work?"
Don't make it too dependent on the code you've
already written within your app.
Try to pull it out as much as possible.
Not everybody can open source,
but if you can, that's a great way to get some feedback
on it; maybe other people have really great ideas
about what you're working on.
If you're open sourcing it,
try to add a contributor code of conduct.
Maybe somebody else is gonna come in and
add something really awesome,
some feature that you never even thought of.
And publish it.
If you think it's a great solution, get the
- Speaking of putting it on rubygems.org,
if you are publishing your gem,
please consider the following.
Some of these were previously discussed
in Seven Habits of Highly Effective Gems,
but we have our own twist on them.
How easy would it be for another person to get started
on your gem or get it started in their own project?
How easy would it be for someone to contribute?
If you don't think it's gonna be easy for somebody
to contribute to your code base,
it's not gonna be easy for your self to contribute to it
three months from now, when you have forgotten everything.
So is your test suite understandable?
More importantly, is it understandable to future you?
Are you testing for style conventions?
Make this decision now
so that you don't have to backwards port that kind of thing
into your gem.
You want to think about is your solution broad enough
for other users' cases, not just the one that you're
If it's not, specify specifically in your README what
you were trying to solve, and document that well.
Have you tested it in Rails 2? Rails 3?
Ruby 1.87? And also document that.
So people know going into it what they are able to
use it for and what they might need to look out for
in other versions.
- So you've built your product and now you're maintaining it
There are some questions to start asking yourself here.
We're all agile, so we're gonna keep working on it.
Maintenance is not just a static process.
We're still working on our feature as we go.
So a question to ask yourself is,
will the next person or future me, hired at my company,
or I guess me if I'm already hired, so me in three months,
hopefully I still work there, be able to jump into
your code base?
Will I be comfortable just getting going?
Is this gonna be a huge hassle to get started on again?
Have I written some good tests?
Not just is it there, but is it well tested?
Does it test the things I need it to test?
If I'm gonna need to add something in six months,
am I gonna remember what I worked on
six months ago?
I think I got my time frames a little confused there,
but that's okay.
Such that I'm not gonna break anything important.
Have I documented it well?
Do I remember what's happening?
Maybe ask somebody else to read your documentation
and try to work through it.
I think that's one of the best ways to know if it's any good
is if somebody else can follow the steps you followed.
And then something really important is
to be able to ask, "Why did I do it this way?"
Because the next person who joins,
or you in three months, is gonna be asking that.
You're gonna be going, "Why did I do this?"
So maybe make sure you can really explain that.
If you have a teammate, have talked it out with them,
if you don't have a teammate, make sure
your cat understands really well what's going on.
And this is a good time to evaluate
how much complexity you've introduced.
Is it just way too confusing?
Did your solution really simplify things,
or did it make it much, much worse?
You can simplify it now because you have
the solution in place, so this is a great time to
clean up your code as much as possible.
Whether you've just installed a gem or
you've completely written something from scratch.
- So aside from our assess, assess, assess,
and then keep assessing, and ongoing assessment,
one of the other takeaways that we want you to have
from this talk is if you're using a gem,
you're not the maintainer.
That is more free time for you to work on your own code
or more time for you to pet your cat.
It's a great thing to not be a gem maintainer.
- However, if there's something else we want you to
take away from this,
it's that you are not the maintainer if you didn't write it.
So guess what, you have no control over updates
or changes or pivots.
It could've been your cat, or your cat could just be
really annoyed at you.
You might end up spending two days in upgrades
because you didn't do anything on this gem
and somebody else just threw in an upgrade
that you realize is also a security vulnerability,
so you really have no choice about whether
you go to the next version.
- So I think we are at the time where we can
take questions; does anybody have any questions
about good assessment or good team assessment
or gems that you think are really awful?
- Yeah absolutely.
He asked if there were any specific gems
that we thought were subject to frequent misuse.
So I'll start with we first came across the problem,
as Nikki mentioned, because were working on APIs.
And we were kind of Googling this,
and a lot of stuff out there was like,
"Use this gem for an API. This is the gem."
And then we'd read the next blog post,
and it would say, "Use this gem for an API."
And it would be a completely different gem.
So grape was one example of that,
where everybody was like, "Use grape. Use grape."
But then Nikki was approaching this problem,
and she found a third blog.
- So after putting in a lot of different gems
to make my pretty basic crud app into an API
and seam ripping all of them out,
I was just like, you know what,
I'm just gonna teach myself how to write an API,
and instead of sitting there and turning off
strong params like grape asked me to do,
I was just able to go into the controller and write
the code in there for the API.
So I think if you are thinking about something like,
"Oh there should be a gem for this,
"I don't know how to do this."
Consider just Googling, "How do I build this?"
So a lot of people I know use
really complex, this came up at Every B for Good,
like how do we make a CRM in Ruby?
And I think a lot of people at that team
tried to start off like, "Can we use gems for that?"
But just kind of like no,
can I take a step back and think about how
I can do this on my own,
and can I do it simpler?
- And this all came about because I'm probably not
the only person here who's been at a hackathon,
been at a conference where somebody said,
"Have you used this gem?"
and you're like, "Well no,"
and they're like, "Well everybody uses that gem."
And suddenly you feel like you're super behind.
And I think that maybe you didn't use that gem because
it actually wasn't right for any case you've encountered.
So I think it's sort of this idea we have that we always
have to use a gem for, or a specific gem for
anything we do, when maybe Active Record is a great gem,
but it's not right for every app, right?
So it's just about using that,
I think there's an analogy of using the same knife
for every problem in your life.
I'm not good at analogies.
- Another thing that I just thought of is that
everybody says you can use Devise.
It's the quickest way to get user authentication
into your app. Just use Devise. Just do it.
And then you see these apps that don't need
user authentication or user authorization.
It's like, "Why do I need to sign into this?
"This is a database of your favorite movies.
"Why do I need to sign into this?"
Well because you could just put Devise in and have
user authentication, then you could be getting user data.
And it's like you don't need user data.
You don't need to have user authentication here.
You are literally just displaying static content here.
So think about what kind of problem you need
and what solutions, like there's that easy solution of
putting Devise in, but do you really need it? No.
The question was, "Do you have any tips for scanning for
- So probably if the gem maintainer didn't catch it
you may not catch it, but if you do see something,
obviously immediately let it send up a warning signal.
I don't know if I'm the only one,
but sometimes I read gem files and I'm like,
"Oh they probably knew what they were doing.
"So if I see something weird, I just won't worry about it."
Like disabling strong params, for example.
But listen to your gut on that.
But the other thing is that we took all of our advisories
from RubySec, so that already had some advisories.
So maybe start by looking there and see if any gems
you're using are already listed there.
And I think Hakiri, that you mentioned as well,
has some listings.
So there's some listings out there as well.
- So Ruby Sec, you can go through and,
lets see here, what's a good one?
Where was that one?
Oh Bundler installs arbitrary gems.
- That was one of our favorites.
- Yeah so it says right here, it was patched
in version 1.70
and a description of the problem and then these
are the places that you can go
for common vulnerabilities.
This is the open source vulnerability database,
and this is, I don't know what this one is,
and the wifi is being slow,
but it'll take you to places that'll do it,
and you can check and see here if it's been patched
and figure out if you want to maybe use the patched version
or if you want to use an earlier version
that didn't have that vulnerability if it
hasn't been patched yet.
- Yeah and you guys might want to read the description
of this one too, because it's a little more scary
than just arbitrary gems.
I think we had a question back there.
Thank you, that's really helpful.
- So for those who didn't hear,
there are some open source places like Code Climate
and what was the other one?
Gemnasium, that'll run tests on your suite before
to see if there's any vulnerabilities that're known in there
- That was an example of a possible style choice
somebody could make.
- An extreme style choice.
- We do not endorse any specific styling choices you guys
- But we give you free reign to go to the extremes
with curly braces in either direction.
- All right thank you everybody so much for listening.