Slides: Ruby to Elixir – what’s great and what you might miss

This is a talk I gave at the Polygot Tech Meetup in Berlin in April. It has parts of my previous elixir talk while adding a new perspective more directly comparing Ruby and Elixir as well as being shorter as it was used as an intro to a fun panel discussion.

Abstract

Elixir and Phoenix are known for their speed, but that’s far from their only benefit. Elixir isn’t just a fast Ruby and Phoenix isn’t just Eails for Elixir. Through pattern matching, immutable data structures and new idioms your programs can not only become faster but more understandable and maintainable. While we look at the upsides we’ll also have a look at what you might be missing and could be improved.

Slides

Slides: Elixir & Phoenix – fast, concurrent and explicit

This is the first talk I ever gave about my two new favorite technologies to play with (at home and at work) – Elixir and Phoenix. I gave this talk at Vilnius.rb in march and at the Ruby User Group Berlin in April. Hope you enjoy it.

Abstract

Elixir and Phoenix are all the hype lately – what’s great about them? Is there more to them than “just” fast, concurrent and reliable?

This talk will give a short intro into both Elixir and Phoenix, highlighting strengths, differences from Ruby/Rails and weaknesses.

Slides

 

Don’t you Struct.new(…).new(…)

As I just happened upon it again, I gotta take a moment to talk about one my most despised ruby code patterns: Struct.new(...).new – ever since I happened upon it for the first time.

Struct.new?

Struct.new is a convenient way to create a class with accessors:

2.2.2 :001 > Extend = Struct.new(:start, :length)
 => Extend 
2.2.2 :002 > instance = Extend.new(10, 20)
 => #<struct Extend start=10, length=20> 
2.2.2 :003 > instance.start
 => 10 
2.2.2 :004 > instance.length
 => 20

That’s neat, isn’t it? It is, but like much of Ruby’s power it needs to be wielded with caution.

Where Struct.new goes wrong – the second new

When you do Struct.new you create an anonymous class, another new on it creates an instance of that class. Therefore, Struct.new(...).new(...) creates an anonymous class and creates an instance of it at the same time. This is bad as we create a whole class to create only one instance of it! That is a capital waste.

As a one-off use it might be okay, for instance when you put it in a constant. The sad part is, that this is not the only case I’ve seen it used. As in the first case where I encountered it, I see it used inside of code that is invoked frequently. Some sort of hot loop with calculations where more than one value is needed to represent some result of the calculation. Here programmers sometimes seem to reach for Struct.new(...).new(...).

Why is that bad?

Well it incurs an unnecessary overhead, creating the class every time is unnecessary. Not only that, as far as I understand it also creates new independent entries in the method cache. For JITed implementations (like JRuby) the methods would also be JITed independently. And it gets in the way of profiling, as you see lots of anonymous classes with only 1 to 10 method calls each.

But how bad is that performance hit? I wrote a little benchmark where an instance is created with 2 values and then those 2 values are read one time each. Once with Struct.new(...).new(...), once where the Struct.new(...) is saved in an intermediary constant. For fun and learning I threw in a similar usage with Array and Hash.

Benchmark.ips do |bm|
  bm.report "Struct.new(...).new" do
    value = Struct.new(:start, :end).new(10, 20)
    value.start
    value.end
  end

  SavedStruct = Struct.new(:start, :end)
  bm.report "SavedStruct.new" do
    value = SavedStruct.new(10, 20)
    value.start
    value.end
  end

  bm.report "2 element array" do
    value = [10, 20]
    value.first
    value.last
  end

  bm.report "Hash with 2 keys" do
    value = {start: 10, end: 20}
    value[:start]
    value[:end]
  end

  bm.compare!
end

I ran those benchmarks with CRuby 2.3. And the results, well I was surprised how huge the impact really is. The “new-new” implementation is over 33 times slower than the SavedStruct equivalent. And over 60 times slower than the fastest solution (Array), although that’s also not my preferred solution.

Struct.new(...).new    137.801k (± 3.0%) i/s -    694.375k
SavedStruct.new      4.592M (± 1.7%) i/s -     22.968M
2 element array      7.465M (± 1.4%) i/s -     37.463M
Hash with 2 keys      2.666M (± 1.6%) i/s -     13.418M
Comparison:
2 element array:  7464662.6 i/s
SavedStruct.new:  4592490.5 i/s - 1.63x slower
Hash with 2 keys:  2665601.5 i/s - 2.80x slower
Struct.new(...).new:   137801.1 i/s - 54.17x slower
Benchmark in iterations per second (higher is better)
Benchmark in iterations per second (higher is better)

But that’s not all…

