 Hi, this is what I learned to love about Ruby when I switched to Python. I tried it out on some Ruby coworkers. I did not massively offend anyone, so I feel that it's safe. This is a little bit about me. I'm a senior software engineer at Flatiron Health. Flatiron Health is an oncology data company. We use cancer data to accelerate cancer research and improve patient outcomes. I occasionally write things at theforthparty.com and also at flatiron.engineering. Prior to coming to Flatiron Health, I'd worked exclusively in Ruby stacks about half dozen different Ruby stacks. And Python was my first foray into, sorry, Flatiron was my first foray into a Python company. I tried to find some photos to paint the picture for you. I found a photo of a happy hour, a photo of Puppy Day, and a photo of my current coworker and I with a Yeti. I learned that I don't take photos of my offices, so we'll jump right into the languages. How many people here have worked with multiple stacks in your day jobs professionally? A ton of people, awesome. And how many people here have tried to learn a second language that wasn't your native language, a spoken language? Also a bunch of people, awesome. I know that a coding language and a spoken language is obviously different, but I'd like to draw a comparison here and start by talking a little bit about language in general. So this is a quote from a researcher from University of California, San Diego, Lara Boroditsky, and the premise here is that language contains a way of perceiving, categorizing, and making meaning in the world that languages give us a habit of thought. They give us a framework in which to understand our world. There was a theory, like 70 years ago, that a language could limit the way that we understood our world. So if I'd never learned the word happy, I could never experience happiness. It was widely debunked by common sense and also lots of research. This is a new philosophy that we're not saying that a language limits the way that you think and limits your capacity, but rather that a language, again, gives you these habits, gives you these natural tendencies in the way that you shape and interact with your world. So there's four things I'd like to talk about in this context, the principle of least surprise, version management, defaults and their consequences, and the philosophy, all in the context of Ruby. So first, I learned to love and dearly miss the principle of least surprise. Let's talk about what this is first. David Hannah Meyer Hansen has a great excerpt on this from The Rails Doctrine. The basic premise here is that Ruby should behave the way that you expect it to. There's a big caveat here. If you are brand new to coding, nothing behaves the way that you expect it to. But if you have some degree of experience and you're in an interactive Ruby console and you type exit, it exits. And if you type quit, it quits. If you are in a Python console and you type exit, it says, did you mean exit? Open parentheses, close parentheses or control D to exit. I find this extremely surprising. Obviously it knows what I'm going for. I am not allowed to exit the program. I literally never get this right, ever. And I get this message, and then every time I write out my parentheses and we try this again. So here's that caveat, which Matz acknowledges himself. The principle of least surprise is premised around Matz because Matz is the author of the language. But as you gain experience with the language and I have found over time that this is increasingly true for me, that there are fewer surprises. And it's like the program is designed to do what I expect it to do. And I think this is really lovely. This is in direct contrast to my Python scripts and my Python consoles that die on white space errors every time. It's like a 15 spaces or a 16 spaces is some sort of existential crisis and the whole thing crashes and burns. This is actually mostly surprising during web development. I'll be working through a web app. I will accidentally space the wrong way. I flip over to my browser. I refresh my page. Everything is dead. Again, I find this surprising. And this didn't come lightly. This came with a lot of work. So Matz had to jump a lot of hurdles. Again, from DHH, I really love this quote, to smile at and flatter its human co-conspirator. I like the idea of a language and I working together. I like the idea of a language responding to me and acting as a compliment to what I am trying to do. I think it's really beautiful. Here's an example, some really simple Ruby code. We have an array. We can run the collect method on the array, multiply it by two. We can collect with an exclamation point and it affects our original object. This is a differentiation of the exclamation point. An exclamation point alters the original object. The method without the exclamation point does not. I think this is really intuitive. I find it hard to remember, memorizing documentation of anything isn't really my jam, but I find it hard to remember when I'm affecting the original object and when I'm not. And I think this is an important distinction. The other thing that Ruby excels at in this area is synonyms. Python is famously one way to do things. Synonyms are an anathema to the Python language. Ruby has a ton of them. Collect and map are exactly the same. The word that comes to you first is the word that you should use and go for it. A lot of times companies will have style guides recommending one option or the other. They'll have a personal preference, but when you're on your own, whatever you like works for Ruby. You see this right down to the documentation. The documentation for find is exactly the same as the documentation for detect, and the code samples includes both. This is the same code block as used for both. You can see these two are the same. These are the synonyms. I tried to find the actual list of synonyms online. I don't know if there exists a list somewhere. If there is, someone should send it to me. Searching for Ruby synonyms gets some really lovely gems. Not a lot about the language itself. Actual jewelry gems. There's one more thing I think is really nice and unsurprising, or rather that helps embody this principle of least surprise is the question mark and a method name. A question mark to me says a yes or a no, a true or a false. And I can use that in my methods that I'm offering to really further this principle of least surprise. I can make my code less surprising for the future people who read it, and Ruby sets me up well with this pronunciation to be able to do that, to be able to imply that significance to my future readers. So that's the principle of least surprise, also known as safely ignoring whitespace and not being an exact memorizer. Next up, I learned to love version management so, so much. I do this graph of a timeline of Ruby and Python over the last few years. Let's look at Ruby first. So Ruby 2.0.0 was released in February of 2013, the last major release of Ruby. Ruby 2.0 was released in December, 2014. In April of this year, it entered security maintenance mode. A version of Ruby has three modes, normal mode in which it's fully supported, bug fixes and security, a security mode where security patches are supported and an end of life where it will no longer be patched but you can probably pay a third party company to pick up a patch version of the language. 2.2.0 is about two and a half-ish years in normal mode. It'll spend one year in security mode and after that it'll be end of life. That's about three and a half years start to finish. If we take a look at Python, I actually had to triple check these dates because I was so shocked that Python 3 predated the most recent major release of Python 2.7. Python 3.0 was released in December of 2008, Python 2.7, which is the most recent major version-ish, I mean technically a middle number, but Python 2.7 in July of 2010. Python 2.7 will be end of life in 2020 in April. It's 10 years start to finish for a version of a language. Python 2.0 to Python 3.0 is a breaking change. Every organization that has Python 2.0 will have to refactor their code to get to Python 3.0. And in fact, when Python 3.0 was introduced, there was a ton of complications. All of a sudden every package we had, every library we had, every support in the community was split between two and three. And maybe the tools in the libraries you wanted existed for one and not the other or vice versa, but you had to pick where you fell on that side of the line. Flatiron Health was founded after 3.0 was released and is a Python 2.0 company. And we have two and a half years for that to no longer be true before we are in a different situation. I think this is really impactful on the cadence of development in the community. Twitters in context, like I said, I've worked with roughly a half dozen Ruby stacks. I've never worked with a Ruby stack that I haven't seen upgraded at some point where I've worked there. I've never worked with a Python stack where I've seen it upgraded. So super different impact on the community. How will we get new features? How will we get the latest and greatest? How will we get the speed improvements? It really has a downstream effect on everybody using your language. And I can't tell you how much I miss being able to say, hey, there's a new version out and it's got some really cool stuff. You know what we should do? Go and get it nice and easily. This is a Python clock. Somebody is maintaining at pythonclock.com to count it down as we approach this dire date. Also in the space of version management, I wanna talk a little bit about packages. Some of you may be familiar with the Ruby version manager or the RBNV manager. How many of you are RVM users? Great, an RBNV. Okay, it's actually a fairly big split. I know that these two can be a touch polarizing. I've witnessed some very heated discussions over which one of these never should have been that way. Polarizing or not, both of these are fantastic compared to what I have at least seen as commonly used in the Python community. And what I think is really great about these is that inherent in both of these tools is the bundling of the rubies with the gems. I was practicing this talk and I was practicing saying rubies and pythons and I realized I'd never said pythons before. It's just not a thing that we say. But rubies coupled with gems where I can switch from environment to environment, I can make the transition to an upgrade super effectively. I can make this path, I have the tools at my disposal that I am familiar with in order to progress through the development of the language. The same isn't true in Python. If there isn't this common adoption of dealing with multiple pythons at a time, how will I get from two seven 10 to two seven 11 or way worse, how will I get from two to three? There are two tools that are fairly common in the Python community in this space. One of them is Anaconda and the other one is Python Virtual M. Let's look at Anaconda first. Anaconda is primarily targeted at data scientists. It is a bundling of Python with the packages. I think it's really heavyweight. Out of the box, Anaconda contains over 100 packages. So if I just wanna work on a light web app, it probably isn't the right fit for me. It does have that bundling that RVM and RVM can offer. But again, it's a strong, powerful solution. Virtual M can bundle my packages for me. It can keep me isolated in one container, but it doesn't bundle Python with it. It is packages alone. So if I have a machine with Python two seven three on it and I have a virtual M, I have a really hard time switching from a virtual M for those packages to a Python three virtual M. I need some other tool. Some kind soul has ported RVM for PyM. This is not the real logo of PyM. It actually doesn't have one. And I made this by putting the PY on top of the RB. So don't try to look it up like this. But it is there. In my experience, it's not in common use. You can see how RVM is used here for multiple rubies on the machine. I can have a local. I can have a global. I can have this grouping. You can see PyM. PyM can actually be used to install Anaconda. So I can just use Anaconda out of the box as well. And I can have a Python two seven and a Python three six on the same machine. And I can flip back and forth. Again, this sort of solves the problem. It doesn't solve the problem if it's not widely adopted because it doesn't improve that cadence for the community as a whole. Last, let's talk about gems. This is a gem file, a selection of a gem file from installing a Rails gem out of the box. So I install Rails. I open it up. I get this gem file and a couple of gems here. You can see the version numbers. It's heavily annotated so I know what I'm working with. And if I run bundle install, I also get this gem file lock, which tells me the version numbers of everything I'm working with. This is highly transparent. It's in a file. I have every version number. I know my constraints and I know my range. This is so beautiful. I used to think some other thoughts about gem files, but I miss them so, so dearly. Because my Python alternative just doesn't have this level of transparency. A Django tutorial, if you run it out of the box, you don't actually get a requirements.txt file, which is what Python will sometimes use to articulate these dependencies in a similar way to a gem file. And if you run a pip freeze to check your dependencies, you don't get what's under the hood. You get the top level versions, but I don't even know if Django is depending on something that is incompatible with something else I would install right next to it. And especially because of the dangers of two, Python two and Python three, I don't know what complications I could cause in this moment. So that's version management, also known as lots of rubies and all their dependencies living super happily side by side, one big happy family. Let's take a look at defaults and their consequences. So my argument here, or rather somebody else's argument here, is the defaults make a difference. This is the last line of a paper called do default save lives. So in 2003, it's by Goldstein, and who's one of those things? Johnson, Johnson and Goldstein. And the paper is about organ donation. So the question of the paper revolves around this diagram. As you can see in the gold, you have opt-in rates of organ donation, and you see in the blue, opt-out rates of organ donation. You might look at our gold countries and think a lot of things. They could have religious hesitations. They could have cultural hesitations. Maybe they just really, really hate organ donation, or maybe they just really, really hate their neighbors. The difference between these two categories is a checkbox. On the left, in the gold, you are required to check a box to consent to organ donation. On the right, I don't want to imply that it's a checkbox. Sometimes there are actually fairly significant institutional hurdles to getting out of organ donation, but you have to opt-out. So this is explicit consent versus presumed consent, and it's about a 60-point difference. So if we think about that, this opt-in versus opt-out and the consequences of it in terms of our frameworks. Again, let's talk about Rails and Django and start with Rails. If you start with Rails as a brand new developer, you can go to the Rails site and you'll see the Rails guides. You see a tutorial. We can go through the tutorial actually and get to a running web server that interacts with the database, about 14 commands. Let me see our versions here. We're gonna start up a controller. We're gonna generate a model. We're gonna migrate our database and run our server. Fairly lightweight, fairly familiar. We'll get a page on to input to post our article where we can put in the title and text. We'll save the article and we'll get redirected to this page that shows our title and text. As you may have guessed, the tutorial is to build a lightweight blog. And behind the scenes, we're gonna get this. This is our Rails console, which I hope you can see. And I'd like to look at what is actually here. So at the top of our Rails console, we get a lot of environment information. We're running Puma, we're running Rails. We have Ruby, we have a certain number of threads. We're listening on this port. Once we get down a little bit into our console, we see our web request. We see the parameters that we're posting back to the web server. We even see more robust parameters than what we could see on the page. We see that we're running UTF-8. We see an authenticity token. We also see our database interactions and our database parameters. We see how much time it takes to interact with the database and our render time. A lot of you have seen Rails consoles before, so I'm sure we're articulating things that many of you work with on the day-to-day, but I really wanna call out the level of detail here. Rails ships with three default configurations, development test and production. There are all sorts of defaults in here. We don't care about caching locally. We don't care about eager loading locally. We do wanna kill the server if we don't have a migration that has been run yet. We are articulating all of these in this development file. Importantly, we actually don't mention the log level in the development file. Of the three files that ship with Rails, production is the only one that mentions a log level and it's set to debug. Debug is the lowest level of Rails logging. There are six. It is also the only one that shows you database logging. Why do we set the log level in production and nowhere else, when in fact everywhere is defaulting to debug? To me, this suggests that production is the one where I'm most likely to change it. So in my development file, I get a set of defaults that there is an implication that maybe I wanna adjust these. The same is true of my test file and the same is true of my production file. But by shipping with these, Rails makes suggestions on what they should be. It suggests to us what is important in each of these environments and how we should distinguish them. So if we look again at this Rails console, this robustness of information is built in to this tutorial, is built in to how new developers interact with Rails out of the box. Let's take a look at Django. Django is very similar on its website, has a nice tutorial. We're actually gonna build a polls application this time so that we can poll. We work through our tutorial, we get about six lines in and the tutorial informs us that we should see a pleasant light blue box with the words, it works. So we run our web server and actually the first thing we see is a security error. Local host 127.001 and 0.0.0.0 are not authorized to access a Django development server out of the box. I of course Googled this and I got this nice stack overflow answer from four months ago. It only has a small amount of views, roughly 3,000 at last count. I was not the only one who found this surprising. But we add this to allowed hosts, we get our light pleasant blue and we can proceed through our tutorial. Again, about the same number of commands. Couple different things are happening here. We've edited that allowed host file so we've got the security there. We started both a project and an app. Migrations are included here as well and then we're running a command that says create super user. Out of the box before we get to a running interactive version of a website, in Django, we're creating a super user. We're creating an administrative backend for this application. And when we run the server, in fact the first web that we're exposed to is this one. The administrative super user endpoint to manage our polls, to manage our users and to manage our groups. This is a very different emphasis on what's important. First of all, it's pretty. There's lots of CSS, it's all dressed up, it is super usable. Secondly, the implication here is that we're gonna need this. So whatever you're building your web server for, we're gonna need a super user outside, like right out of the box. If we take a look at this console, compared to Rails, this is extremely quiet. The one thing that we see here that we don't see in Rails is server reloads. You see them there as performing system checks. System checks identified no issues. It's funny because even if it did identify an issue, say something like white space, it would just die. I wasn't able to get it to identify an issue where it didn't die. But in theory, we reload, we continue. We get web requests, we get timestamps, we get HTTP status codes, no parameters, no database, no, really not that much environment information besides the Django version itself. So really different, I'm gonna call it a different energy. This actually looks to me a lot more like a production web request blog, as opposed to a development web request. If we take a look at the Django configurations, the first 30 lines of the Django configurations are referencing security, security, security, security. But then there's this line highlighted in red here that these settings are unsuitable for production and should only be used in development. So we both have this massive emphasis on security and the fact that this is for our local environment. I think it is debatable what we want a brand new engineer running through a tutorial to focus on. I think it is telling that these applications focus on such different things. Django teaches me to focus on administrative purposes out of the box. It teaches me to focus on security out of the box. Rails teaches me to focus on timing and to focus on my database. It's a really different direction to send a programmer in and to increase their sensitivity to at the very beginning of their work with this language. If we sum these all up side by side, we get the sense that Rails does have this much more robust information about what's important. This is also rather ironic because Ruby and Rails are often cited as the magical languages. Everything's happening under the hood. And yet I'm pretty sure there's a lot of stuff happening under the Django hood that I am not privy to. When we give new developers our consoles, whatever they may be, when we set the settings at our more established organizations, we're probably, we've tweaked these, we influence the way that they develop. The reason that I called out this example, the reason I added this to this talk is because when I left Rails to move to Python, I lost my database logging and I didn't notice. Wasn't configured, it wasn't turned on, I saw a console, whatever, work proceeds. And then one day I slowed a website down from a regular load time to a 10 second per page load time and I went looking for my database logs and actually couldn't figure out how to get them into Flask, I ended up tailing my Postgres log. And when I did, I found I was making the same rather slow query 10 times a page because I wasn't passing the variable around correctly, I was just redoing it. And I found that I was not nearly the only developer who had done this. In fact, every page of our application requested the user information eight times. When you don't have transparency into this, you don't teach people to look for it. Consider that every policy must have a no-action default, again from our organ donation paper. If you do nothing, there is still an implied direction. If you pick nothing, if you have an absence of choice, people still understand it as a suggestion. And the implication is that the majority shouldn't have to change it. And we see it in organ donation and we see it in configurations. We should be really sensitive to this. And I really miss the sensitivity built into Rails that I don't think I ever understood or appreciated at the time. So that's defaults and their consequences, also known as training beginners with principles that I personally think are extremely valuable. Last but certainly not least, I loved to learn the philosophy. I loved to, I love the philosophy of Ruby, I really learned how much I missed it. If we go back to language here, a language offers a window on a culture's dispositions and priorities. And I think Adam actually set me up really nicely for this. It matters the way that we talk to ourselves. So let's think about how we talk to ourselves in Ruby and in Python. Fair warning, it's fairly different. So these are our two founders, our language founders. On the left, we have Yuka Hiramatsumoto, the author of Ruby. And on the right, we have Guido Van Rossum, the author of Python. Both of these guys have pretty significant cults of personalities. I'm guessing that most of you have heard their names before, that we know who they are. People seem to nod, exactly. We know who they are, they're important, they're part of the origin stories of this language. And we talk about them differently. In Ruby, we talk about mats. And we say mats is nice and so we are nice. Those of you who know me might know that I'm actually not that big on niceness per se. I think it can have a stifling effect on how we talk to each other. We should be direct, we should be welcoming and respectful, but we should be direct. So I'm gonna say that mats is nice and so we are respectful. I'm in a soire, if you will. But whether it's nice or whether it's respectful, this is a super different conversation than a benevolent dictator for life. I think it is fantastic that Guido steers the ship. I think he is the captain, he steps in at the right point. He was one of the main authors of the Python 2 to Python 3, and he made a hard decision for that language in one that can have a really great effect on his community. But I think it's telling. When we talk about niceness and we talk about dictators, it's a different thing that we're telling ourselves. My language is nice, and my community is nice and welcoming and respectful to each other. My language has one way to do things, and my language has a benevolent dictator for life at its head. There's one more way we talk about these two. We talk about the joy of Ruby, and we talk about the zen of Python. I by no means invented these terms. I stole them from the internet. When we talk about the joy of Ruby, we talk about developer ergonomics. We talk about magic, and it's very playful rhetoric. It's a very, really it's enjoyable, it's fun. And then we talk about the zen of Python. We talk about one way to do things. We talk about things being Pythonic. This one way to do things, I actually find a little grading. There are fewer, if any, synonyms in Python, absolutely, but I can still write a for loop and a while loop, and I'm pretty sure I can accomplish the same things. There are ways to do things in more than one way, even in Python, and yet that's the party line. One way, Pythonic, very consistent. I gave this talk to a set of Python developers, and they asked me if I thought Ruby was harder to contribute to as a team, because there were so many ways to do things, how could you ever agree? And truly, I had never thought of anything like that before. I think they really overestimated the number of synonyms that we have. But I thought it was really telling that it was seen as a challenge to overcome for a team, that we couldn't find a consistent way to agree on things. Again, I make no personal preference besides the one that I'm subtly stating throughout this, but I think, I do think it's important. It matters the way we form these habits of thought. It matters the conversations that we have with each other, and I think it trickles down into the way that we interact and the way that we actually use these tools that we're using every single day. Liz Bailey made a call out to Why the Lucky Stiffs poignant guide to Ruby, which I will call out here again. This was actually authored in 2005, which is why in the top left corner there, you can just see live TV in the year 2012. I didn't personally see this on TV that year, but that's all right. This is chapter one of Why's poignant guide to Ruby. It's incredibly playful. I love the idea of the cavity of my body being filled with avocado and mayonnaise whip. It came with a soundtrack that I think Why authored himself that would play alongside as you learned Ruby. It's so much fun. It's so welcoming, and it says anybody, anybody can do this. I don't wanna go too hard on Python, so I will call out that there is also a lot of joy and simplicity for the new people joining the Python community as well. There is an anti-gravity module that you can import that will return you a random XKCD comic. The author of XKCD himself is a huge fan of Python, and it is still a fantastic language. So that's philosophy, also known as being super welcome and having fun with the tools that we're using every day. So where does this leave us? I wanna take one more minute to talk about Python. Python as a language is actually a multi-master language. When we think about Ruby, we often think about Rails. They're coupled so tightly together that when I was looking for examples of how to demonstrate Ruby and how Ruby behaves, a bunch of people gave me Rails examples because they conflate the two because they're such a tightly coupled tool set. Python, on the other hand, has three distinct categories of its community. Systems administration, web development, and data processing, ETL work, all kinds of fantastic things you can do with data in Python. And I really respect this in Python. First of all, it's really powerful. Secondly, it's a really challenging hurdle. So even if you are upgrading as a community and presenting these challenges to your community, to be able to upgrade from two to three a massive breaking change for three separate sets of your community is much, much harder, much, much more impactful. And I think for Flatiron Health, Python is absolutely the right tool. We work with a massive amount of data every day. We want our quantitative sciences team, our systems administrators to all be able to converse and to work with our data in a really consistent way. That being said, for all the reasons listed here and many more, I maintain my Ruby fangirl status and I'm very proud to be a member of the Ruby community. Thank you for having me.