We're walking me back downtown to Atlanta, to Mercedes Benz Stadium. You ain't ready, you ain't ready, man. Third and a mile for Atlanta, and a fire down, and Cod Zacchaeus, first down. From under center, Marriota's going to keep it in sneak for the touchdown. How about you Marcus Marriota, in the scramble for the ball, and it's over.


Biking obviously takes me places physically, but it also takes me places emotionally. Adventure cracks open my heart. It doesn't have to be on the other side of the planet either. Adventure is anywhere there's an open sky and an open mind.


Hi everyone, my name is Erin Buchanan and I'm here to teach you today about the R package MOTE. MOTE stands for Magnitude of the Effect or Measure of the Effect. We actually picked one a long time ago and we forgot, so whatever it says on GitHub.  So you can use this package on many types of effect sizes that you would find in reported research like D, R squared, eta, G E S, and omega squared. So let's check out how to do this. I built a little template markdown. If you have not installed MOTE, it is available on CRAN, so you just simply use installed packages. You can also install it directly from GitHub. I won't run this because I have already installed it, but you should at first install that package. I do assume you have some knowledge, working knowledge of R when you are watching this tutorial. To work today, I'm going to load MOTE, dplyr, because it's my favorite, and easy, so I can show you an example of an ANOVA. So let's run all those bad boys. Cool. So the first thing I really want to do is say that we spend a lot of time on the help pages, so I hope that you look at them. And so to look at those, you can just do question mark or and type MOTE as a package, or come over to the packages window, find wherever MOTE is at, and click on it. Click on the name and not just the description, but then we have a whole bunch of examples. So here are all the things that MOTE includes so far, but it is an actively developed package when I get a break, but we have in general, the rule is that the name of the function starts with the effect size you're calculating. So everything that starts with the D is for Cohen's D or some form of T as an effect size. Everything that starts with Delta, his glasses, Delta, right? Epsilon, eta, GES for the generalized effect size, right? Odds ratios omega, R, and chi-square, so Kramer's V. The other things to say data next to them are example data points from each of these particular pages. So if I click on eta here, it tells you about the function, the usage for the function, so how, what all the arguments are, a description of what you should put in each argument for these functions. The details where we tell you what the formula is for the function, right? So this is how eta squared is calculated, given the inputs that you put in. You can click on this link to go to the example page that has even more stuff on it. It still works, fingers crossed. This will render in latex format after it thinks for a hard while and you can read it a little better. It has an example from each page. Now, the website has more examples and these might be really good for your students who are trying to translate output from different statistical programs, right? So here's an example from JAS, an example from SPSS, an example from SAS, and how that function runs in R. In a different video, I'll teach you how to use the online shiny app version of this. So it explains all of the outputs that you'll get once you run this effect size code and then examples. So these examples are all from like intro stats books, but it shows you how to calculate something. So all of these examples will work directly from the code. So you can just copy them or actually I think you can just click run examples and it will show you the output where it won't get hit enter and you'll get output. So we put a lot of time and effort into that documentation. I would love for you to look at it. Now, what all do we have? Well, we have the main effect sizes that you will find in the literature, other effect sizes forthcoming, but mostly the common pairwise test the glasses delta G and then the common linear model tests, right? So eta, omega, generalized effect size, the one for chi-square, Kramer's V, and some odds ratios. So we have a good number of those different effect sizes and they are based on the type of research design that you have. And then I will say that if you're writing your markdowns in R, maybe with the fabulous papaya, you can also pull out the effect sizes in latex format and tell it to print directly. It mostly works in PDF-nitted versions, but it will format it in APA style for you. So let's look at a quick example, two quick examples. So to do this, I'm going to use the Palmer Penguins data from the Palmer Penguins package in R. It's a really great package if you are tired of iris or empty cars. And I'm just omitting the missing data from the Penguins data set. So it's got a list of penguins, their species, their buildings, their body mass, and gender. And so I'm going to use TAPI. You can also do this with dplyr and do calculate by groups. But one thing that we've done so far with Moet is simply entering the numbers directly, but you don't want to type them because typing them directly means you might make a typo or this won't be dynamic with changes in your code. And so what you can do is save your mean, your standard deviation, and your sample size. So let's look at those. The body mass difference, it does seem that females are lighter than males in penguins. The standard deviation for that body mass and grams and the sample sizes for each of those. Okay, so how many of each do I have? Now that is two distinct groups of data. So this is between subjects effect size. And since there's only two groups, I can calculate d. I can also calculate r, but for a lot of folks d makes more sense as the magnitude of the difference between them, as opposed to the correlation between them. So we'll do d dot i and d for independent samples dot t. And again, if you're not sure what you're supposed to enter, use a question mark. So i and d meaning independent samples, t test as the test. If I did i and d dot t dot t, this was before I've figured out that Python does lots of dots, so please forgive me. i and d dot t dot t means I want to calculate d for independent samples, t test on the t value. So you can convert directly from t. However, it's usually better to convert directly from the means, so that's what we'll do. And these two, they're equivalent in repeated measures tests. They may not be equivalent. So we'll say mean one equals mean one. Mean two equals, sorry, too much scrolling. Mean two, standard deviation one, standard deviation two. I should label this better. In one and into, you can see all of those listed if I back up in order that you're supposed to write them in. And this way I'm just saying for the first mean and standard deviation, compared to the second mean and standard deviation, my alpha, my significance level is 0.05, that means I'll get a 95% confidence interval. So let's see what happens. Well, I saved this on purpose so I could show you that it prints a ton of output. One way to look at it is just print it out. The other way to look at it is use the environment and look at everything. So we'll give you the effect size with its label, so d, low and high, the 95% non-centralized confidence interval for that effect size. And then for this statistic, we actually will give you the mean, standard deviation, which you entered directly, but also the standard error, the confidence interval for that mean, right, based on its standard error and sample size, mean two, standard deviation, standard error, and that's confidence interval, s pooled and standard error pooled, which are part of the calculation, a for t and one and two, the degrees of freedom, t and p. So you actually get like the entire t-test, including the really fancy way to put it out into your document. So if I wanted to print this in late-time format, I could say effect dollar statistic, which will print the t-test statistic, okay, the dollar signs will give it the right appropriate formatting look in late-time. And so I could say, wow, that's a really big effect size. And I could also do effect dot, I forgot, estimate, okay, and that'll give you the estimate for Cohen's D. Notice here that it's got this s statistic, okay, that's Cohen's D for independent samples, okay, that's from the Lakin's paper on the best way to label all these different versions of the what's called Cohen's D. And so this will print for you in nice pretty APA format in latex style if you're using that. Otherwise you can grab each piece one at a time, effect dollar D, dollar mean, etc. Now that's how we might look at t. Let's look at a effect size for ADA. Okay, so I'm gonna use easy ANOVA for this example because it's one of my favorite ANOVA functions because I can make the output match SPSS kind of easily to show people that they do provide the same answer. I do have to have an ID number for easy ANOVA to work, and I'm just going to run a very basic one way between subjects ANOVA, comparing the different types of species of penguins on their bill lengths. So is there a difference between the different beak lengths on penguins? I didn't know this until I ran this. Now looking at the easy output, right, it gives me Levine's test, which is the second one I think, prints kind of funny in our markdown, but the first one is the ANOVA. So that we see that, yes, we do have a significant difference in the buildings of different penguins, but the nice thing about easy is it will give you generalized ADA squared, and in between subjects test, that's the same thing as ADA squared, so we can make sure that we're actually doing it right, and then it'll give you Levine's test. So let's see. I'm going to calculate ADA F, so ADA directly from F. Now I could calculate ADA fully from the sum of squares or partial ADA squared from the sum of squares, but we'll just do the simple one, which is directly from F. You put in your degrees of freedom model. Now I'm using the terminology from the anti-field book of degrees of freedom model. It's the same thing as degrees of freedom numerator, degrees of freedom error here. It's the same thing as DFD, or degrees of freedom denominator. We put in F, which is this number, and our alpha, which we're going to stick with point of five. And what do we get? Same kind of output ADA, so 70.70. It's a really big effect size. I don't make them this large on purpose, right? But if we compare that, we get the same number as our generalized effect size. And then going back to it, we get a low and a high statistic, model error F, and it calculates P again for us. So I can again print out the estimate and the statistic so that I have the complete package of all the numbers I should report in my APA output. So it's a very quick and easy version of how to use moat, right? Like I said, we have so much documentation. Please love to look at it. Tell us what's wrong with it and give us some feedback. But the documentation should help you if you're not sure where the number is coming from. It's got examples for three or four different types of output. So I'm glad that you're here today. Enjoy moat. Hi guys, my name is Erin Buchanan and I'm here now to show you how to use the online shiny version of moat. You want the R package? That's a different video. So one thing first is that we have this really great website that shows you everything about the package and has a really great documentation. So you can click on tests and look at all the different tests that we have sorted by the type of test that each effect size goes with. The references for how we pulled a lot of this. Big props to Ken Kelly's M-Best package to help us out.  So all this goes with our shiny app, which hopefully will load. All right, so when you're working the shiny app, this is really great like in the classroom or for students who need to calculate on their own and you don't want to teach them coding but you do want to teach them about effect sizes. So what you do is you pick the type of statistical test normally that you're pairing this effect size with. As we organized it around that because it's generally what students are learning, right, is the type of test. So let's do an easy one and do an independent t-test. I'm going to calculate that from means. Then over here you enter all the information that you might find. What's really nice and thank goodness to some graduate students of mine at the time is that for each test we have examples. So where's our independent t? Between subjects with, here we go, okay for your pulled standard deviation, the denominator, that's independent t, right. As we have a description of the formulas here in latex format, so it tells you the formula for the test. It tells you the formula for t and how those two things are different. So you could use this for teaching. Relevant r information gives you an example and the data is available on GitHub. Then for three of the biggest popular programs we have JASP, which Jmovies Output is very similar, with SPSS and SAS all shown here on this data pictures of what that output looks like so that you could show students, you know, this is the t value you'd need. Here's the mean that you'd need, grab it from here, take this from there, okay. And then it also shows you how to calculate this in moat. So how you'd enter information into the package or the shiny app and then what effect size that you might get and how you would interpret that output all the way down through the interpretation. I also have a whole series of videos on YouTube beyond this one that go over these exact things as well. So this is like a summary of the summaries, almost, but let me show you the package in action. So we're just going to make up some numbers here. So let's compare two to four, something nice and easy, right, with a standard deviation of two in each one. So that would be two, four minus two, right, divided by two, so our effect size should be approximately one. Give or take, you know, sample size. So let's see, we've got a hundred and a hundred just to make these numbers nice and round and easy. And then we'll hit calculate. Now one thing that's confused people in the past is there's a number of us supposed to go here and so sometimes people hit calculate and it doesn't do anything. You do actually have to type the number in the box. So we just put in the default of what you should be putting there, right. If you're a student you may remember that alpha is that p less than 0.05 thing. Hit calculate. It'll tell you the definition of that particular effect size. It'll give you the effect size and its confidence interval. So our effect size is one. It will interpret the effect size, so if it doesn't include zero it will spit out your effect size does not include zero. So most people might think that that's not different from zero, something very simple like that. It actually will print the group summary for you, so it'll calculate standard error and the 95% confidence interval for each group and it'll actually print the t-test as well. If you're trying to transition students from SPSS to R you could also show them how it works in R. And so this is the help guide pulled directly from R. And then the help page is a video that shows people how to pull information. And so between the online website and the data embedded directly in the app you should be able to calculate just about everything on these two. And these are the students that helped with this. They're wonderful. They're my favorite heroes because this took a lot of stuff to set up and they did a really great job making sure all of the help pages look as good as they do. So I will not take any credit for that but we'll take credit for putting together a very extensive list of possible effect sizes for you guys to use. And hopefully this will also help with teaching because we put a lot of time and thought into having the information and the interpretations listed on the pages themselves. So let me know if you have any questions but this is how you use Moat the Shiny app and where to find all the information in case you get stuck.