This is not just about performance, though. When people take this “shortcut” they also circumvent one of the hardest problems in programming – Naming. What is that Struct with those values? Do they have any connection at all or were they just smashed together because it seemed convenient at the time. What’s missing is the identification of the core concept that these values represent. Anything that says that this is more than a clump of data with these two values, that performs very poorly.

So, please avoid using Struct.new(...).new(...) – use a better alternative. Don’t recreate a class over and over – give it a name, put it into a constant and enjoy a better understanding of the concepts and increased performance.

Running a meetup

Running a meetup

So far in this post series I covered what you should be aware of before you start organizing a meetup and the 5 basics defining your meetup. I saved one of the most important parts, how to actually run the meetup, for last.

A meetup is usually divided into a couple of phases: Before, Arrival, Main and Goodbye. To easily see what there’s to do, the format of this post is slightly different than the others. It’s not so much discussions but more of a check list for each of the phases, so you don’t forget anything.

Before

As you might have noticed during the first two posts, most of the work done for a meetup happens before the meetup. The preparation is the real work, if it is good, then the meetup is mostly fun. The foundation for a great meetup is great preparation. Most of the things to prepare (online presence, atmosphere, talks, regular schedule, …) were discussed in previous posts. This is about what to do in the days leading up to the event.

  • Check with the hosts if everything is still set and clear up any questions (how many people are expected to come, how long the meetup will run, do they have a projector etc.) and remind them of important things (putting up signs etc.)
  • Check with the speakers if they are ready and everything is good to go for the meetup day and remind them of the CoC
  • See that you announce the meetup via the mailing list and twitter (I usually like to tweet about every talk individually to give the speakers some exposure and let interested attendees know what topics will be covered)
  • On the day of the meetup tweet again, make sure that the directions to the meetup are clear and let them know if there’s food at the meetup

Arrival

For Arrival I like to be the first person at the venue, so I get there 30 to 45 minutes before the official meetup start. If the meetup involves presentations of any kind, be sure to bring your own laptop. The laptop of a speaker might break down, they don’t have their adapter with them… lots of things can happen, so it’s good to have a backup on your side.

Then it’s time to make sure everything is set:

  • Who is the responsible person from the venue in case we need anything?
  • Is there something special we gotta pay attention to (for instance, keep windows closed so neighbours aren’t disturbed)?
  • Are there enough signs to the meetup place so people can find it easily?
  • Are there enough chairs for the expected crowd?
  • Is the projector there and ready? Are adapters there?
  • Is there a microphone system, do we need it?
  • Where’s the bathroom?
  • Is there Wifi? What’s the password?
  • Where are the drinks (+ food?)?
  • Where are my speakers? Do they have any preference when to speak? (I usually let them choose on a “first come first served” basis)
  • Check that the laptop of the speakers works OK with the projector (Adapter etc.), before the meetup starts to prevent bad srprises

Main

For the Main part I’ll make sure I found enough speakers to fill the content before the break and then start relatively on time. Starting a bit late is fine, as people always arrive late. The Ruby User Group Berlin even has this “tradition” where we always start 15 minutes late (pssst).

First comes the welcome and an overview that should include:

  • thanks everyone for coming
  • quick introduction to the format (talks, lightning talks)
  • today’s topics and speakers
  • where are the bathrooms
  • where are food & drinks
  • wifi (also good to show on a projector or have signs around)
  • mention general rules such as the CoC
  • host & sponsors (if you have some), I usually give them maximum 5 minutes to introduce themselves while advising for a shorter time – people get bored easily

Then it goes on to announcing talks, as well as different parts of the meetup (break, lightning talks) and tell people that we are always looking for talks and encourage them to approach me to bounce talk ideas around.

If there are small pauses in between speakers (while connecting to the projector) I like to share some related news (new version of major library X released, security vulnerability in Y, conferences) and ask the audience if they also have any news to share. I just don’t like sustained periods of silence while the meetup is supposed to be running.

To get the attention of people and have them be silent a long extended “Shhhhhhh” while standing on the stage usually works best in my experience. Sometimes it’s just enough to stand there, wait and look like you are going to say something. Holding up one hand (maybe with a balloon) also has worked pretty well for me.

Trying to get some attention at a Rails Girls Berlin workshop
Trying to get some attention at a Rails Girls Berlin workshop

Goodbye

For the Goodbye the essential topics are mostly:

  • thanks for coming!
  • next meetup place + time
  • call for talks
  • if there’s an after party place, tell them where it is and where to form a group to get going there
  • ask kindly for help cleaning the space up (stacking chairs, collecting bottles etc.)
  • thank the speakers once again for their talks

And that’s basically it… but don’t forget – after the meetup is before the next meetup and it’s always a lot less stressful to have things already organized a long time in advance. I try to aim for having the venue and a couple of talks confirmed a month in advance, admittedly I often fail at that.

And that’s also an important takeaway here, nothing is ever perfect and it doesn’t have to be. Don’t worry if you don’t get all of this straight, if you forget something… it happens. I’ve been doing this for a long time and I still forget things but usually everything goes just fine. If I forget something, people remind me or ask. People also know that meetups are organized by volunteers, so they  are forgiving and willing to help when something goes wrong.

So, let me know if this helped you or if I forgot to cover something and you have any remaining questions. This marks the end of this little series, so I hope that this helps you get your meetup started or that you got the insight into organizing meetups that your were looking for.

Defining the 5 basics of your meetup

Defining the 5 basics of your meetup

After looking at some things you should be aware of before you start your own meetup. Let’s take the next step and ask: “What will your meetup be like?”. In this post we’ll take a look at 5 basics that will define your meetup. These are:

  • Atmosphere
  • Activity
  • Place
  • Time
  • Refreshments

As always, this is my own opinion and I might have forgotten something. If you find something missing please let me know and I’ll happily amend this post:)

Let’s start with Atmosphere as it is the fuzziest concept but probably the most important one.

Atmosphere – creating a friendly community

When you organize a meetup you create a space where people meet. These people are mostly strangers, especially in the beginning. For the continued success of a meetup it is important to create a welcoming, inclusive and friendly atmosphere. How do we get there?

One of the most important factors here is you, the organizer. Whether you want it or not you’ll lead by example. Your actions and behavior will influence the expected behavior of the group. Be friendly, welcoming, stay humble and approachable. It is important that people can come to you, raise concerns, alert you to problems, give feedback or just for a friendly chat.

Speaking of which, to signal to the outside that you want to create a friendly community that welcomes everyone, who abides by a basic set of rules you should have a code of conduct. You should also be willing to enforce these rules. I’m not going to debate the merits of codes of conduct in detail here as that has been done better elsewhere and this post is going to be very long as it stands. Just be aware that just “having” a CoC isn’t enough. Attendees, especially speakers, need to be made aware of it and you need to enforce actions against violators. Also, don’t roll your own. There are plenty of CoCs for events out there that you can take or adjust. For instance, in Berlin we created the Berlin Code of Conduct, which is based on the pdx.rb CoC, translated it into many languages and you can sign it. You will note the contact information on the web page. It is there so attendees can reach out, request help or report violations.

Activity – what do we do

What do you want to do during your meetup? There are multiple possibilities that vary for the size of the meetup and the organizational effort. Also be aware that you can mix and match these, which often makes sense.

Talks

This is what the meetups I organize mostly do. We have speakers that present about a topic somehow related to the overall topic of the meetup. We usually have 3 talks that are around 20 minutes each. We split that up into 2 talks, a break, then another talk and then lightning talks (or a quiz!).

Talks shouldn’t be much longer than 20 minutes (I usually cut people off at 30 minutes). Not everyone is interested in a given topic, so sitting there for 60 mins hearing about something you are not interested in can be pretty frustrating. Also it’s hard to focus for so long (especially after a work day as most meetups are on week days and in the afternoon). Moreover, it encourages the presenters to focus on the essentials.

Mostly talks are accompanied by Q&A sessions. Q&A is controversial, some people don’t like it at all while others LOVE Q&A. Some Q&A sessions tend to get down into nitty gritty discussions of one very deep topic that is only valuable to the one asking the questions. Moderation is key here, don’t let it get too long (I tend to do ~3 questions tops).

To get talks going it is great to have a way for people to submit talks with abstracts that you can then schedule for the meetup. This is why I love onruby (first class support!) and deplore meetup.com (have fun searching through all your messages and manually adding everything!). You need to inquire if speakers are ready to give their talk at your next meetup rather early as they need time to prepare (2 weeks to a month or more in advance is the optimum, a week works if you are lucky, but isn’t really fair to the speakers) and your need to do all the speaker management as well.

With this sort of setup, the greatest compliment you can get is that your meetup feels like a “mini conference”. It is a great setup to have, but especially with a high number of desired talks it is hard to keep going month after month. You need to have a rather big community to keep this going with good talks. Of course, it is fine to scale down and sometimes just have fewer talks. At the same time it is vital to establish that the community is friendly, talks by first time speakers are very welcome and that you’ll aid with feedback about slides and/or presentations.

Lighting Talks

Lightning talks are very short talks (usually 5 minutes – sharp, no running over!) that therefore often don’t need a big preparation time. I don’t usually schedule them in advance for meetups. I just ask during the meetup if anyone has a lightning talk they want to present and then they can come to me and get started right away.