The forest and water resources sustain human life and the environment. It connects people, cultures and economies. They are also essential to achieve the millennium development goals and other internationally agreed development goals such as the integration of the principles of sustainable development into country policies and programs and reverse the loss of environmental resources. It is against this backdrop that the Department of Forestry is embarking on a year-long campaign to push actions associated with the theme for World Forest Day and World Water Day 2022, sustainable production and consumption, two areas of national development that are closely related. Deputy Chief Forestry Officer Rebecca Rock, in explaining the overall objective of the joint observance, says the goal of this year's roadshow was to showcase the importance of forests and water to the livelihoods of St. Lucian's. We're not talking just bush. We look at things like carbon sequestration. We're looking at climate change because forests are the low-hanging fruit when it comes to climate change. The more trees we have, the more carbon we sequester. The more forests we have, the more water we save. So this is why we're going around just reminding people that forests are important. It's not just bush. It's not that we just cut it down. We just want to conserve our forests to make our livelihoods in St. Lucian better. As seen in the increasing cycles of floods, devastating hurricanes and unbearable drought periods, forest and water resources have the power to destroy lives and livelihoods, and climate change is expected to exacerbate these already disastrous events. The recent economic and financial crisis seen worldwide must also be acknowledged, and the consequences of the crisis on integrated forest and water resource management and services must be addressed as soon as possible. National Project Coordinator for the Jeff South East Coast Project, John Calyxt, says these awareness-raising initiatives align with the project's mandate of ensuring the sustainable management of the forest to combat climate change and to contribute to the prosperity and well-being of current and future generations. Essentially, one of the objectives of our project is to restore and maintain ecosystems in the southeast coast. So it should include marine and terrestrial ecosystems, so water and also forests. So for us, it has also been able to provide information and awareness of our marine and terrestrial ecosystems. So it's very significant for us to support the Department of Forestry on the tour today, because it helps us to put out the message of the importance of the forest and of water to our constituents in the southeast coast, but also St. Lucia. In order to address global forest issues and adapt water management strategies to global changes, the Department of Forestry remains committed to developing new policies, adaption strategies, institutional reforms with the active participation of local elected administrations and water users, international commitments, financial mechanisms, technology, and innovation. From the Communications Unit of the Ministry of Agriculture, I am Anicia Antoine reporting.