Sometimes people just show off cool hacks or announce new events. It’s usually a lot of fun. I’ll allow a max of 4 lightning talks per event (so that the event doesn’t run too late), usually it’s less.

Coding Together

Especially in smaller meetups where you can’t prepare talks every time it is cool to just sit together and code learning from each other and trying out something new. In my opinion this is ideally accompanied by an introductory talk/tutorial about a library/pattern/whatever so that people can then get to playing with what they learned straight away.

I watched a talk by the creator of Elm where he mentions that for him doing a meetup about Elm with talks often attracted PhDs while a coding/hacking meetup encouraged newcomers and helped to spread the technology much better. I can’t verify the same for RUG::B (no PhDs and plenty of juniors often) but I can see how newcomers benefit more from a coding meetup and how it might be better for very new technologies, that a lot of people just want to play with. In fact I’d love to start some sort of “hack together” meetup in Berlin, but time is sparse😉

Our local Clojure user group also runs a similar setup (talk + hacking). When I was there I found it very fun, because of the hands on nature and the pure joy of learning from my peers (we played with ClojureScript and Om).

Discussions

When you have neither talks nor coding together, you can also just sit together and discuss. I’ve seen this used mostly in meetups around “agile” development/project management. In a  smaller group (10 to 30 participants usually) participants first propose topics to discuss and in the end it is voted which topics will be discussed. Depending on the venue either all topics are discussed together in the big group as participants chime in or there are multiple topics which are then discussed in different rooms in parallel. The discussions are time boxed and after the discussion is over the findings are summarized for the whole group (especially cool with multiple “tracks” as you get to hear the conclusions of the other groups/topics).

The easiest form of this is to just get together in a Bar/Restaurant and talk about whatever people feel like talking about – rather unstructured. This can be a lot of fun depending on what you are after. I genuinely like people from the community and so it is great for me to get out and get to know them talking about things that aren’t necessarily programming related. We used to have both Ruby Picknick and Ruby Burgers (Berlin style – vegetarian) organized in Berlin, just a friendly get together. People also frequently go to a nearby bar/restaurant after a meetup.

If you choose the “discussion in a bar” as your primary activity, be aware both with the meetup structure and the title that the drinking part doesn’t take the main stage, especially with alcoholic beverages. The concern here is not only about the quality of discussions derailing, but it can also have a repelling effect to people that don’t drink and especially minorities. Some people don’t feel safe in this environment (especially with lots of strangers!) or simply don’t like it by nature.

Quiz

A quiz prepared in advance about oddities, edge case behaviours or “Aha!” features of the technology of discussion has been really successful for us. Usually everyone is pretty engaged trying to figure out the answers plus you learn something. Mostly what you learn isn’t really that applicable but still fun to know.

Examples of what I’m talking about: Ruby Trivia one two and three.

Of course it’s great if you have some sort of prize for people who answer questions. It’s not necessary though, people are fine just answering for the fun and joy of it.

Refreshments – people are thirsty & hungry

Make sure that drinks are available at your chosen venue, either sponsored or for an affordable price. It’s important that there are non-alcoholic drinks (water, lemonade etc.). The presence of alcoholic drinks might depend on your country. In Germany it is rather normal to have beer available at meetups, while I know of meetups in Sweden where there is a conscious decision not to have alcohol at meetups. If you have alcohol at your meetups take care that no one goes over board. Meetups should never be about the drinks, meetups are about the people and the activity (talks, coding..).

Food is optional. It’s great to have food, otherwise people either go hungry for a long time or they have to hurry to get some diner before the meetup starts. However, food for so many people isn’t exactly cheap. It can be more affordable for smaller meetups, though. I know of a couple of small meetups (5-20 people) that have a recurring food + drinks sponsor. I usually ask our hosts if they want to provide food. If they do, great. If they don’t, no problem. If there is food, be sure to announce it in advance so everyone knows. Make sure to also be inclusive with the provided food options. In Berlin we make sure to at least provide vegetarian options and try to provide vegan options.

Venue – where do we meet

The venue for the meetup should be reachable from wherever people mostly work. If you move a bit too far away you can expect a 10 to 30% drop in attendance (+ sometimes frustrated tweets of people who think it’s too far). The place of course should offer enough space for your expected crowd. For talks bigger open spaces mostly work best. If you want to have multiple separate discussion groups then of course you need multiple breakout spaces.

A regular venue is good because people don’t have to look up where to go and how to get there, they just know. It’s also less stress as an organizer as you don’t have to go looking for a venue every time. Often times the regular meeting space is the company at least one of the organizers works at.

However, the Ruby User Group Berlin likes to move around (as from before I took it over). That has advantages as well: You get to know companies from your city, you introduce your meetup to employees of the host company (as they are likely to stick around) and companies that only host the meetup sometimes are much more likely to sponsor drinks and food😀

As usual, there is no best option. I think for a new meetup sticking to a regular venue is easier for organizers and attendees at first. Plus, in order to be able to move around venues every month you need a somewhat large pool of companies willing to host you, meaning your topic/technology needs to be sufficiently “mainstream”. Sometimes special venues also lead to an increased attendance. Our highest attended meetup ever (150 to 200, depending on whose count you believe) was in the brand new SoundCloud office that people really wanted to see, right after it opened.

Time – when do we meet

The most important property of the time is that it should be regular. This way attendees can get used to when it is. RUG::B is every first Thursday of the month at 19:30 unless that’s a holiday or something special. Done, people know that.

Of course check for scheduling conflicts with similar meetups (especially a Berlin problem?) – you don’t want to have attendees having to decide where to go.

As far as I can tell evenings of weekdays, excluding Friday, work best. Give people enough time to get to the venue and also to grab something to eat before arriving at the meetup. In Berlin meetups usually start around 19:00 or later. As people want to get home at some time make sure the meetup doesn’t run too long (admittedly, especially RUG::B often runs late).

There are also meetups that happen in the morning (to be more parent friendly among other things), which is another idea to be explored.

Now that we have the basics down, think about what your meetup should be like. How do you create a friendly atmosphere? What will the format of the meetup be? Where and when do you meet? What refreshments will there be? When that’s all decided, we’re all set up for the first meetup. So the next post will be about running the meetup – from start to finish:)

 

Before you start to organize a meetup

Before you start to organize a meetup

I’ve been running the Ruby User Group Berlin for over 3 years now. Additionally, I’ve been running the React.js Berlin meetup for about a year now. These are meetups with 60 to 90 attendees per meetup right now (ruby used to be 100+) and rather well known. Also I run the lovely rails girls project group “rubycorns” together with Til, bringing you rorganize.it. As a result I regularly get asked “Tobi, how do I organize a meetup?”. So instead of repeating myself I’ll write up some basic thoughts on organizing meetups of different sizes. This is my own opinion based on my experience, so other advice may vary.

As this came out to be rather large on the first writeup I decided to split it up into three posts as follows:

First meetup I moderated. Photo by @wikimatze (link)
First meetup I organized and moderated (back in 2012). Photo by @wikimatze (link)

So let’s get started with the first one:

So you want to organize a meetup?

First of all: That’s great thanks! It’s a valuable contribution to the community! Before we get into the details of what will define your meetup and how to rune a single meetup, let’s see what you’re getting yourself into.

Organizing a meetup is a reoccurring activity that will eat time and energy. Most of the actual work is done before the meetup when you look for locations, talks and coordinate all of that. Naturally there are also communication channels through which you have to be responsive (which I still sometimes fail at) and be active in announcing and promoting the meetup.

I always feel like it’s not that much work, but it always ends up being more work than I normally think. Some sort of passion/excitement for whatever your meetup is about is required to keep it going and help you pick good talks and have a nice atmosphere.  If you’re reading this because you want to organize a meetup solely for your company’s or your own good my tip is simple: Don’t. People will realize and neither your nor them will enjoy the experience. If you enjoy it yourself, it also won’t feel like work, which is probably why I always underestimate the effort:)

Get a team

Also, make sure that you’re not alone – get a team. You’re human, you can’t always deal with everything as there are more important things in life. Be it vacation, sickness or whatever. It’s good to have someone you know to take over the meetup or just to bounce ideas off each other. I mostly do RUG::B by myself these days for instance, but when I need advice or can’t make it I know I can count on Thilo and Nico. And I couldn’t support the rubycorns on a weekly basis which is why I split that with Til. Also sometimes I can’t make it to the react meetup and then Chris & Bodo thankfully take over.

Me (middle) on the first rug_b meetup I moderated (totally nervous). My then organization mentor @freaklikeme to my right. Photo by @wikimatze (link)
Me (middle) on the first rug_b meetup I moderated (totally nervous). My then organization mentor Thilo to my right. Photo by @wikimatze (link)

Also don’t underestimate the “bouncing ideas off each other” part. Should we allow job ads? Is this a suitable talk? Does anyone know a good last minute location? Can we do anything different? It’s vital to have a trusted team to talk about these. Without them the Berlin Code of Conduct would have never seen the light of the day, among other things.

Your Online Identity

Got a team? Great. The next post will talk about what defines your meetup, but you need to get some place to announce it. Your online presence – a website and most likely also a twitter account. Some form of mailing list/forum is also great to have discussions, announce meetups etc.