Good afternoon. I don't know if we can put Henry up on the screen if we can connect him. I'm Graham Allison, a professor at Harvard, where I became a graduate student more than five decades ago. And my professor was Henry Kissinger. And I've been learning from him every day until this day. With a brutal war raging in Ukraine and the risk of war over Taiwan rising in Asia, we're very fortunate today at Davos to have with us by Zoom a person uniquely qualified to give us a historical perspective on war. So Henry, at the ripe young age of 99, rapidly approaching your centennial birthday, which we're looking forward to, yours has been the most amazing life. Both in your own personal experience and in your research and writing and 19 books, the most recent of which was published last year on leadership, a great book, you've drilled down deeper on the challenges of war and peace than any other person I can identify. Born in Germany, five years after World War I, you escaped from Nazi rule and served in the US Army at the end of the war. After the war, became a student and then a professor at Harvard writing your first great book on the Napoleonic Wars and the Congress of Vienna that created a century-long peace that followed. As a statesman, you played a pivotal role in ending the Vietnam War, in constructing détente with the Soviet Union that kept the Cold War cold, in establishing relations with China that helped bring the Cold War to a peaceful end. And in the decades since, you've continued thinking and writing about the challenges of building a peaceful world order. So this afternoon, we're going to start with the question of war in Ukraine. And after Henry said a few words about that, we'll turn to the risks of war in China. But Henry, let me be specific here. Last month, you wrote an article in Spectator recalling European leaders sleepwalking into a conflict none of them would have chosen if they had foreseen the war's end in 1918. You asked in that article whether the world now finds itself at a, quote, turning point in Ukraine as winter imposes a pause on large-scale military operations there. And then you say, quote, the time is approaching to build on the strategic changes that have already been accomplished and to integrate them into a new structure towards achieving peace through negotiation. So let me ask you to be more specific. I appreciate this introduction. I've made me proud of whatever professorial contribution I made to your later career. Last year, I made some observations here about how to conceive the end of the war in Ukraine. It was not fully understood what the intention was. And so let me repeat and expand on some of these principles. The war in Ukraine began with the invasion of a sovereign country. And the principle that this must not be a method of settling international disputes was established by NATO and strongly supported by the United States. And I have strongly supported the efforts to do so. We are now at a point when many of the objectives have already been achieved. It has been demonstrated that a conventional attack from Russia on Europe will find united resistance and that Russia probably does not have the capacity to overcome it by conventional means. So secondly, NATO has been expanded by the adherents of Finland and Sweden. And so the strategic objective has importantly been achieved. But the outcome of the war will involve also where various lands should be drawn in the process of preventing the war from escalating and causing damage beyond what existing levels. And so I proposed last year, and I think again, that a ceasefire along the lines of invasion is the reasonable outcome of the military actions but not necessarily the outcome of a later peace negotiation, which would be under ceasefire conditions. The United States has supported Ukrainian resistance and should continue to support and, if necessary, intensify its military support until the ceasefire line is either reached or accepted in some preliminary discussions. And another purpose of this is to keep the war from becoming a war against Russia itself, to keep Russia an opportunity to rejoin an international system. This may seem very hollow to nations that have been under Russian pressure for much of the Cold War period. But the new conditions that I have described may cause Russia to re-evaluate its historic position, which was an amalgam of an attraction to the culture of Europe and a fear of domination by Europe that to provide possibility to reassess that reliance on military, on reliance on military force, this is all the more important because the destruction of Russia as a state that can pursue its own policies will open up the vast area of its 11 time zones to internal conflict and to outside intervention at the time when there are 15,000 and more nuclear weapons on its territory. So this is why I believe dialogue with Russia while the war continues, an end of fighting when the pre-war line is reached and a continuing process of discussion by Europe, America, and at that point Russia about the later evolution while the conditions of sanctions and other pressures will be maintained until the final settlement is reached. I believe this is the way to prevent the war from escalating by raising issues beyond those that existed at the beginning of the war and making them subject to a continuation of military conflict. I want to express my admiration for the president of Ukraine and for the heroic conduct of the Ukrainian people when I asked them to participate in an effort which should be made by Europe and Ukraine together before this war. I was opposed to membership of Ukraine in NATO because I feared that it would start exactly the process that we are seeing now. Now that this process has reached this level, the idea of a neutral Ukraine under these conditions is no longer meaningful. And at the end of the process that I described, it ought to be guaranteed by NATO in whatever forms NATO can develop. But I believe Ukrainian membership in NATO would be an appropriate outcome. So we now hope that the courage of this period and the heroism of this period will be matched by a vision of a process which uses this time as a step towards a strengthening of Europe. An opening to Russia if it meets the required conditions to participate as a member in these European processes and as a fulfillment of the hopes which have characterized the evolution of Europe since the end of the war and fulfill the principles of America in bringing about a more peaceful world order. OK, thank you. There's about 20 pieces of nuance in that and that certainly does take a step beyond the spectator piece to clarify. So I think, as you said, you were going to say what you think, and I think we've had a chance to hear it. Before I drill down on that one, let me just turn to Asia since the time is short. You've been involved in the whole question of China and its role in the world, including its relation with the US since you and Nixon went to China to open relations with China. Now, a half century ago, when that began, if one of the clear irreconcilable differences among the parties at that time were the views about Taiwan, but in the Shanghai communique and in the framework of strategic ambiguity that you and Chow and Lai and Company wove, irreconcilables didn't turn out to be unmanageables. And somehow, the five decades since then have actually seen better increases in the lives and well-being of people on both sides of the straits than in any equivalent period in their history. So on the other hand, this situation is heating up, where you can see some political impulses in the US even calling for recognition of Taiwan as an independent country. Something that you've said and that I have written as well, I cannot imagine any Chinese leader abiding. So what about the Asian front and also from a historical perspective? When President Nixon began to move together with Chairman Mao towards progress in the American-Chinese relationship, there had been 162 negotiations about Taiwan in Warsaw, which ended very quickly on each occasion, because each side put forward the proposals that the other side would not accept. We began the process because we were convinced that the American people should be given a vision of peace that was not defined by the Vietnam War, but that showed prospects of constructive relationships developing even among societies that had ideologically substantial differences. China felt itself at the same time under pressure from Russia and considered it to its own advantage to open a dialogue with the United States. For five decades, this process operated effectively. The issue of Taiwan was put under arrangements under which the Taiwan could develop economically politically without the affirmation by the United States of a separate China. And the contribution that the United States made to the process was its affirmation that it understood the Chinese view on one China and that it would not challenge it. This process has been under pressure in recent weeks. The presidents of China and the United States have met to arrest the movement towards conflict and begun and created a basis for a dialogue. And I am delighted to see that my friend of two decades, Ziou, has expressed a vision at this meeting which outlines ways by which this process can be implemented. What this process needs, above all, is a deep conviction on both sides that it is not simply a tactical move but a necessity for our period. When the two technologically most advanced countries with capacities in artificial intelligence and nuclear destructiveness are engaged in a confrontation, in a military confrontation, the structure and stability and ultimately the survival of mankind is threatened. We each side should not look at these negotiations as a means of building on its assumed advantages over the other and in preparing for an expected showdown. In the first phase, such a goal is probably not achievable. In the first phase, a number of specific steps need to be taken on the more limited and concrete issues that confront us. And I notice with great pleasure that the Chinese side has lifted its insistence that every issue had to be negotiated simultaneously and that the United States has reciprocated by its own willingness to engage in specific steps like the conversations that will take place here between the WHO and Secretary Yellen and negotiations that are going on between the rentables in the climate issue in time. Each side needs to consider for itself how the threat to human survival of the destructiveness of weapons coupled with making them almost conscious in their application can be dealt with. It seems far from immediate negotiations, but it needs to be conducted first within each side and then between the two sides. If that can be achieved, we can live in a world of prosperity that has been against in recent decades without the threat of a kind of military action that can devastate humanity. The two countries will, of course, not talk about a bilateral domination of the world. The two countries have their allies and have their cultural preferences, but they need to do something that has never yet happened, a way of harmonizing the destiny of mankind in developing its non-destructive capabilities for the sake of peace, progress, and humanity. That vision can be put before us, but only if the leaders of both countries produce the conviction in their societies that it is not necessary and not act on the belief that they can find a way to destroy the others by the others inadvertence. The goals are clear. How to achieve it is a challenge to the domestic politics of each of our countries, but it is necessary and therefore should be pursued. Thank you for giving me this opportunity to speak. We've got about two and a half minutes left, so I saw Luca today. He sends you the warmest regards. I said, you were told me to tell him that you were coming to China soon. He said sooner rather than later. I said maybe April you were told me, but he said they'll welcome you with open arms. So that's his best regards. And he gave an excellent presentation at the Davos session, as you mentioned earlier today. But with one minute and 45 seconds left, if you were thinking about Taiwan, again the way you thought about it 50 years ago, any clues? No, I think it would be best if both sides prevented conduct that the other would interpret as an imminent showdown. That is that China should restrain its military buildup and the United States should avoid acting as if it was heading for a two-China solution under the guise of one China principles and in the interim while they are reflecting about how to implement this if both sides could cool and avoid threatening language vis-a-vis the other. It might create, it would create conditions in which a dialogue can be presumed. Well, thank you very much. So I'm sorry that our time has given up, given out for today, but for 99 years young, your mind is as sharp as ever. And I would say we're looking forward to the centennial and beyond. So let's say thank you very much to him.