Lots of meetups are on meetup.com, it is a good place to get started out and be found (there are people that search for meetups only on their home page). However, I don’t really like it (and really want to move the react meetup off there). Meetup gives you messages, comments and a description for scheduled meetups. It’s nice, but for meetups with talks they are missing the whole talk management. E.g. “Which talk proposals do I have?” and “I want to schedule this talk for this meetup”. It’s a hell to manage. Plus the RSVPs are way off, from experience I can tell you that only ~40% to 50% of that people that said they’ll go will actually show up. Plus it costs money. So what are alternatives?

Berlin.js had a nice workflow where they have a github pages website and you submit talks by opening pull requests to the repository to add them to a meetup. I love the simplicity of this. My favorite is on_ruby though, a white label site for ruby communities. It understands what topics are, people can propose them, you can schedule them, there is a maps integration for locations etc. It’s a great solution overall. And I think the site is also open to hosting non ruby meetups. RSVPs have a different “problem” here though, more people show up than are registered:)

Our meetup page - containing all important information at a glance: time, venue (with map), topics, attendees and links to share
Our meetup page – containing all important information at a glance: time, venue (with map), topics, attendees and links to share

For twitter, it is a great and easy way for people to get in touch with you and give your speakers and event some coverage before and after the event. I usually tweet talk teasers in the days leading to the event and photos during talks. Also good for ad-hoc communication like “the door is closed, how do we get out?”.

The mailing list/forum is great to discuss topics further, announce the next meetup date (link to website as the “source of truth”), ask for talks and discuss talk ideas. It can also be used for job ads or other discussions.

These days lots of meetups also have a slack group. The ruby berlin one is quite nice (join here), of course you can also go with the good old IRC but that doesn’t seem to be as hip and cool any more.

Also note, that you don’t have to create and manage all of those yourself or by the team. E.g. I created neither the slack nor the IRC, they were created by members of the community.

Recruiters and other promoters

One of the less well known side effects of running meetups is that you are contacted by a variety of people. Most of them are nice and great people. People who want to give a talk, people that ask if they can help you and people who want to host your meetup. Some are less nice and more nagging though. Recruiters want to promote their jobs at your events and others want to advertise their conferences, workshops or whatever. Be prepared for this and settle on a stance how to handle this.

I “inherited” my stance on recruiters from the previous organizers and it is “no recruitment pitches at the meetup”. Speakers can quickly mention that they are hiring, so can host companies but that’s it. There is a [JOB] tag on the mailing list where jobs may be posted. As for events, community events are fine to announce at the meetup others can also go to the mailing list. “Why?” you ask?

Most developers I know are tired of recruiting messages (enough of that on LinkedIn, Xing etc.). Getting them on the mailing list you can just ignore the [JOB] tag or look at them if you’re interested. Devs usually are at meetups to enjoy talks and connect with peers.

My view on this is enforced by the fact that ever so often I meet Berlin Ruby developers telling me that they stopped coming to the Ruby User Group Berlin 5+ years ago. Their reason (so far) always is because there were recruiters at the meetup somewhat aggressively trying to recruit them, which they found very annoying. So much even, that they never came back. Sad, but true.

That said – meetups are about the participants. I’ll gladly offer some stage time to participants looking for jobs or the like, especially Junior developers.

If you think I’m a bit overcautious, some highlights:

  • Startup founder offered 50€+ plus to be allowed to pitch his startup
  • Plenty of lengthy discussions with recruiters and founders about why they can’t pitch at the meetup and no that is not unjust and not excluding them (pro tip: explain your stance once and then don’t engage in lengthy discussions – sadly I still haven’t mastered this)
  • people wanting to organize their “own” Ruby user group Berlin at their office, announcing that “official” ruby user group Berlin meetup on our mailing list
  • people scraping our website for emails, twitter handles etc. and then writing each member recruiting emails/messages, sometimes pretending they were at the same meetup (Oh I wish this only happened once…)

With that said, luckily this remains the exception. Lots of people understand a simple no and carry on with their lives. Then, of course there also are the nice people wanting to help you, being awesome hosts etc which usually outweighs the others.

It’ll all be alright

If you’re worried now – don’t be. Mostly organizing a meetup is fun. That’s why I do it in the end. I always say that every meetup feels like a birthday party to me – so many great people there that I want to talk to all of them! But I can’t talk to them nearly as much as I’d like because in the end I run around and organize things(tm). And the best is seeing the happy people enjoying the meetup.

Also standing on stage as an organizer for the first time will almost certainly feel weird, but don’t despair – you’ll get used to it rather quickly (at least I did). Also not everything has to be perfect, so don’t pressure yourself:)

Make sure you have a small team (one person is enough) to back you up, an idea about your online presence and then we’re ready to get going with the second step – figuring out the 5 basics for your meetup, in the next post!

Benchmarking a Go AI in Ruby: CRuby vs. Rubinius vs. JRuby vs. Truffle/Graal

The world of Artificial Intelligences is often full of performance questions. How fast can I compute a value? How far can I look ahead in a tree? How many nodes can I traverse?

In Monte Carlo Tree Search one of the most defining questions is “How many simulations can I run per second?”. If you want to learn more about Monte Carlo Tree Search and its application to the board game Go I recommend you the video and slides of my talk about that topic from Rubyconf 2015.

Implementing my own AI – rubykon – in ruby of course isn’t going to get me the fastest implementation ever. It forces you to really do less and therefore make nice performance optimization, though. This isn’t about that either. Here I want to take a look at another question: “How fast can Ruby go?” Ruby is a language with surprisingly many well maintained implementations. Most prominently CRuby, Rubinius, JRuby and the newcomer JRuby + Truffle. How do they perform in this task?

The project

Rubykon is a relatively small project – right now the lib directory has less than 1200 lines of code (which includes a small benchmarking library… more on that later). It has no external runtime dependencies – not even the standard library. So it is very minimalistic and also tuned for performance.

Setup

The benchmarks were run pre the 0.3.0 rubykon version on the 8th of November (sorry writeups always take longer than you think!) with the following concrete ruby versions (versions slightly abbreviated in the rest of the post):

  • CRuby 1.9.3p551
  • CRuby 2.2.3p173
  • Rubinius 2.5.8
  • JRuby 1.7.22
  • JRuby 9.0.3.0
  • JRuby 9.0.3.0 run in server mode and with invoke dynamic enabled (denoted as + id)
  • JRuby + Truffle Graal with master from 2015-11-08 and commit hash fd2c179, running on graalvm-jdk1.8.0

You can find the raw data (performance numbers, concrete version outputs, benchmark results for different board sizes and historic benchmark results) in this file.

This was run on my pretty dated desktop PC (i7 870):


tobi@tobi-desktop ~ $ uname -a
Linux tobi-desktop 3.16.0-38-generic #52~14.04.1-Ubuntu SMP Fri May 8 09:43:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
tobi@tobi-desktop ~ $ java -version
openjdk version "1.8.0_45-internal"
OpenJDK Runtime Environment (build 1.8.0_45-internal-b14)
OpenJDK 64-Bit Server VM (build 25.45-b02, mixed mode)
tobi@tobi-desktop ~ $ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    2
Core(s) per socket:    4
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 30
Stepping:              5
CPU MHz:               1200.000
BogoMIPS:              5887.87
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              8192K
NUMA node0 CPU(s):     0-7

First benchmark: Simulation + Scoring on 19×19

This benchmark uses benchmark-ips to see how many playouts (simulation + scoring) can be done per second. This is basically the “evaluation function” of the Monte Carlo Method. Here we start with an empty board and then play random valid moves until there are no valid moves anymore and then we score the game. The performance of a MCTS AI is hugely dependent on how fast that can happen.

Benchmarks were run with a warmup time of 60 seconds and a run time of 30 seconds. The small black bars in the graph denote standard deviation. Results:

19_19_ips.png
Full 19×19 playout, iterations per second (higher is better)
Ruby Version iterations per second standard deviation
CRuby 1.9.3p551 44.952 8.90%
CRuby 2.2.3p173 55.403 7.20%
Rubinius 2.5.8 40.911 4.90%
JRuby 1.7.22 63.456 15.80%
JRuby 9.0.3.0 73.479 6.80%
JRuby 9.0.3.0 + invoke dynamic 121.265 14.00%
JRuby + Truffle 192.42 14.00%

JRuby + Truffle runs on a slightly modified version of benchmark-ips. This is done because it is a highly optimizing and speculative runtime that leads to bad results after warmup. This is explained here.

Second benchmark: Full UCT Monte Carlo Tree Search with 1000 playouts

This benchmark does a full Monte Carlo Tree Search, meaning choosing a node to investigate, doing a full simulation and scoring there and then propagating the results back in the tree before starting over again. As the performance is mostly dependent on the playouts the graph looks a lot like the one above.

This uses benchmark-avg, which I wrote myself and (for now) still lives in the rubykon repository. Why a new benchmarking library? In short: I needed something for more “macro” benchmarks that gives nice output like benchmark-ips. Also, I wanted a benchmarking tool that plays nice with Truffle – which means doing warmup and run of a benchmark directly after one another, as detailed in this issue.

This uses a warmup time of 3 minutes and a run time of 2 minutes. Along with the iterations per minute, we have another graph depicting average run time.