Well, thanks a lot, Ryan. 10 in a row. That's nothing to be sneezed at. Best record in baseball. That's nothing to be sneezed at. And also beating a team that many expect you to have to compete against to win the American League East. That's a big thing too. Well, it is, especially here north of the border in their home ballpark. Nice crowd here tonight. You know, you just feel that this is the battle of the American League East this year. These two teams are going to go at it all year long. So every game is that much more important. Jordan Montgomery again. Nice job. He got a two run lead, gave it away, but held it right there and his normal, hey, he got two runs of support. You know, that Jordan's used to that, but a lot of feel good stories all the way around. Michael Glabor-Torres, as you mentioned. Clay Holmes, a nice job there. Jonathan Loisica kind of been struggling, got out of a big jam there in the middle and Chad Green closing in at the end. I mean, there's a lot of things you can sink your teeth into if you're on the Yankee side. And something that you have to like about this Yankee team right now is that they could do it in different ways. So they'd won nine in a row coming in and during the nine game winning streak, they had 20 home runs. Now they had the Glabor home run, which was important today, but they didn't put a load of runs on the board and they still squeaked one out against a team that really is close to the Yankees because they win these one run games. It's a great point. You know, and we didn't even talk about the defensive side of things. A couple of big double play balls, kind of for Lefa playing great at shortstop. A couple of picks, hard hit balls. The Yankees defensively look like a different team this year. There's no two ways about it. And as you said, Michael, to have LeCastro come off the bench late in the game in a tie game and look like, hey, which pitch is he going? There's no doubt that he's going to steal second. It's just a matter of when he's going to go. He does. He puts himself in a position to score and Glabor Tour is a big RBI late in the game. And you're rolling at that point. You got a one run lead. Even though Chapman's not available, you run green out there and still get the job done. And one thing that's going to get overlooked with everything that's gone on in Glabor's heroics, if Stan doesn't get on then against a tough pitcher, he lines the single to center field. That kind of opened up the managerial moves for Aaron Boone to bring in LeCastro and the rest, as they say, set up for Glabor to get that hit. Yeah, it's true. I mean, Stan getting it going too. And you know, underneath all of this was that great play he made in right field. And if you think about moving forward, what's the best lineup the Yankees can throw out there? Well, you know, they're going to shift it around a little bit. There's going to be sort of that built in day off for one guy. But this lineup tonight makes sense. If Glabor Torres is Glabor Torres, then Aaron Judge playing center field. The fact that Stan can play right field opens this all up for the Yankees and for Aaron Boone. If you really think Glabor Torres is your answer at second base and DJ the Mayhew can play third, Donaldson can DH because Stan is in right field. And the play he made just gives you even more confidence that he can spend more time out there in right field. And that opens up everything for the Yankee lineup. And now we've also said that the Yankees have four, maybe five legitimate closures in their bullpen. That's why their bullpen is such a weapon. And you'd have to say that Chad Green might be plan D or E. He might not be what he was three, four years ago, but that's a nice plan D or E. I don't think many teams have that. He was able to close it out tonight. Yeah, one thing you know about Chad Green is he's reliable in terms of throwing strikes. He's not going to be afraid of the moment. He's not going to walk the bases loaded. He's going to be aggressive. He's going to go right after the hitters. And then the silver lining with him was the breaking ball for strikes. He threw three straight curveballs for strikes. How many times have we talked about Chad Green trying to develop a reliable secondary pitch, whether it was a curveball or some sort of change up to a lefty? It looked good tonight. It was a real weapon for him. And finally, one of the knocks against this Yankee streak that they're on. Well, they really haven't played anybody and the Blue Jays have played a tougher schedule. Well, coming into this series, the Blue Jays have played seven series that haven't lost any of them, but they did split a four game set with the Yankees. Now, the Yankees take the first game against the Blue Jays. And I always laugh when people say, they haven't played the toughest teams. They play the teams that are on the schedule, and those are the teams you have to beat. You can't win for losing, right?  Well, you didn't take advantage of the teams that you were supposed to beat last year. Well, Yankee's doing all the right things right now. Things look good. They're getting great pitching. I think that's the strength of the team, obviously, in the early going here as we move into May. The overall depth of the Yankee pitching, as you mentioned, I mean, Chad Green, maybe your fourth option to close. Jonathan Loisica getting it going again. I mean, the Yankees bullpen in the depth of their pitching, even reaching down into maybe guys we haven't seen in AAA as of yet. I say one through 20, the top 20 pitchers in the Yankees organization, as good as anybody in Major League Baseball right now. Well, the Yankees will go for 11 a row tomorrow night, and we'll be here for that, Ryan.


A large percentage of a developer's day is spent on updating their branches and rebasing. They are essentially racing their teammates to get their merge requests merged. You added a change and now your merge request is ready for merge. Your pipeline is green, but when you merge it with the target branch, the target branch may have already changed. Merging now could introduce breaking changes to the target branch. GitLab has a powerful feature, merge trains, that always keeps the target branch green. With merge trains enabled, a merge request can be added to the train, which takes care of it until merged. A merge train can be imagined as a queue of MRs that is automatically managed for you. The train ensures that only green merge requests will be merged to the target branch. If a red merge request is detected in the train, it is removed from the train, and pipelines run again on all remaining merge requests to ensure they are green. Let's see a merge train example. Three merge requests, A, B, and C, are added to a merge train in order, which creates three merged results pipelines that run in parallel. The first pipeline runs on the changes from A combined with the target branch. The second pipeline runs on the changes from A and B combined with the target branch. The third pipeline runs on the changes from A, B, and C combined with the target branch. If the pipeline for B fails, it is removed from the train. The pipeline for C restarts with the A and C changes, but without the B changes. If A then completes successfully, it merges into the target branch, and C continues to run. If more merge requests are added to the train, they now include the A changes that are included in the target branch and the C changes that are from the merge request already in the train. To summarize, when the target branch fails, teams are in a panic, and until this is resolved, developers might be on hold for a few hours. Merge trains solves this situation and keeps your main branch always green.


The New Colombo Plan Mobility Grant is funding that is provided through the federal government through universities to students to study in the Indo-Pacific region. A mobility grant is a study exchange where you get accreditation for studying abroad at a host university. People who are eligible for New Colombo Plan Mobility Grants are people who are studying at Australian universities, who are Australian citizens. The New Colombo Plan Mobility Grant has really opened doors for me in terms of professional networks and also links with other students.