19_19_ipm.png
MCTS on 19×19 with 1000 playouts, iterations per minute (higher is better)
19_19_avg.png
MCTS on 19×19 with 1000 playouts, average run time (lower is better)
Ruby Version iterations per minute average time (s) standard deviation
CRuby 1.9.3p551 1.61 37.26 2.23%
CRuby 2.2.3p173 2.72 22.09 1.05%
Rubinius 2.5.8 2.1 28.52 2.59%
JRuby 1.7.22 3.94 15.23 1.61%
JRuby 9.0.3.0 3.7 16.23 2.48%
JRuby 9.0.3.0 + invoke dynamic 7.02 8.55 1.92%
JRuby + Truffle 9.49 6.32 8.33%

Results here pretty much mirror the previous benchmark, although standard deviation is smaller throughout which might be because more non random code execution is involved.

Otherwise the relative performance of the different implementations is more or less the same, with the notable exception of JRuby 1.7 performing better than 9.0 (without invoke dynamic). That could be an oddity, but it is also well within the margin of error for the first benchmark.

For the discussion below I’ll refer to this benchmark, as it ran on the same code for all implementations and has a lower standard deviation overall.

Observations

The most striking observation certainly is JRuby + Truffle/Graal sits atop in the benchmarks with a good margin. It’s not that surprising when you look at previous work done here suggesting speedups of 9x to 45x as compared to CRuby. Here the speedup relative to CRuby is “just” 3.5 which teaches us to always run your own benchmarks.

It is also worth noting that Truffle first was unexpectedly very slow (10 times slower than 1.9) so I opened an issue and reported that somewhat surprising lack in performance. Then Chris Season was quick to fix it and along the way he kept an amazing log of things he did to diagnose and make it faster. If you ever wanted to take a peek into the mind of a Ruby implementer – go ahead and read it!

At the same time I gotta say that the warmup time it takes has got me worried a bit. This is a very small application with one very hot loop (generating the valid moves). It doesn’t even use the standard library. The warmup times are rather huge exactly for Truffle and I made sure to call no other code in benchmark/avg as this might deoptimize everything again. However, it is still in an early stage and I know they are working on it:)

Second, “normal” JRuby is faster than CRuby which is not much of a surprise to me – in most benchmarks I do JRuby comes up ~twice as fast CRuby. So when it was only ~30% faster I was actually a bit disappointed, but then remembered the --server -Xcompile.invokedynamic=true switches and enabled them. BOOM! Almost 2.6 times faster than CRuby! Almost 90% faster than JRuby without those switches.

Now you might ask: “Why isn’t this the default?” Well, it was the default. Optimizing takes time and that slows down the startup time, for say rails, significantly which is why it was deactivated by default.

If I’m missing any of these magic switches for any of the other implementations please let me know and I’ll add them.

I’m also a bit sad to see rubinius somewhere between 1.9 and 2.2 performance wise, I had higher hopes for its performance with some appropriate warmup time.

Also opal is notably missing, I couldn’t get it to run but will try again in a next version to see what V8 can optimize here.

An important word of warning to conclude the high level look at the different implementations: These benchmarks are most likely not true for your application! Especially not for rails! Benchmark yourself:)

Now for another question that you probably have on your mind: “How fast is this compared to other languages/implementations?” See, that’s hard to answer. No serious Go engine does pure random playouts, they all use some heuristics slowing them down significantly. But, they are still faster. Here’s some data from this computer go thread, they all refer to the 19×19 board size:

  • it is suggested than one should be able to do at least 100 000 playouts per second without heuristics
  • With light playouts Aya did 25 000 playouts in 2008
  • well known C engine pachi does 2000 heavy playouts per thread per second

Which leads us to the question…

Is this the end of the line for Ruby?

No, there are still a couple of improvements that I have in mind that can make it much faster. How much faster? I don’t know. I have this goal of 1000 playouts on 19×19 per second per thread in mind. It’s still way behind other languages, but hey we’re talking about Ruby here😉

Some possible improvements:

  • Move generation can still be improved a lot, instead of always looking for a new valid random moves a list of valid moves could be kept around, but it’s tricky
  • Scoring can also be done faster by leveraging neighbouring cells, but it’s not the bottleneck (yet)
  • a very clever but less accurate data structure can be used for liberty counting
  • also, of course, actually parallelize it and run on multiple threads
  • I could also use an up to date CPU for a change😉

Other than that, I’m also looking over to the ruby implementations to get better, optimize more and make it even faster. I have especially high hopes for JRuby and JRuby + Truffle here.

So in the future I’ll try to find out how fast this can actually get, which is a fun ride and has taught me a lot so far already! You should try playing the benchmark game for yourselves:)