presenter, calling him simply a speaker, does his pants at his service. He hardly needs an introduction. In addition to being a Rails Core team member, he's an avid beard grower and meat connoisseur. In addition to 90s fashion hoarder, he's here, I actually got the, I have the slip of paper. He's here with written permission from Gorby Puff. I had to get that, I had to make sure that it was okay. And with that, I'd like to welcome up on stage Aaron Patterson. Thank you, thank you. Thank you, thank you. I'm very excited to be here today. May I be the first person to welcome you to RailsConf? If you notice any typos in my slides, please let me know. Just tweeted at me. I want to start my talk off with a couple of quotes. The first one is, my mom has the Ferrari of sewing machines. This is from Kate Hiddleston. We were talking about her awesomely embroidered jacket last night. You should follow her. And the other quote I want to start with is Dad Gummett by Bill Dance. That's actually why I have this hat, is because I'm a fan of his. I love the animated GIFs working keynote now. Anyway, so my name is Aaron Patterson. If you don't recognize me, this might help. That is what I look like on the internet. I learned from the sketch note talk that I should put my Twitter handle there, so hopefully you can remember it. I have a cat and that's him. This is him from a different angle. So if you like this talk or if you like anything, you should give it a tender love seal of approval. So I'm on the Rails or Ruby core team and I'm also on the Rails core team. I think I'm the only one on both teams. That doesn't mean I know what I'm talking about. It just means I'm really terrible at saying no. So I work for a very tiny startup that's based in Dallas, Texas. AT&T, I actually do work for AT&T.  So I'm an open source developer for AT&T and we're going to talk about stuff that I do. Anyway, my job title is in the past. 2011, my job title is Corey Nanes. 2012, Senior Facebook Integration Engineer Elect. I lost that election, unfortunately. Then I became a senior software architect. So I got a drafting table and all that stuff. It was very cool. This year, I'm a thought leader in training. So I want to get out of development and I heard that thinking is on the rise, possibly. So somebody needs to lead those thoughts. So I figured it's a great market for me. So I noticed there are some people around here with Google Glass. That's pretty exciting. I also have a Google Glass. I did not bring it. This is my Google Glass. I saw there was a talk about, someone was giving a talk about doing 27 million hours of pair programming or something and ask them anything. I thought that was really cool. I also do pair programming, but not for as long. Like here's, I want to show you a couple of action shots of me pair programming. I'm pair programming there. This is a very close up pair programming shot. I can't do it for 27,000 hours. My pair goes bad after a couple of days. So I don't know how he did it. Anyway, the USB interface on this was terrible. It was very hard to figure out. Anyway, I have two cats. This is my not as famous cat. Her name is C-Tac YouTube Facebook Instagram. But we call her choo-choo for short. And then this is Gorbachev Puff Puff Thunder Horse the Third. And you can follow him on Twitter at Gorbipuff. That is his Twitter name for those of you sketch noting. This is me with my cat. I love them. The Christmas card in the works right here. So I, like I said, on the Internet, I am tender love. I write a lot of puns on my Twitter. And I also give people hugs and stuff because I work from home and I get kind of lonely working from home. So I hug the Internet on the weekends. That's why we did that thing, although I'm extremely shy. So I would not make you all do that.  These are my tweets. It's 90% puns. Hugs, cat photos, and sometimes tech stuff.  This is stickers of my cat. And the thing is like, so it has come to my attention that people might know who I am. And this concerns me very greatly because I am very introverted. So I'm really, really shy.  How is it possible that you're doing that? And really shy?   So if I mess up, it's like, look at these. Distraction, wow. Anyway, so people have said to me like, Aaron, you're very famous. I'm afraid to talk to you. And I want you to know that this is why carry around a whole bunch of stickers with me is because I am also afraid to talk to you. I don't know what to say. So if you want to come talk to me, this is like a totally easy thing to do is just say, hey, Aaron, I heard you have stickers. Can I have one? And I will say yes, I do. I love my cat. Here's a sticker of my cat. So please, you know, don't be afraid to approach me. Now let's talk about some Chicago stuff. We're in Chicago. I noticed like, so people have told me you need to connect with your audience. Like it's important to connect with the audience and I didn't, I noticed like nobody really did this so much in their presentations, but I'm going to do it now. I'm just going to say a bunch of Chicago stuff to like connect with all of you. Like the bears, the bulls, Mike Ditka. So now we're all connected on Chicago, right? Okay, perfect. So last year, I want to talk a little bit about what I did on my keynote last year, and then we're going to go into this year. Last year, I introduced my consulting company. Here it is. This is my consulting company, Adequate Industries. I did the same joke last year, but I figured this would be good enough. Like it should work. Figured that would be adequate. Anyway, I also dropped a lot of F-bombs. It was pretty sweet. I also got into a really awkward situation. So before my keynote last year, like I always, before I give a talk, I always do one thing.  And unfortunately, I was very, very nervous and I went into the women's bathroom. But there was nobody in there, so I didn't know. I was like, wow, there's a lot of stalls in here. That's okay. I need to use the stall anyway. All right. Use the stall, come out. And then I'm like, okay, there is a woman janitor. I'm okay with that. I'm a progressive person. It's fine. I don't mind if there's a woman in the bathroom. And then I see that there's another woman washing her hands.  And the janitor's like, get out of here. And I'm like, ah. And of course, the only thing running through my head is like, do I wash my hands? Do I wash my hands? Anyway, last time, so last time I was in Chicago, it was about 10 years ago. This was before I had an iPhone or anything. And this, so this story is, is rated PG-13. So like, I know we're not, we're not in prime time yet. It's only like 430. So hopefully you'll forgive me. Last time I was here, I accidentally went to, well not accidentally, I guess it was accidentally, I ended up at a party at Cynthia Plastercaster's house. Okay, I see none of you know who this is. If you Google her, only click on the Wikipedia link, please. That's the only one you want to click on.  I'm hip, I know artists, people who like to do things with plaster, that's cool. So I didn't like, I didn't want to seem uncool so I didn't ask who this person was. And we went to the party, went to the party, and it turns out that Cynthia Plastercaster is famous for in the 70s and 80s making plaster casts of rock stars penises. And I did not know this in advance. So we go to this, we go to this party and at the time an adult video had just come out with Jimi Hendrix in it, but allegedly Jimi Hendrix and they weren't sure whether or not it was him. So she was called in as an expert witness. And so she's there and they had just come out with a DVD with her being the expert witness and she puts in the DVD and we're like watching and I'm like, what is going on? She's on the DVD, she's like, yes, you see here and here, that's him, that's definitely him. And I lean over to my friend and I'm like, who is this person, why are we here? And so then she explains it to me and I'm like, oh, I see. So it was incredibly awkward and the most interesting part of it to me was that there was a guy there dressed in a hot dog costume which seemed most appropriate for the place where we were. Anyway, so that was my last encounter in Chicago and the moral of the story is if you don't know something, you shouldn't be embarrassed to ask about it because down the line it could be potentially even more embarrassing. Anyway, so Rails is 10 years old and that's really exciting. I was thinking about like, okay, Rails is 10 years old. What did I look like when I was 10 years old? And so I decided to dress like that today and that is why I'm dressed like this. So this is about what I looked like when I was 10 years old, maybe 12 or so, I'm not sure, around in that ballpark. And I know you probably can't see the back of my t-shirt. I'll turn around here, it's probably hard to read but what it says is this, it looks like this.  And I love it, it's like there's a dog surfing by, it's like the literal interpretation of the internet. And you know, in the early 90s, like this is how most people thought the internet worked, is like these things going around the globe with like bubbles and stuff and there's a dog flying by. And I'm just thinking to myself like, yeah, there's some guy sitting there clicking his mouse, like yeah, if you can't surf with the big dogs, you gotta get off the net. Just kills me. Anyway, so I think we've made a lot of progress since then because basically what dogs look like on the internet now is this, like, I mean this is surfing with the big dogs right here. Anyway, so 10 years ago, like Rails, the Rails community started solving incredibly hard computer science problems. So 10 years ago, we were able to solve the problem of naming. Check, it's solved. Say Rails generate new model or whatever. We got the names down, you use plural, super exciting. Last year, last year during DHH's keynote it was very exciting, incredibly exciting. We solved caching, boom, Russian doll caching, thrown in there, don't worry about it at all. Also in the previous year, like another insanely hard computer science problem solved was dependencies. We solved that. In fact, I have a quote about it here. The genius behind NPM is that it solves dependencies, a long time problem in computer science. Boom, solved. Unfortunately, that was with NPM, so all I just have one thing to say is like, get your act together, RubyGems. What is the deal? Why have we not solved dependencies yet? So this got me thinking like, what's left in computer science, right? I mean, we're doing groundbreaking work here on the Rails core team. It's amazing, there's one thing left. P equals MP. And you know what? I'm gonna solve this one for you on stage tonight. I don't even know why this is so hard. You just divide both sides by P. Done, we're done, yeah. I think we're done here, we can all go home now. Anyway, so this is my anti-keynote. DHH opened, he gave the keynote. I am closing, I will give the anti-keynote. Tonight, we are going to talk about coverage, speed, metrics, and hard effing science. So things I've learned at RailsCuff, Yehuda taught me that it is nearly 5 p.m. on a Friday at the end of a very long conference, so your cognitive batteries are probably very low, which means that I am your default. It means that you need to listen to me. Science is good, TDD is great. Baratunde taught me that I am white. I did not realize that until the other day.  So DHH's presentation gave me a really awesome workout for my eye muscles. You can see from this diagram right here, this is the eye roll muscle. I'm not shit, not a lot of exercise back there. Super strong. So I'm like, okay, oh man, we got this person with a birth year on it, how do we test this? Well, obviously we have to pass in today. We modify our API, pass in today, and then we can test it, and I just have to say one thing, stop! This is not how you test it. This is not dependency injection. So let me show you how I would test this the way I would test this is I would use the API that we already have. Your person has a constructor. You can give it a birth year, so pass in the current year, and then test whether or not the current birth year is equal to that, and whether or not, then refute it as well. What's really cool about this, what I think is really, really awesome, is that there's no new API necessary. Wow, amazing. Constructors are pretty cool, I think. I like constructors a lot, but the lesson from this is that you need to make construction easy. If you make construction of your objects easy, then they should be easier to test. So okay, there's some trolling out. I wanna start out with my controversial opinions. These are my only, well no, I'm gonna give you some controversial opinions now, and then some at the end of the talk, so I'm gonna start out with controversial opinions. I am a software engineer. I am not a software writer. I am sorry. I imagine, when I hear a software writer, I imagine somebody sitting in their villa in France on a winery. Oh, look at how that brace lines up with this other brace. It's beautiful. So amazing. Look at how those methods are indented, just one underneath private. Oh, it's so readable. What kills me about this is that beauty is in the eye of the beholder. Like if you, for example, look at this ridiculous outfit I'm wearing. In the 90s, this would have been acceptable. Science is important. I can't believe I had to say this. So you may not have to be a computer scientist to be a web developer, but having some sort of scientific background might be important for things like making money. Like, I mean, sure, any of us can sling out some HTML, but can you make money with that? You need to be able to measure things, like, for example, AB testing. There's math. Money, more math. It just, anyway, yes, science is important to me. So I want to talk about mutable state. I think I said in the title I was going to talk about mutable state, so I'm going to do that. I promised I would. Amatsuda said in his talk, Rails has many bugs. So we're going to look at some bugs. These are my favorite bugs recently. Actually, I found two of the three bugs we're going to look at. And all of these bugs have to do with mutable state in one way or another, and we're going to see how. The first one is inconsistent return values. Typically, I assume that if I call a particular function twice, it will return the same thing. I know this is probably silly in Rails. So I think that those two methods should return the same thing. If you call that once, this literally happens today in your Rails code. If you do these two particular lines of code, the first time it'll return false, and the second time it'll return true. And when I look at this, I feel like I'm Bill Dance with a dog going. Let me just watch that gif. I love the dog. Anyway, there's another problem with this too. It also has a memory leak in it. Look at that. These are action controller parameters. This is the params thing that's in your controller, that hash that you deal with in the controller. There is a memory leak in it if you do this particular code. Like if you write this, if you fetch a value and then delete it and then assign a new one, you'll get a memory leak in it. It'll look like that. So if you run that program, it'll just go infinitely. And the reason is because we're doing a conversion on the stuff that we pull out when you do fetch, and that conversion gets shoved into an array. And unfortunately, this parameter's hash, it allows you to delete things from it. But when you delete stuff from it, this internal array thing is not updated. So it deletes from the hash, but doesn't delete from this other converted array value. And this is something that was missed because the parameter's hash inherits from a hash with a different access, and hash with a different access inherits from hash, and hash implements a whole bunch of methods that maybe you didn't think about. For example, delete. So when you inherit from something like hash, you have to think about all these different ways that people can interface with your code. And it's similar to this.  What do we do about that? So this is one thing that I do not like. It's not very fun, and I mean, you can tell this is not done with TDD, possibly. Oh, I'm just kidding, I'm just kidding. It probably totally was. So another example here is an inconsistent return value. So the first time we call size on this one, on this relation, it'll return a hash. And the second time, if you call 2a on it, the second time it'll return a one. So I would expect that both of these return a hash or return a one, but they don't. And the cause is because we have a mutated state inside of the relation object, which is when we load the records from the database, we shove that into an instance variable so that if you try to reload them again, we don't actually go hit the database. So if it's loaded, then we'll return the length of the records that are in there. And if it's not loaded, then we'll actually do it, we'll do a count on that. I'm not totally sure how to fix that. These first two problems I'm not sure how to fix. I feel like this one, another build dance. I should probably tell you whenever we find issues like this or mistakes, we take one of these gifts and put them into campfire, which is why I own this hat. I feel like I am screwing up all the time because it's probably my fault.  This one is courtesy of that Eileen codes.  That's my name. You can see her speak at Ruby Nation and I highly encourage you to do so. Actually, I saw her present this bug at Mountain West Ruby Conference. She was giving a talk on active record stuff, like in turtles and she's going through all this stuff and she's like, if you call it in a certain way, then it's incredibly inefficient. It does this weird stuff and it's incredibly inefficient and of course, during Q and A, I was like, why don't they fix that?  Anyway, so let's look at the bug. So we have an object here. This is just using fixtures. We have an author, the author is David.  If we think about what the SQL is for that, we would expect that it's like, okay, delete all from posts where the ID is whatever and if you execute this, yes, that's what happens. Delete all from posts where author ID equals one. Okay, now let's say you're messing around with this thing in IRB. You say, okay, David up posts and you inspect the return value of it. So this test is simulating that. We're calling inspect on that because that's what IRB does to any return value. It calls inspect and then shows you the text below it. So what do you think the SQL would be for this? If you thought it was the previous one, you are wrong. Otherwise I wouldn't be showing this to you. This is what the SQL looks like. A giant in statement. So yes, this is definitely inefficient compared to the other one. Anyway, the cause of this is exactly the same as the cause of the previous one. We had state saved. We said, okay, if this is loaded, then we do a different thing versus if it's not loaded. So we're like, okay, if it's loaded, then we're gonna do a delete with an in. Otherwise we're just gonna delete all the records when actually we just wanted to do a delete without the in. So this is my next bill dance gift. Oh, I love this one. So the lessons that I hope you all to take from this are avoid subclassing built-in classes. They probably implement stuff that you're not expecting. They're probably implementing an API that you may not need or may not want. You should be conservative about the API that you implement. It's much easier to add a method than it is to take one away. If you take one away and you need to deprecate it, there's a lot more work. It's a lot easier to introduce something new. The other thing is that you should be extremely careful with mutations. I'm not saying like, don't mutate stuff. I'm just saying be very careful about it. If you keep a small API, then it's much easier to be careful with your mutations. So you might be asking yourself, Aaron, you find all these bugs in the rails and there's all these bugs. Why would you want to work on this piece of code? And I'll tell you, the reason I like working on rails, the reason I love being on the Rails core team is actually because I love Ruby. Is that weird? I just Googled for heart images. I don't know if that's like. Is that? Anyway, the reason I love working on rails is because Rails is what gave me a job as a Ruby programmer. So I want Rails to give everybody jobs. I want everybody to be able to work in Ruby on a day to day basis. So it's really important for me to make Rails a better place so that companies will continue to adopt it and that people will be able to have jobs and get paid using Ruby. So the next portion of the presentation I want to talk about is adequate record. The thing that I've been working on is from adequate industries. So what is adequate record? Adequate record is a fork of active record with some performance improvements put on top of it. And I want to talk about those performance improvements. But first off, I gathered a whole bunch of quotes about adequate record, like what people are saying about it, like using it on their applications and how they find it. So I want to share those quotes with you just so you know the quality of the software. It's like active record, but more adequate. I'm quoting myself. That's how you know it's legit. It's all right, but I've seen better. Thanks Jeremy, I appreciate that, that was really good. Yehuda says, oh it seems to work. Josh Susser says, sometimes good enough is good enough. I actually, I tried to get a quote from Matt and he just said, what is that? So why did I name it? Like why did I actually name this library adequate? I actually haven't had a motivation behind naming it adequate record. And the reason is humility. Like I'm actually super tired of libraries that are named like active something and terrible this and all that. Like why do we have to have things that are named like super awesome whatever software? Like I just want to know what your software does. I don't care how awesome it is. I just want something that works. So that's why I named it adequate record. It's also another thing, like I think it's an anti-marketing term. I feel like a lot of software is trying to be sold to me and it really bugs me. I don't like it when people try to sell stuff to me. It's kind of like, I don't know. The new version of people coming to your door and trying to sell you stuff. I want people to buy this software based on its merits not based on like how cool the name is or whatever. So why did I fork? The reason I forked is that I don't actually want new features.  I don't actually want new features in Rails yet. I think that Rails accomplishes like 90% of the stuff that we need to have make great web apps. And I'm afraid that if we try to keep going that extra 10% we're just gonna be adding cruft that nobody wants to use or it's just even worse increasing the complexity of the code that's there. It actually makes me incredibly paranoid when we add new features to Rails because a lot of people think like, hey there's a new feature there. This is really awesome. I can do these super magical things and I look at it and I'm like, oh man, how many years of refactoring is that gonna cost me? So let's talk about adequate history so I can give you a little bit of background about why I have opinions like that. I've actually been working on this project for about three years. So I've been refactoring the Rails code base with this particular optimization in mind and it's taken me three years of refactoring this legacy code just to get to the point where I could actually add this stuff. If you look at my talks for the past three years I've been talking about this stuff in theory like talking about doing prepared statement caching, talking about doing yak shaving. All these things are actually just leading up to this. So I'm actually very glad to have all of you here today because this is probably to me the most important talk that I've given because I've spent so much time on this. I've had this idea in my head for three years now and I really wanna talk about it, adequate. So in order to talk about this we need to talk about how ActiveRecord works. So I'm gonna show like a brief overview of how ActiveRecord works and then we'll talk about the performance improvements of adequate record. This is what it looks like when you say post.find10 we go through a process that looks similar to this. When you say post.find we create new ActiveRecord relation objects. Those ActiveRecord relation objects eventually get translated into arrow SQL nodes into a SQL AST. That AST is then transformed completely into a string, literally a string. That string is sent to the database.  Those records are turned into ActiveRecord base objects and then sent back to you wherever you called that. So this is basically the high-level overview of what happens with ActiveRecord. So the change, the first change that we had to go through was bind parameter introduction and I'm gonna show you why we need to do that. If you looked at the logs in Rails many years ago you'd see something that looks like this. If you did post.find1 or find3 you'd see these SQL statements in your logs and you may notice about them the only thing that changes is that number. The rest of the string is constant. It does not change. So what we did now, if you look in later versions of Rails you'll start to see something in your logs that looks like this. Select star from posts where id equals question mark and then some square brackets that are saying id comma one. And what the idea here is that we're trying to separate static and dynamic content. Those id's are the only dynamic thing in that string. We wanna be able to generate something that's always the same. The adequate theory is that in this diagram if everything that generates that string always generates the same thing we should be able to cache it. If you say post.find and it goes through all this stuff and it generates a SQL statement that's always the same we should be able to cache that computation. It means that we can say okay let's just cache that. Then the next time you call post.find we don't have to generate the SQL statement it's already there because we don't have any dynamic values embedded in it. So this was done quite a while ago. The next thing that we needed to do is decouple our code. Now separating the static and dynamic content sounds like easy enough but it actually is not because it is embedded deep within the Rails code. I mean I'm gonna show you where it is. This is the worst part. Right here, you don't need to read that, don't worry. Those three arrows are pointing at dynamic values that are being inserted into your code. This is deep within the call stack. This is actually inside the associations code. And that is one method. It is one method. It is one method to rule them all in legacy code.find. So this method defines how all the joins are done inside a relation. Basically the problem with this method is if you have, specifically it was STI. So if you have single table inheritance and you need to insert that value for the model name in there, that's what that was handling. So in order to simplify that, so that code was, I think I said this, was only to do with associations, like has many, has many through, et cetera, et cetera. And I wanted to simplify that code so in Rails 401 I deleted has and belongs to many. It is gone. Thank you, I'm extremely proud about this. And for those of you that haven't upgraded to 4.1 yet, it still works, okay? Has and belongs to many, the keyword is still there. You will be able to upgrade your app and it'll actually work. And the way that I got it to work is has and belongs to many is actually a subset of has many through, if you think about it. So if you think about has and belongs to many, it's got three tables. Has many through also has three tables, but has many through forces you to define a middle model. So the refactoring that I did is just on has and belongs to many, it translates that call into a has many through with an anonymous middle model. So it should be completely transparent to you. And because I was able to do that, I could remove a bunch of code from that very complex method. And I wanna show you that, I don't expect you to read this diff. I'm gonna show you a diff. I'm just showing it to you because I'm very, very proud of it. It's one of my favorite commits in the Rails code base. Like all you need to see is that there are red parts and no green parts.  And the reason I love these commits so much is because they're removing stuff, not replacing it. And they're specifically removing conditionals. There are if statements in there that are just getting pulled out and thrown away. It makes me so happy because when you look at this code, you don't have to think about those conditionals. Those conditionals are what tire you out. You look at that and you're like, oh, if it's this thing, then it does this. And you think, well, how did it get that way? And you have to go figure out how did it get that way? So I felt very happy about this. I was eating code out of the Rails code base. It made me super happy. So the next part, I'm actually making it on time, I'm happy, okay. The next part, part three was to introduce a cache. This is finally where we get to see our speed improvements. I'm gonna show you what the caching API looks like, but this is totally internal, it's like, don't use this, the API is unstable, but I'm just gonna show you what it looks like and what, I'm gonna show you what it looks like so that you know what the cache is or what we're caching. This is the cache code example. So we can say, okay, person.wear, name, parameters.bind, and then limit one. And what that does is it caches the relation that you created in there. And we can execute that cache statement multiple times with dynamic values. So wherever that params.bind is, that's a dynamic value. So there's our normal active record relation object and that is where we execute it with different values. Now the thing about this is the reason I haven't exposed this to anybody or one reason I haven't exposed this to anybody is because the return value of that statement inside the block must be an active record relation object. And probably I'm figuring most people outside of the Rails core team don't know which methods return active record relation objects. So I know this, but probably not many other people do. So I don't think it's a very good interface for public consumption. So I wanna show the cache object internals. This is what the actual statement cache looks like. We have, from that previous example, we have the bind values. These are the bind values. This keeps the offset. It indicates the offset into the SQL statement where that dynamic value is and it also contains the information for how to cast that dynamic value. So for example, when you get an ID that comes in from the request, that ID is a string and we need to be able to cast that to an integer. This contains that information. And then down below is where the actual SQL statement is cached and you can see it's just a string. So the next step after defining these cache, this cache was to update the internals and cache any relation objects. And this is very interesting because we went through and looked at all the places in ActiveRecord where relation objects are actually used. So they're used, these are the examples of things that are used in, I know it's a cardinal sin dots with stuff to read, but I don't care. I've been working on this forever, so screw you guys. So all these things use ActiveRecord relations internally. Basically everything that you do with ActiveRecord uses relations internally. All of these are cacheable. So we can add cache to all these things and I'm gonna show you an example of the cache that we added internally. This is an example implementation. So this is the implementation for find with an ID. You can see in there we have a key and we say, okay, create that relation. So in your Rails code, you may have typed post.wear primary key arrow, that thing, we're basically just doing that internally. So it's really not much different than what you would do inside your app code. So that is our static values for the SQL statement and then here are our dynamic values. That's the ID that you actually passed into find, so you just always call with that ID. So I wanna share a few, after looking at that, it's really exciting, I wanna share a few fun facts. These are the different ways that you can call post.find. I don't know if you knew this. You can call with an array. You can call with an array of an arrays. You can call with a hash. You can call with an ActiveRecord ID. You can call it with a block. You can call it with a scope and you can call it with a block and a scope with any of those combinations above it. So only that one is cacheable. The rest of these are like, I have no idea why we even support that. I don't even know what they mean. So when I was trying to figure out what we could cache and what we couldn't cache, I felt like this. So if you go look at the method, if you go look at the method, I'm like, okay, this is all the stuff that we can't cache. I don't know this, this, any of these. So I'm gonna show you some performance statistics for this and if we could remove all of that API, that would actually be super nice. I would like that because we could have ActiveRecord even faster. So let's talk about measuring performance because we wanna see the performance of these things. I'm gonna talk about some benchmarking tools, the way that I benchmark this stuff and the way that you should be benchmarking things. The first tool I wanna talk about is benchmark IPS. This is a library that actually Evan wrote and I'm gonna compare this to the normal benchmark library that comes shipped with Ruby. This is the normal benchmark library so you say like, okay, benchmark something and then you need to loop over something and see how long it takes. That'll report to you how long it takes to call that thing. The problem with this benchmark is we loop n times but how big should n be?  Good job, dude. So you have to sit there and think like, okay, I gotta increase the n, maybe decrease the n and maybe you send the benchmark off to somebody who has a faster machine than you or a slower machine than you, then they have to change the n. What benchmark IPS does, it actually measures the iterations per second. The number of times it can call that method per second. So you write a benchmark that looks like this and it will run that block as many times as it can in five seconds. So it'll just defaults to five seconds. And the output looks like this. It says, okay, we can call it that many times in five seconds. And the other thing I really, really like about it is it gives you a standard deviation report, that plus or minus 3% that's shown there. Problem with the previous benchmarking tools, it doesn't tell you standard deviation. So let's say you write some code, let's say you do some sort of performance improvement.  You're like, great, it's slightly faster. But you didn't know what the standard deviation was. If you don't know what the standard deviation was, it could just be noise. Could be other programs impacting your benchmark. You don't really know that information. It's better if you have the standard deviation so you know, ah, I'm one standard deviation outside or I'm two standard deviations outside. So yes, this is definitely a performance improvement. Getting standard deviation with your benchmark is important. The next tool that I use is GC.stat. I'm not sure what version of Ruby this is in, I think 2.1. GC, this is in order to count object allocations when we're doing queries. So this call will do a total object allocation count. So this actually counts the number of objects that have been allocated in your system ever. Not like now or not inside a loop, but ever. Every time you allocate an object, this value increases. So what we do is I say, okay, I'm gonna call, I'm gonna warm up this benchmark, I'm gonna call person.find, then I'm gonna count the total number of objects that were allocated in the system, then I'm gonna actually execute my benchmark and say, okay, find this person so many times, count the objects again, subtract and divide, and then we know the number of objects that have been allocated per call. Science. I should have put a slide of Jesse Pinkman in here. Anyway, so let's actually look at some numbers. Let's look at the performance of adequate record. So we're gonna look at post.find and post.find by name. So I wanted to benchmark these because they're essentially the same thing. One is just finding by ID, the other one's finding by name so they should be approximately the same. And this is a graph of their performance essentially over time. The x-axis along the bottom is the branch, so on the left side is two, three stable, to three, oh, stable, proceeding to the right, the very right is adequate record. The bar along the y-axis is the calls per second to post.find, so the higher that is, the better. You can actually see there around in three, one stable, it was tanking like super hard. I mean, look at that. What's also interesting here is that yellow line represents mySQL and I should say these, along the bottom there, I say SQLite and mySQL2 and mySQL and Postgres, that actually represents the particular adapter that we were using. So not exactly mapping to the database or testing mySQL twice. And I think this graph is interesting because you can see in two, three stable, there was actually a bias towards mySQL. MySQL is significantly faster in two, three stable than Postgres was, but you'll see that those actually even out along here. Now this is the same benchmark but with post.find by name and you can see basically the look of the graph is about the same as the previous one. We started out faster in two, three. It slowed down, then over on adequate record we're going much faster. And I just wanted to call out this one here. This is mySQL, this is that same graph but I specifically pulled out mySQL to show you exactly the performance, the performance changes of mySQL over time. So you can see it just tanked super hard at three, one and then slowly came back up. This is the percent faster the adequate record is than four, one stable. So let's see, what is that? Some of these are over 100% faster so it's two times faster. This is the percent faster it is in three, two, three stable. We can see mySQL, it is faster on adequate record but not by much. So we are faster. This is a graph of the object allocation so this is the number of objects that are allocated per call. And you can see there around three, one stable and three, two we're actually increasing the number of objects that we allocate per call to this. So it doesn't necessarily directly impact the calls per second. It does have an impact on it. GC pressure does cause issues but they're not exactly aligned together. Same issues with find by name. And you can see there again on two, three stable a strong bias towards mySQL. So, adequate record allocates 70% fewer objects than four, one stable does per call. It allocates 55% fewer objects per call than two, three stable. Now I wanna look at belongs to, like I wanna look at the, I'm gonna look at each of the relations. So belongs to graph looks very similar to those previous ones except that SQLite 3 is insanely faster. So again, along the bottom is time, along the y-axis is calls per second so higher is better. Percent faster than two, three stable and four, one stable. The MySQL 2 bar doesn't have a two, three stable one because MySQL 2 that adapter didn't exist for two, three stable so I didn't test it. But we are all adequate record is faster in all cases. Has many through. So I wanna show has many as well as has many through. This is the performance graph for that as well you see exactly the same thing. Sorry about fast two, three stable went down and now we're faster and adequate record. Also has many through call speed over time. So again, we're also faster than two, three stable in every case, much faster than four, one stable in every case. And the last thing I wanna look at is has many through growth. So caching these SQL statements should give us a, should give us constant time performance with regard to generating the actual SQL statement string. And that's what I wanna demonstrate here is show you that constant time performance compared to actually any of the other branches. So what I'm talking about with has many through growth is let's say we have a model that looks like this. We say has many through one thing. What I wanna study here in this case is what if we add another has many through. So what if there's two of them, we go through two. Then what happens if we go through three? What happens if we go through four? Et cetera, et cetera, et cetera. So we keep increasing the number of tables that we're joining against on has many through. And this is what the graph looks like. So you can see on master, well, four one stable, actually any of the branches will look similar to this. Along the bottom is the number of tables that we're actually joining against. So that's the number of has many throughs that we're joining against. So at the very right hand side, we're joining against 16 tables. And you can see on master, we actually have linear growth. And on adequate record, we have constant time growth. And it does grow just a little bit there. And the reason it grows just a little bit is because we're actually sending those queries to the database. So database time is impacting this, but the algorithm is constant time. So I am extremely, this is my favorite graph. Oh yeah, constant time. So this is one of the things that I'm talking about with why I think studying computer science is important. Okay. If you study this stuff, you can say, you can look at these, this performance, you can increase your code and you can talk about it. You can quantify it. DHH gave the example of like, oh, I take a lot of pictures and now I've taken a lot of pictures. So I'm just good at pictures, which is very nice, except that there is a, I'm happy that I take pictures, that's cool. I like to make, I like to cure meats. I mean, we all have things. But even with, even with studying picture taking, people are like, okay, we have the rule of thirds. We have the golden rule. There are these things that we do that eat, that we can all talk about. We have a common language and we also all discovered that hey, if we do these particular things, our photographs turn out better, generally speaking. We have these things we can talk about and I think that's exactly what studying science brings to the table. We can talk about this. I can say to you, here's exactly why the performance is much better. Generally, constant time is better than linear growth. Anyway, TLDR 100% faster. 9,001% better. It's over 9,000. So what I wanna talk about now is I wanna talk about the adequate pricing model. How much are you willing to pay for adequate record? $200, $300? Well, today I'm offering a very special price. Today I'm offering it for $299 plus in-app purchases. I'm just kidding. Let's talk about some of the challenges, like some of the issues with this thing because we're not like, it's not all unicorns and fairies and all that stuff. Like there are definitely trade-offs for this code and I wanna talk about that. We're trading memory for speed, obviously. Like we can't just get this speed from nowhere. We have to cash this stuff. So we need to understand what the cash size is and I'm gonna give you a little formula for the cash size. I'm sorry, it's math. So we need to count. The cash size is equal to the number of relations that you have, all those has many's, and also the number of find buys that you have in your system total. But it's bound by that and it's multiplied by the size of that cash object. So I can't tell you exactly what the size of the cash objects are because they are variable depending on the size of the SQL queries that you have in there, but they're not very big. So we are definitely paying for memory. So this will actually increase the amount of memory that your system is consuming. So we need to study this. We need to study this because maybe we should introduce an LRU cash to this and expire things as they go out. But since this particular cash is bound, I don't think it's gonna be a problem. The other issue is raw relations. So you might be saying to me, Aaron, I'm really excited for you to increase the speed of all this stuff, but I don't use find by name. I use this. Person that wear a name, that thing. I use that, I don't use find by name. Why don't you just make that faster? And I say to you, why don't you make it faster? Jerk. And the question is, so the question is can we cash this? Like can we cash that thing? Can we make that thing faster? And we can, it's true. We can do it, it's possible. I have an experimental branch to do this. This isn't in adequate record right now where we take those values and then generate a key from the values that you pass to each of those relation objects and then cash the SQL query that's generated from that. And we actually see a 30% speed improvement. This is person.wear, name to a. So blue is master and green is the experimental branch with the caching built in. So it's about 30% faster. So that's good. The problem though is if you take a look at the implementation, like this is approximately the implementation, that blue part is calculating the key for the cache and then the red part is actually executing the query. Now the problem with this code is that over 11 different variables impact the cache key. So I have to actually inspect 11 different variables to say like, are we sure that we've seen this query before? Are we sure we've seen this query before on 11 different variables? In fact, that implementation that I showed you only handles two forms of person.wear. I only cashed like person.wear and person.limit, those two. Because I wanted to show you one more experiment. One more experiment is doing a finder comparison. So let's say we have person.wear, name, errand like what you might write in your controller and then person.findbyname, errand. These are both on the experimental branch of adequate records. So the person.wear does have the speed improvements that I just showed you. And if we benchmark these two, this is what the results look like. Wear compared to findbyname. It's not even a contest. Findbyname is three times faster in this case and that's even with performance improvements. So the wear case and the reason is because every time we call that person.wear, we're actually allocating a new active record relation object and we can't get around that. We're always gonna be allocating those objects. So my actual question is like, should we cache these relations? Should we do this? I'm not sure. I'm really not sure if we should do this. It introduces some very complex code and if you're doing a bunch of like dot wears and all those things, I'm not sure exactly what you'll be caching. In adequate record today, the cache is bound but if you're doing a bunch of crazy stuff like all that wears and stuff, maybe it will be unbound and you'll see unbounded memory growth and I would not like that. B2W unmounded memory growth is bad. Science. So I want a new API. I want something that looks like this. So like cached query, find all by name, do name, and you pass in a name. So you can define a method that does this and we pass in the dynamic values to that. So we build up a cached relation in here and then we can execute that cached relation multiple times and the reason I want that is because the cache key is easy. The cache key is just that thing you pass to me and we're bound in size. The relation API is maintained as well. That's another advantage of this thing and I know you might be thinking, Aaron, this looks like scope. We can't use scope because people in their applications today expect that the scope block will be executed multiple times. I expect that there are many of you in the audience who have a scope that are like today's posts, right? Where it generates a date, it says give me all the posts that are after that happened today and you'd expect that that date is calculated every time that block is executed so we can't just go off of the scope block. All right. So I've got one other more thing. I think Steve Jobs said that, right? So let's merge Attica record. Should we do that? Yes? Okay. So I know this is a totally cardinal sin of presentations but I'm gonna do it live. Is that okay? Would you forgive me? All right. All right, so let's do this. All right. Hold on, I'm not very good at typing, sorry. Okay. Okay. Okay, this will work, this will work. Okay. So we're getting pulling now. It's downloading from the internet. The internet might be a little bit slow. Hopefully it'll work. Please work to do this live. Oh, okay. Okay, I think it's there. Ah, oh. How do you merge? I don't know what I'm doing here. I mean, don't you think that Git has really good documentation? Isn't that true? Like we can read through all the help pages there? That looks, ah, ah, I didn't know about that one. Okay. Ah, oh, back to the merge, back to the merge. Okay, we're merging it in, we merged it in. Ah, all right, let's commit to merge. Commit it, commit. Okay, doing good, good job, Aaron. Oh, that was, that was the wrong way. Okay. Now let's merge it in, now let's merge it in. Okay. Merged, ah, nice. Okay, that's master, right? Are we doing it right? Is it coming up? Ah, oh. Okay. Add a good record, it's been merged. Three years of horrible stuff done. Ah, okay, so one, this is my last very, very strong opinion. My last strong opinion of the evening. I think that Rails 4.2 will be the fastest Rails ever. This is what I am working for. I also think that this is just the beginning. This is just the beginning of the performance improvements that we can do to Rails. So, thank you.