Okay, so in today's talk this is sort of part two of a series that I started yesterday. So yesterday I talked a little bit about getting started and your first couple of years and transitioning and getting towards effective agile. And this is sort of picking up on where teams often get to consistently at about two years in to a tech-first agile transition. So this is in the stages of, or in the agile fluency model. This is when you've got good fluency at level two. So we're going to talk about what that looks like. And I'm going to talk about the area that teams are exploring these days. So all the way up through level two, you can pretty much, teams get the same result. You do a fairly similar set of practices, you get a fairly consistent result. So I'm going to talk about what that result is. Level two is where teams are exploring today. And there are some parts of it that teams are getting consistent result. And there are some parts of it that are wide open field and people are still exploring.  So first half is discipline, second half is make awesome. So first thing I want to talk about is that most people have never seen two-star success. So I'm going to be telling everything in terms of stories. I want to talk about my first agile transition. This is way back in the day when the extreme programming white book had been written, but no other XB books had yet been written fairly early on. So like most teams that were making transitions at that point, we did it because we were hosed. The company was going to die. So our board of directors had told us literally that we needed two signed contracts at the end of the E3 game expo in May, or they were going to shut the company down. In order to do that, we needed to put together a first version of the product to be released in May. We started the plan and development for that in September. By January, I looked around at all the dev team and said, who thinks there is even a 1% chance of success here and no one raised their hand? Company is going to die because the product is going to launch and the board has told us it's going to shut it down. So we decided, the second question was, so who's willing to try something extreme? And we pulled out the extreme programming book and started our transition. And fortunately on the team, we had a guy who had a physics background, a laboratory physics background. And so he said, well, we don't have time to mess around. We don't have time to do it wrong. So we need to have short iterations, we need to run a lot of experiments, we need to gather data, and we need to intelligently change direction. And we also don't understand this space. So we can't go off and invent our own. What we need to do is assume that the book is right. And we're going to assume for the first while, until we really have evidence that the book isn't working in our context, that any mistake we have is because we aren't understanding it correctly and aren't applying it correctly. And so all of our experiments, we then did one week iterations, we'd experiment and we'd look at our results, find a problem, and then design another experiment and the data that we were going to use to measure it and iterate. And every one of those was trying to find in what way we don't yet understand XP. And we did that for three or four months and got a pretty good process. And between middle of January and May, we not only completed the whole project that had been scheduled for twice that long, we completed it a month early and then went to the customer, to our biz dev guy who was going to be doing the contracts and asked him to go out and find the killer features for every person he was going to demo to. And we implemented one killer feature for each of the 50 demos he was going to do. There was custom targeted for that conversation and the company did not die. So that is two star agile success. That ability to just deliver, to execute successfully. So first indicator that I see of a team that is a two star success, zero bugs. So numbers seem to be, the number of bugs written is right around one bug per fortnight per team. Most of those bugs are found within an hour by the devs who wrote the bug. But a bug in the way that I'm calculating here is anything that surprises somebody in a non positive way, no matter who that person is. It exists in code that has been checked in to main. So that's a very open-ended definition of bug. Doesn't matter whether it's found in testing. Doesn't matter whether it's found by development or by the live users. Just it's a bug if it's a negative. It also doesn't matter what severity it is, it's a bug if it's a negative. Teams that are doing this are writing one of those every two-ish, two to three weeks for the whole team. So Microsoft online store has a good example of this. They have a small team there that the way they calculate their bug metric is days since last industrial accident. They consider a bug to be, a bug hurts people. It hurts the users or it hurts the dev team or it hurts whatever. So they identify that as an injury accident. And they have in the corner on their board the number of days and the number of stories that they've shipped since the last time they had an industrial accident. When you're at zero bugs, maintenance becomes boring. So, typical teams, your database, bug database size. Because you're writing so few bugs, you can fix not only all the bugs you write, but any of the bugs that you had from before. And so if you look daily at the size of the database, the maximum size that it got to, the median will be zero and the max will be one, which means a lot of stage two proficient agile teams don't have an electronic bug database because they don't need to prioritize, they don't need to hold them for very long. What they have is a corner of the whiteboard that says the current bug is and is usually blank. So, Smilebox does exactly that. They typically are running at zero bugs. Once in a while, they will have a bug that they choose to not do anything with for a little while, but that's pretty rare. Usually it's right around the holidays when they have something else that they need to get done. But even then, they'll get two bugs and then deal with it. So, Smilebox, when they get a bug, their response is when they see something unexpected, then their response is this is one of two things. Either it's unexpected and it pleases people, pleases users, in which case it's a feature. It's an unanticipated feature, but it is a feature. And it's a feature without tests, so we need to write tests around it. So it's got a card to finish the feature by writing all the tests. And if it isn't, the other option is it's a surprise and it's negative. In which case, it's a bug and it needs to be fixed. And then tests put in place and root cause done to ensure that nothing like this ever happens again. This entire category won't arise again. So either way, it is a card and it preempts everything else. That's how they keep it zero. These teams are insanely predictable. The amount of variance between tasks is tiny. There isn't technical debt anywhere in the system. So the amount of time it takes to do something is based on the amount of time it takes to do something. Not random expense of working in different parts of the system that are paying to work with. And they have enough data over a long enough period of time that they really do know their velocity. They can make medium and long range projections. When I was at Blue Tech, we stopped calculating costs for anything because there just wasn't any point. We could just, when we made an estimate, it was gonna come true. And in fact, the stories were tended to be about the same size. This is also pretty common. The smallest to biggest, the ratio was about 2x. So it really wasn't worth estimating. And you could just count the number of stories and see when things were going to happen. The result was that the sales people and the customer support people had complete control over what was going to happen. They'd pick the order of things. They'd pick when things were going to occur. And they'd know what the result is. They never had any need to push the team because they didn't feel like they could squeeze the team and get a 15% boost in productivity.  And it was going to be the maximum that was possible, and every single time. Which allowed us to prioritize based on value alone. Corey Haines is also doing this, there's current company whose name I have forgotten, otherwise it would have the company name up here. So when you're working in this way, cost becomes not an issue. In fact, what I find is that cost of work tends to be distributed in a Pareto distribution, it tends to be vaguely linear. The difference between the most expensive feature and the least expensive feature ends up being about 2x, right? There's not that much difference. Whereas value is distributed far more, it's actually the high value features tend to be distributed exponentially in terms of their value. Which means that if I'm doing trying to optimize for ROI, well, I've got one thing that's linear distribution, one that's an exponential distribution, I can ignore the linear. I optimize for ROI by optimizing for R, just for the return. And that, if everything is exponentially distributed, is really easy to tell. The ones that aren't exponentially distributed, the crowd-pleasing features are exponential. The ones that are competitive catch-up are linear. And the ones that are hygiene factors are all flat. They don't really have a return. So it's pretty easy to identify which ones are the exponential features that are so much better than everything else. And you just do those first. And when you run out of those ideas, then all the rest are roughly the same. And so you can pick them at random or on the basis of preference until the first time you can find something that is clearly and obviously better. And this is what their company does and what a number of others that I've been at have done. Every work item can be done by anyone. You see a lot of pairing at these companies, pairing or mobbing or whatever. And the reason is not because of the impact that it has on productivity. Not because of the impact that it has on bugs and the like.  It's the impact that it has on learning. If you go look at mental innovations, they've got at any given time four or so different projects in flight. They're a software outsourcing consulting company. The four or five projects, they have a team allocated each one. And every week, they rotate people through those teams. In every single one of those projects, it rotates like a third of the people through, so you're on a project for like three weeks and then you move around. They'll bring in new projects from new companies and they're just totally unrelated. In every single one of those, every single task can be done by any arbitrary pair. They don't need to allocate it to anybody because everyone has the skills to do any of the tasks for any of the projects that mental innovation takes on. Reason is because they're so good at spreading knowledge that the instant one person on the team knows something, within a few hours, everyone on the team knows that thing. Productivity doubles every two years. So this one, there's two facets to it. One, the industry as a whole doubles productivity every two years. So that which cost me $100,000 to develop today will cost me $50,000 to develop two years from now, just on average. Some teams are able to keep up with that rate, many teams are not. So often the way that most of the industry is advancing at that rate is teams come into existence at the high end of the bell curve and then increase with a doubling time of four years, which means they are slowly going to the bottom of the bell curve until they're no longer competitive and that company ceases to exist. All those people go form a new company with a new way of working that's at the high end of the bell curve and continue working their way down. So industry is outpacing almost all of the members of industry and everyone, the company's just live for a little while and then drop off the bottom. But there are some companies that are actually able to keep up with that pace and not drop off the bottom. Hunter Technologies is a fine example. They a few years back made a change to Mob Program, talk a little bit more about that. And one of the impacts of that was they went from annual releases of two to three products a year, so two and a half, to releasing twice a day and shipping 25 products a year on average. 10x improvement in productivity, same products to the same customers. People talk about legacy code as a debt, code debt and a cost. Working in legacy code is harder than working in other code. And in fact, you can ask someone the question, so how much harder? Assume that you have the same task to do. You have two different ways you can do it. You can implement it in your own code base using everything that's there today, integrating to the stuff that's there today as an add on feature. Or you can implement it in a brand new project, make it a console app or something. You're not allowed to use any of your existing libraries or anything that you have built up. But you also don't have to integrate it to anything. What is the cost difference between those? For many teams it's as high as a three times as expensive in legacy code using all of my existing stuff as it would be to just do it as a console app. So legacy code is a cost, I have a debt there. And I have to pay a tax when I implement every feature. For James Schor had a team a couple of companies ago in which it was an asset when they measured that they found that they were about three times as productive in the legacy environment as a green field. Because there was so much more advantage, so much more code already existing in their legacy system that they could take advantage of. It was an asset that paid a dividend on every feature that they built. When they needed to add internationalization, they were producing an application that the customers had promised to them would only ever be English. It was only for the US market and it was easy. And so they'd built with that assumption and hadn't really thought about internationalization. And then the customers came back and said, actually, so we just got a new investor and we want you to support English, French, and Arabic. And it should just work in this RTL thing, figure it out. And ask, so how long is this going to take? And they thought about it for a little while and scratched their head and said, okay, we need to run a spike so that we can give you an answer because we know internationalization can be hard. So we're gonna go figure that out. They came back an hour later and said, we'll have it done by the end of the day. And they did. Because they just happened to have factored all their code well so that even though they hadn't ever thought of this requirement, all of the things about string handling and the language and layout and position were each located in one class. They had three classes to update and the updates were obvious and the code was well tested. At Facebook, 90%, actually more than 90% of the code that they ship is not their code. Facebook has identified that there are one or two things that determine their business. They have a key competitive advantage and they keep those all internal. Originally it was Facebook was able to do compression of large sets of photos better than anybody else. So they could have more photos stored than anyone else could store. And they've got a couple of things like that that are there and are proprietary and they build and code that. And they code nothing else. Everything else they do is shared, it's open source, it's whatever else. Some of it, they write and then share it out and then other people contribute. Some of it they consume, but they are very good at analyzing what is our key competitive advantage, let's code that. And what isn't our key competitive advantage? Let's not code that, let's turn that into commodity software so that it can't be anybody's key competitive advantage. These teams ship fast. And it's not necessarily that they ship on a high cadence, but they have the option to ship on a very high cadence. And when I talk about option to ship, I mean like company that my wife was at where when the president wanted to do a demo to a new customer. He would just grab the latest thing from the CI server and throw it in front of the customer. They don't worry about which one it was and there wasn't any concern about there might be something broken. Because he could take any random thing and show it in front of a prospective customer and not lose the sale. Flickr ships, my data is out of date, but three, four years ago they were shipping a couple hundred times a day. Amazon ships every 12 seconds. Now, Amazon's 12 seconds is across the whole company. So it's not that any one team in Amazon is shipping that frequently. But teams at these companies are checking in to Maine. Typically, I won't go more than an hour, often 15 to 30 minutes between commits to Maine, and every one of those is either fully shipped live or fully shipped through my CI system and packaged up so that someone else could basically decide that this one wants to go live. Stakeholders are all involved from the start throughout the whole process. At Merrill Lynch, this is now several years ago. They set their traders and their software people working together. So every experienced trader had sitting, he was sitting there doing his trades at his computer and sitting right next to him was a pair, a pair of developers. And the developers were virtually connected into teams of eight. And their job was to execute any piece of software that would help that guy make more effective trades right now. So typically, they would produce products in like a one or two hour turnaround time. The trader is doing some trading. He says, it would be really handy if I could do this sort of analysis. And the programmer executes that. And three hours later, he's got a tool to do that sort of analysis. The stakeholders are involved all throughout that process. The trader, as he's trading and doing stuff, he asked for the analysis. The coders code for 20 minutes and they say, so is this what you're thinking? And they look over, yes, back to trading. These teams are transparent and they invite decision collaboration, right? It's not just that they report status out and are obvious about what they're doing. It's not just that they will allow people to come to their startups, their stand-ups and interact or come to their planning meetings and interact. The groups are working out loud. They are actively engaging everybody who is interested in those discussions. They're making it very easy for people to find out what's going on, to get up to speed, to throw in some information and choose to participate as much as they want in a decision or not. They can drop by and leave. They can drop by and stay. It's up to everybody how much they want to do. Yammer recently was purchased by Microsoft a couple years ago.  And one of the things that was added there was annual budgeting. They'd never done budgeting before, because they were not a public and trading company, and so who cares? And when they came and joined Microsoft, then the requirement came down to do budgeting. Now, Microsoft wanted Yammer to keep Yammer's culture as much as possible. So it wasn't placed initially as a requirement. It was as a pitch of we think that annual budgeting will be useful to you for the following reasons. And the leaders that sort of heard those reasons and yeah, it makes a lot of sense, okay. So at that point, management of this division of Microsoft is now bought into, yeah, we need to do annual budgeting. So the question is what do they do? How do they roll that out? At most companies and most parts of places, what they do is they start creating budgets and they invite people into the budgeting process and so on. So at Yammer instead what they do is they posted on to the Yammer Eng leadership alias, which is the one that everyone's on. There are more people on that public group than are in Yammer. There are people who are no longer, who have moved other parts of the company that are in that group. There are other people from Microsoft in that group. This is the primary mechanism whereby low level management conversations and decisions happen, and it is completely public. So when the budgeting thing came up, the leaders of that group popped in and said, so annual budgeting has been suggested and we think it makes sense for the following reasons and we think it also has the following downsides. So guys, who is interested in working with us to figure out how to amplify those benefits and decrease the downsides in how we're gonna roll out budgeting? And should we actually roll it out? And they started that conversation. And they didn't actually reply back to Microsoft that yeah, we're going to do this until everyone in Yammer had figured out that yeah, it actually, it makes a lot of sense for Yammer. So bringing these all together again, these are average two star results. There are two star teams that exceed that. There are two star teams that are a little bit below that during the same category. These are not what the results that most people are used to. Most people have never seen a two star proficient, fluently executing agile team.  It's not that agile planning allows us to change direction and we can embrace change late. It's that when you're working in a way that you get these results with this level of discipline, you can change your mind on a whim, right? So you can welcome late changing requirements as advantage because you have no sunk costs, you might as well. Like, if there's new information, let's use it. So now let's talk about making awesome. That before was discipline. That level of result is what you can get by just running the formula. You get that by out of the book extreme programming without really modifying it. Except you might have one or two contextual things that you need to nuance a little bit. But pretty much that's what you're gonna get and teams get it over and over and over. This is, once you've gotten that, now where can you go? So first one I wanna talk about is again Yammer, metrics driven development. So this is an interesting case because Yammer is, at this point, moderately large. I consider them small, there are a couple hundred people, but many people consider that larger. They are trying, they're a single product. They're trying to make that product better. And they have no real central planning. They do, they have a number of bodies that are coming up with ideas and whatever, but they don't actually need central planning. So what they've done is they value metrics and they do metrics driven development. So they are continually gathering information about the customers. And they're using that information to do two things. One, they run a whole lot of analysis to identify what are the measures that correlate with future revenue? What is the lead time of each measure? And what is the correlation coefficient of each measure? So that they can identify from the many hundreds of things that they measure. Which are the ones that we should really be paying attention to as indicators of future success? And they're continually reevaluating that model. Because they don't assume that before Microsoft and after Microsoft, after making joining and working with Office 365, any of these things could dramatically change what measures actually drive revenues, and many of the features they do could change even what measures drive the revenues. So they're continually reanalyzing the measures that they'll use to drive the business on the basis of what predicts revenues. And then the decisions of what to implement are all driven by what moves these indicators. And so when they go decide what to build, it's not a popularity contest and it's not people stating their opinions. It's people coming up with ideas and then saying which measure they expect it to move, and then they run it and see whether it moves the measure. And they are often surprised by which things have an impact. Turns out changing the font to sagoy and changing the color to blue had a 1% improvement on their engagement metric, which was one of the most significant improvements in engagement they had seen. And completely shocked them. No one has been able to explain why, but fact is it works better for customers, so whatever. So this is an example of hypothesis driven development. So a canonical example of hypothesis driven development really is the lean startup stuff, build, measure, learn, everything at IMVU. When you're doing hypothesis driven development, you don't assume that you're building features. You assume that you're testing hypotheses. The purpose of every story is to increase the amount of knowledge that we have to predict what stories will be useful. Secondarily, if the story is useful, then by all means, we will keep it out there. And if it is not useful, then we will not keep it out there. So in this hypothesis driven environment, we're really focused on the knowledge gain that we get from doing work. Not focused on the implementation and what the system turns out to be. The system is a side effect. It's a result of gaining knowledge about the customers. Another direction that people are going is again related to figuring out what should we build. You'll notice that a bunch of these make-awesome's are figuring out what should we build and how should we understand the customers and interact. Whereas a lot of the stuff before was about execution. That these things that people are exploring are three-star agile. So the next one is customer development, design thinking, and a number of other related sciences. Many coming out of user experience design. Many coming out from other fields. Nordstrom Innovation Lab is a great example of this. If you have a chance at some point, watch a search for Nordstrom Innovation Lab on YouTube. They've got a really great five minute video that shows a lot about what they do. But in the video, they move their dev team from this lab out into a store in Nordstrom. And they set up an environment out there with their whiteboards and everything else in the middle of the floor. And they're testing out ideas. So the purpose of this lab is people from all over the company have some idea of some product, some software product, that they think will help retail sales. And this lab's job is to test and see which of those are worth making a significant investment in and which ones are not. And then those ideas that are worth making an investment get flow into the regular development pipeline and they make an investment. So this group is testing out one of those ideas. It's for an iPad in the sunglasses place that allows you to take a selfie with a couple of different classes on them and then compare them easily side by side so you can decide what you want to look at. They build that over the course of a couple of days, iteratively.  And they aren't just doing that in the way of here, let's test this out and let's demo it. They're actually very intentionally doing design thinking. So through the whole process, and this you can't really see in the video because it's condensed, but through the whole process they're very carefully paying attention to when they're doing divergence and when they're doing convergence. They've got different activities and different ways that they're engaging with the customers to gain different types of information. They're following a very rigorous process of finding out what we should build by the process of designing and building that thing. And the nice thing about these techniques is they're established, they are documented, they work. So much like we have techniques that work for getting to two star agility, these are some that work for once you've got that ability to execute, getting some of the three star advantages. Co-opetition, this is another interesting one. So Derrick Neighbors' company, who again I've forgotten the name of the company and I apologize, they found that they had one chief rival in their market, them and one other competing for the market. And they did something that was really odd. They went and bought a building that was twice the size of what they needed. And then invited their chief rival to lease the other half. And they put the cafeteria in the middle so that everyone would eat together and talk together. And the whole point was that they wanted to get conversations going between them and their chief rival. And engineers would swap ideas and they intentionally reduced the barriers. They told all their engineers, feel free, talk to them about all of our tech. Go to, end of the sales people, talk to them about sales and even future sales and things that are in the pipeline, go to. And the result was that these two companies started swapping ideas. And they started seeing where each of their technologies had an advantage of the other and all the techies were able to see that. And then they could tell their own sales people. And the sales people could do that. And very quickly they switched from, over the course of some number of months, they switched from showing up at a perspective sales with two competitors. To showing up with both of them saying, we're able to do more of a consultative sale, ask what the person needed and say, okay, sounds like about three quarters of it is stuff that we do. And the other quarter, you should go talk to these guys. And they were all referring things to each other. Total market size goes up a lot. No other competitors in the field can really compete against the two of them cooperating together, and it was better for both. And it is still competition. They had a couple of products where they were in direct head to head competition. But they were doing some of each, mobs. Hunter Technologies is the canonical example of this, mentioned them before. So at Hunter Technologies, they do not program solo, they don't even program in pairs. The whole team, which is seven people, sits in front of one computer, dual screen projector, all day, they program single threaded. So at any given time, there's one typist, typist is not allowed to think. The typist rotates through every five to 15 minutes. The other people in the room think, discuss, and command the typist what to do. The other people in the room are all sorts of other people in the room.  Now, of course, since they're mobbing, everyone has developed all of their skills. But there's different mindsets. You've got the couple of people who really like tearing systems apart. And the couple of people who are really creative, and the couple of people who are really analytical. And actually, since it's a mob, it no longer requires programming skill to be part of the programming team. So Hunter Technologies produces software that's factory control automation. The vast majority of the company are factory workers that are working out on the floor doing stuff. So at any given point, they rotate one factory worker in for a couple of weeks at a time into the mob. That person is a full programmer, member of the mob for a couple of weeks. They're bringing in all the knowledge and experience of, yeah, I mean that seems like a great idea. But you need to understand the way these things are laid out in 3D on that factory floor, right? It's a different set of knowledge. And that person is fully able to participate because you don't need any particular set of skills in order to be part of the mob. And that's what has resulted in Hunter just not having bugs anymore. They shipped 65 products in a row without any defect ever being found in testing or in live. It's just an amazing story. Now, mobs, again, brand new technique. I can't say this is well tested. I can say that a whole bunch of people have had some really interesting experiences in its anecdotes, but you might want to try it. Responsive organization. So this is, as you're starting to get even beyond three star, you're starting to build a culture that thinks differently in your company. Fundamentally a decentralization, not just of decision making and power, but of the way you think about things. So this one, there's a number of movements that are coming together under the responsive organization banner, working out loud movement and a number of others, Management 2.0, I don't remember all of them. But they're all looking at different ways that businesses can be run when the amount of information increases, the ability to execute increases, the lead time and transaction cost of changing direction decreases, and the amount of transparency increases dramatically. All of what you're happening in business today, you've got the ability for people to see all the code across the company. And to see all the decisions across the company before they're made. And to see the information about all the customers across the company. And to communicate easily. Red Robin is a perfect example of this. So Red Robin, a restaurant chain in the US, they had for forever a menu that was centrally designed. It was built in the headquarters. And the reason for that is because of logistics, supply logistics. They need to ensure that they can send everyone the same sort of food and everyone can build the same sorts of things. And then the customers also want a uniform experience. They want to show up at a Red Robin, any Red Robin, and get about the same thing. So central designed menu that would then get distributed. And that happened like twice a year or something. I don't remember, two or three times a year. And at some point they brought in, they started using Yammer. And Yammer originally was rolled out in the central office as a replacement for email where it floated like a lead balloon. Nobody used it, there was no value, there was no point. And so it stopped getting used in the central office. However, it made it out to the periphery. It made it out to all the Red Robin stores. And what people there found was that whenever a customer would complain about something, the wait person would grab their phone, they pulled out and they said, here, could you just type that into the Yammer thing? And they put that in there. And whenever a waiter would have a problem with trying to figure out how to get something out of the kitchen. They'd type it into Yammer and, hey, has anyone else seen this? And all of the stores across the US were all in Yammer together. And so some customer would have some problem in New York. And a store in Cincinnati would say, yeah, actually we had that problem. We solved it this way and it seemed like it helped them, right? And so then they'd apply that in New York. And ideas just started flowing from across the wait staff level, all over the company. The wait staff at a restaurant, those are the people that are in contact with your customers, right? They're the ones that actually have the most information about the most important resource in your company. So menu organization goes through. The next time the big menu comes out from central, there's a fairly quick response from a number of the stores. It's like, we recognize and value the ideas that you sent to us. And most of them are pretty good. So it looks like you're making the following four changes. Well, those two, we already implemented on the basis of customer demand. And it turns out that the first one of those does sell pretty well. The second one doesn't, we already discontinued it. This third one that you did is an interesting idea. We tried these other three things that were pretty similar. And we think that it's probably better if we go in this direction. So we're probably going to unless you correct us. And that fourth one is new. We'll go ahead and try that. They had so much more information and data. That was the last time that menus were centrally planned. Because now they had an ability to decentralize the planning of that menu. And to make the decisions on the basis of more information. And all the people at the restaurants were also fully aware of the logistics concerns and all of that sort of stuff. Because they've got the cooks there who are dealing with all of that, right? So they could figure out that we needed to have a uniform menu and how to do that. And the only thing that they really needed from corporate was, if we're going to add this ingredient. Like, what's the supplier? Can you get a buyer on this? So this is a shift that we're seeing towards responsive organizations. And I won't say that it's a groundswell, everyone's going this way. But we're starting to see them come into existence. These organizations that are making fundamental business decisions, strategic business decisions on the line. With the people who have the most information, not with the people who have the most authority. And that means that the old power structures end up changing. And in fact, the responsive organizations, they talk about here. Learns and responds rapidly through an open communication, experimentation, and working as a network. It stops being the relationships between people in the company. Stop being about power and authority. And start being about moving information around. And your ability to work is based off the information you have. And how much you can share that information with others and get information from others. So too long to read. Awesome discipline is awesome. Most people haven't seen it. But it is actually pretty darn amazing what you can get just by doing things by the book at high discipline and never accepting slacking, right? Never agree to something that you're not going to commit to. If it's worth doing, it's worth doing to access. And if you do that, you get amazing results, right? Few teams do that. I used to when I was going out and getting jobs, the number one criterion that I would rate on depending was whether a team was willing to be the best in the world. If a team was not willing to be the best in the world, I wasn't going to work there. And it's not whether they want to be, it's what they're willing to do. They're willing to put forth, to maintain that level of discipline, to be constantly asking themselves, questioning themselves, and really improving themselves. Because if they are, you can get these results every single time. So most teams think they are doing pretty awesome, and they have the great discipline, until they see one of these teams. Some teams really do have this discipline. This is not a one or two teams have these results. When I go talk to XP teams, I show them some of the papers of bug rates. And Nancy Van Schoedenwurt's paper, Embedded Agile by the Numbers with Newbies, it's a great example. Full detailed analysis of every defect they had, the whole three-year project. And XP teams go, yep, it's about right. Now it's normal. And the teams that are really pushing the boundary today, they're the ones that did that, and then they built on it. So the key thing is, go ahead, and when you hear about continuous deployment, and when you hear about Lean Startup, when you hear about all those things, be inspired by them. But if you want to go execute them, make sure you've built in the discipline first. Build the discipline, get the strong results, get the ability to turn on a dime without any sunk costs. And then leverage that just like those people are who are exploring continuous deployment and Lean Startup and Build Measure Learn. And really go for that. Thank you very much. Conversation and telling more stories. If you'd like to do questions here, we can, but come on up. So the first one is the average for teams that haven't started that two-year transition to discipline. When they get there, then it's more like 99.99% is value. And the once in a while they have some stabilization.


According to latest estimates by the Centre for Monitoring Indian Economy, 1.3 crore people lost jobs in just June this year. In May the number of employed persons was 40.4 crore which dropped to just 39.1 crore by June end. As can be seen on this chart, employment has been hovering around the 40 crore mark for the past year, but the nose-dive last month has exposed the extreme vulnerability of India's working population. What does this really mean? An employment level of 39 crore means that only about 36% of the working age populations is actually employed in India. This stares apart the lofty talk of the advantages of a young working population for India and reveals the dire and distressful situation of the Indian people. What makes the situation more worrisome is that along with growing job loss, the labour participation rate or LPR in the country has seen a downward shift. The LPR which refers to the share of people who are working or willing and seeking work has dropped from 39.91% in May to a low of 38.3% in June. This is the lowest LPR since the first lockdown back in April May 2020. A reduced LPR along with growing job loss means that not only have people lost jobs but that they have lost all hope. These hopeless and frustrated people have quit the labour force altogether, preferring to perhaps wait it out till jobs become available again. Another measure of the job situation is the unemployment rate, which measures the number of unemployed persons as a percentage of the total number of persons in the labour force. This has risen from 7.1% in May to 7.8% in June. What are the reasons for this dismal state of affairs? The delayed onset of monsoon in June this year is mainly responsible for the low number of employed persons and also for the low LPR. Usually the sowing of kharif crops starts in June with the arrival of monsoon rains. This is labour intensive work with lakhs of agricultural labourers including women out in the fields. However, the crucial monsoon rains were delayed this year and rains properly began only by the last week of June. This meant that the army of agricultural labourers was forced into idleness through most of June causing a sharp increase in unemployment, a drop in LPR and a decline in the number of jobs. Agricultural labourers and small or marginal farmers are the most vulnerable section of Indian society and also the largest in number. The large scale unemployment in these sections will not only cause huge distress among the poorest families but will also mean that a substantial chunk of the population will have no money in its hands. This will further depress the languishing demand and thus perpetuate the low level of economic activity that is already haunting our economy. It is probable that with the arrival of a full-fledged monsoon in most parts of the country by the end of June joblessness will decline somewhat. But what this chain of events highlights is the extreme dependence of India on the monsoon and the vulnerability that it brings. Even a delayed onset can mean a tremendous and large-scale impact on lakhs of families. This is not a sign of an advancing economy and definitely not a feature of an aspiring economic superpower. That being said, agriculture was not the only sector that suffered. CMI estimates that job losses in June also include the loss of 25 lakh salary jobs. Unlike in the case of agriculture this could not have much to do with the delayed onset of monsoon. It is known that the industrial sector is the biggest potential source of jobs for agriculture's plate peasants and agricultural labour. With this sector still growing very slowly or just stagnating, those displaced by job loss in agriculture have no alternative now. Additionally, with demand stagnating, industry has no prospects of increasing productive capacities and thus giving employment to new members of the workforce. What is the government doing to help? At a time when focus should be on resolving existing problems, the Modi government is adopting policies that heighten the job crisis. It is trying to implement labour codes that will increase contractual work with easy hire and fire leading to more instability of employment. It is applying fund squeeze to various job related schemes that provide some relief to jobless people. It has reduced the prospects of secure employment in the armed forces by announcing its partial contractualization through the controversial Agni Pad scheme. Its reliance on the so-called new economy, jobs like startups and gig workers is also not reaping results in recent times with large scale job shedding. To cover up their failures and appease the public, the government announced that 10 lakh government vacancies will be filled up. Although the modus operandi for this filling up has still not been announced, in all probability it will be through outsourced means at low pay scales and therefore will not be of much help. Needless to say, the prospects of any major jump in employment levels in the coming months are bleak and with a stagnating economy which is also in the grips of an inflationary spiral, the distress of people is likely to mount.


With seemingly endless options at your local health food store. It's hard to imagine that there aren't that many good options for protein bars So let's take a look at the ingredients and go over why that's the case I think just about everyone including myself would get incredibly overwhelmed when looking at all of these options It is absolutely crazy, but the first thing we have to ask is is the bar organic if the bar is not organic that kind of removes The worst options already. Does it make sense to look at the products that aren't organic? I guess so I guess some of them might not be too bad, but that puts a lot up in the air. One thing I noticed immediately was These collagen protein bars have Really been marketed strongly over the past few months and if anything these are worse than the majority of the other products MCT oil is highly filtered. This hydrolyzed collagen has to go through so many processes. Imagine They're making this from Agrochemical phila beef waste the skin the hooves all that garbage from cows They're putting in cashew butter these collagen protein bars are One of the worst things that are being sold under clever marketing tactics So this is a minimal ingredient bar organic dates organic peanuts organic strawberries organic chia seeds If we analyze each of these foods on an individual basis, you know The peanuts have omega-6 concerns the chia seeds have anti-nutrient concerns strawberries and dates aren't too bad But then all you have is caloric energy. So overall I would say You know this bar isn't actually that bad John's bar. It's all organic Maybe they have a bar that's passable without omega-6. So they put almonds and seeds in here as well I think this is gonna be an overarching theme a lot of these protein bars are going to contain Omega-6 a lot of them have peanut butter almond butter Some type of nut butter is going to make it so we don't really want to consume these so what's up with these are X bars They look minimal ingredients three egg whites 14 peanuts two dates no BS. Yeah. Well, it's not certified organic. So Outside of the biotin deficiency concerns with the egg whites, you know conventionally raised chickens Estrogen what's in the feed peanuts how make it six dates nothing's organic if it's not organic Look regardless of how simple it is Even if this was organic, it would be an issue. So now you're adding even more pollutant and agrochemical concerns So these epic bars might be one of the better things we're looking at today Egg yolks chicken and apple. So the problem is even if this is organic and It's from quote cage-free chickens. Whatever. It's still American corn and toy-fed chickens So these are thrown out the window based off the fact that these are probably loaded with estrogen if they contain American Chickens in that we're about this 100% beef beef dried cherries walnuts lactic acid I Mean I still have stuff in it. You don't want to eat these have bacon pork is a red flag All right, this might actually be the first one that I would eat what they put in the venison lactic acid No additives not stuff you want and it's not certified organic either. So is this the worst thing in the world? I mean, what are you gonna have it for a snack? There's much better options in the supermarket.  You know 30 ingredients not organic bunch of chemicals additives. There's no reason in Assessing this this is near the bottom of our list so far. All right so far. We've looked at three categories of bars They seem to have some meat-based bars that aren't organic that are minimal ingredients But again, we have conventional feed the animal concerns We have minimal ingredient bars the non-organic ones are certainly inferior to the Organic options we have so really the Jones bars are looking pretty good. You know, we have the BS keto marketing bars that have 30 ingredients in them Collagen proteins a category on its own I think in deceiving people Let's check out organic plant-based performance protein bar So although this is organic The bioavailability and nutrition of this is It's gonna be all towards macronutrient energy and look at that ingredient list. It's ridiculous, but let's go down it So organic tapioca is a start source. It's not too bad T protein definitely has some anti-nutrient concerns almond butter omega-6 pollutant mycotoxic concerns Organic vegetable glycer and it's highly processed sugar.  So this gets worse and worse and worse on paper compared to a standard American diet It's actually not horrendous, but it's still you know something That's probably towards the middle of the pack here. You know since it is organic There are some pollutant concerns removed, but that's it one apple one pear in each food bar Why don't you just go buy an apple in a pair? We're in the supermarket ingredients apples and pear Okay, so I mean if this was organic Then I would go for this 100% because it's just fruit But you know why don't you just go buy some organic food if you're gonna get this? I guess it's nice to carry around it, but you can dehydrate your own fruit and blend it into a bar like this I think fairly easily Organic this is why we made the warrior bar guys This is exactly why we made the warrior bar. Look at all this crap These Lara bars are something I've always heard of vegan gluten-free peanut butter cup I Guess You know, I think they were just known for tasting good I think that's why people like them definitely less ingredients, but still omega-6 base still not good Yeah, I mean that's not horrendous, but Again towards the middle of the pack here a lot of plant-based nonsense a lot of agrochemical waste a lot of concerns again, I think the Jones bars are at the top of the list here and If these were organic, they'd be better too. I don't see too many other organic bars Look, what is this nonsense pecan goji pistachio? Like I don't even have to look at that. I guess we could take a look at kind it's a Popular brand high amount of ingredients not as high as some of the other things we've seen but This is mostly chemicals and processed garbage. So we don't want that the hemp bar Hem protein is really making a push, but you know, the amino acid profile isn't ideal Hard-on digestion high and anti-nutrients a Lot of vegan bars. I think most of these down here are all plant-based nonsense bars Nothing we really want to consider Go macro peanut butter organic bar if you put peanut butter in a bar, it's already off my list It's too expensive to use quality ingredients. You want to make a bar with macadamia nut?  What's this? Mother-daughter own invades in the small rural community our mission is to spread awareness for a balanced plant-based lifestyle with products that Okay, we're poisoning you be nice to us And we put 40 ingredients in it. I was hoping I'd be pleasantly surprised by something Oddly enough one of the first ones we looked at was the best one What about this Primo kitchen astroturfing BS?  It's like it's supposed to be paleo and good But it's actually just standard American bullcrap. It's not even organic Look how you charge a $2 for one bite because while this bar is I'd rather not eat it's so processed This is like these bars are so incredibly processed if you looked in the factory while they were making these It would just be a bunch of powders and syrups and and mush You would not be able to distinguish the ingredients on their own. Oh mega three We know how this one's gonna go Unless they put fish in this bar, they shouldn't be marketing it as a mega three We believe a strong brain is just as important as a strong body by packing our delicious protein bars with Sustainably source omega-3s and 14 grams of grass.  So the grass and marketing is probably deceitful Oh, they put fish in here. Man, this must taste horrible But why would you put whey protein fish oil and then put all the if you have allergies This thing would make you sick and go to the hospital So there's two concerns here one, you know, it's not organic way. It's not from a it's probably American way So there's agrochemical and estrogenic concerns and you never want to buy a fish oil Supplement it's basically oxidized Omega-3 and then they put vegetable why don't you put vegetable glycerin tapioca syrup and something that is seemingly good The marketing on this is terrible.  Oh mega-3. Oh mega-3. Oh mega-3. I don't know apparently not doing that. Well, what about these guys? Square organics. Are these guys gonna take the crown kings from From Jones bar organic whole grain brown rice here protein Organic whole grain brown rice protein. Okay Here's the deal. So that's the only bar we've seen today that uses Grasted whey protein. I don't think we've seen another bar that has whey protein in general a lot of these Protein energy bars are moving away from a protein source because it's expensive I mean collagen protein, you know, they have a source of protein But it's agrochemical waste and they're charging $4 for two bites of bullshit these other ones though Very little protein. It's all plant-based cheap ingredients You know the meat bars or none of them are organic. None of them are reliable. It's all it's all astroturfing This is basically conventional feedlot beef Whatever chicken and they're trying to market it as healthy, which I don't really like So your protein options are basically Astroturfing agrochemical waste or plant-based protein, which isn't available He took off his mask in the store This has me more and more excited for us launching our warrior bar officially so we should have it in Two ounce portions relatively soon. So you guys can go to franky syringe meat calm We have plain which is for really strict dieters. It's you know, no carbs. Basically just whey tallow and salt We have a vanilla ice cream flavor. We have chocolate. We have banana coconut macadamia nut So definitely give those bars a try guys minimal ingredients high quality Free of agrochemicals giving you nutrients protein fats everything you need to be healthy. So thank you guys for joining me today Hopefully this answers some questions Basically what I would do is buy something else from the supermarket There's way better options than these protein bars And you know, I would even try to make something similar to what we have on franky syringe meat yourself Thanks again for joining me today guys. I'll see you for tomorrow's video


Hello, I'm Megan Tomio, Engineering Librarian for Ohio University Libraries. As a current faculty, staff, or student affiliated with Ohio University, you have access to the electronic and print books, journals, databases, and more, both on and off campus. If you are no longer affiliated with Ohio University, you no longer have off campus access to our online resources. When you are on campus, access to our online resources is seamless because we authenticate by IP address. When you are at home or work, we direct you through a proxy server, which requires you to enter your Ohio ID and password to authenticate. You may see a login like this from Ohio University Libraries, or you may see a login like this from OhioLink. If you see a different login or are prompted to pay for full text, it could be because Ohio University Libraries is not paying for access. Double check the date of what you need against what we have access to in Alice's Catalog. Current faculty and students in the Russ College of Engineering and Technology can also access online resources by using the virtual desktop. This will give you the same seamless access as if you were on campus. Online students in Ohio can access our print materials via OhioLink. Online students not in Ohio can make Interlibrary Loan Iliad requests for our print materials. If you need any assistance, do not hesitate to ask. I am happy to help.


go in and get started because it's already a couple minutes late. So it's great to be here at RubyConf. This talk is entitled, Rota, the Routing Tree Web Framework. My name is Jeremy Evans, and I'm the lead developer of the Rota Web Framework. And I'm also the lead developer of the SQL Ruby Database Library. So I started off explaining why I created Rota. After all, there are a lot of Ruby Web Frameworks. So there should be a good reason for creating another one, especially if you want to recommend that other people use it. To explain why I created Rota, I need to go back about 10 years when I first started using Ruby. So I first got into Ruby in 2004, late 2004, about six months after Rails was first released. I think 0.8.5 was the first Rails version I used. And I found that Rails made web development much easier than the frameworkless PHP that I was currently using for web development at the time. And I used Rails for pretty much all of my web development for a few years, but I gradually got disillusioned by the complexity of Rails. When I found out about Sinatra in late 2007, I was amazed with the simplicity. The fact that you've just specified the routes you wanted to handle, and they just yielded to a block to handle the action, just made developing web applications so much simpler. So in April 2008, I started using Sinatra for all of my new web applications. Now over the years, I found that as the applications I was working on got more complex, I ended up with a lot of duplication in my Sinatra routes. Since my only real basis of comparison was Rails, and the Sinatra code was still simpler than what I would have written in Rails, I didn't really consider this too much of an issue. Now in July of this year, I was looking at a comparison of a bunch of lesser known Ruby web frameworks, and I read about Cuba. Now Cuba has been around since 2010, but this was my first exposure to it. As I read about Cuba, I saw how it addressed the duplication issues that I was seeing in my more complex Sinatra applications. And from reviewing some benchmarks, I also saw that Cuba was significantly faster than Sinatra. After trying to convert one of my simpler Sinatra applications to Cuba, I found there were quite a few things I didn't like about Cuba that were easier in Sinatra. And I came to the conclusion that I should create a new web framework based on Cuba that borrowed many features from Sinatra, along with some other ideas I had about extensibility and non-pollution, trying to get the best web framework for the types of web applications that I developed. And that's the story of Rota's creation. Now when I originally decided to fork Cuba, I hadn't decided on a name, so the temporary name I used was Sonuba, since it borrowed features from Sinatra and Cuba. And as I was laying in bed one night thinking of a name, I thought about what made the framework special. And in my mind, the main difference between Rota and Sinatra is that in Sinatra, you are iterating over an array of possible routes. While in Rota, the routing process is broken down and generally takes the form of a tree. So Rota is named after the Rota trees, which appear in the ease video game series, and help the main characters accomplish their goals. And this picture is from Ease Origins, and it shows a Rota tree prominently. As I said, the main feature that separates Rota from most other Ruby web frameworks is that it is designed around the concept of a routing tree. Since most programmers are not familiar with the routing tree concept, I'm first going to talk about what a routing tree is and how it works. Now before I can talk about a routing tree, I need to talk about routing in general. And in general, routing is the process of taking the request and finding the code that should handle that request. And while routing can consider any aspect of the request, in most cases, only two parts of the request will be used during routing. And these two parts are both contained in the HTTP request line, which is the first data transmitted from the client to the server during an HTTP request. Now an HTTP request line looks like this. Here, get is the request method, and albums one tracks is the request path. And it is possible to use other parts of the request during routing, such as routing using information from the request headers or the request body. But in most cases, only the request method and the request path are used. Sinatra and other similar Ruby web frameworks look at the full path of the request when deciding how to route a request. So they iterate over their array of possible routes, checking each route to see if it matches the current request. Now a routing tree handles things differently, routing by segments of the path. So in routing request for albums one tracks, a routing tree is going to look at the first segment, albums. And if the album segment does not match, it's going to skip the entire albums branch so that other routes under albums are not considered. If the album segment matches, it's going to look inside the albums branch of the tree for a route for one tracks, ignoring other branches. So incidentally, this is more or less how a file system works. When you ask a file system to open a file, it doesn't compare every path on the file system to see if it matches the requested path. It looks at the first segment of the path, sees if it is a directory, and if so, it looks inside that directory for the rest of the path. Now if the use of a routing tree was purely a performance issue, it wouldn't be all that interesting. What makes routing trees interesting is that at any point during the routing, you can operate on the current request. So if any of you have used the Ragel state machine compiler, this is similar to Ragel's ability to execute arbitrary code during parsing. So now that I've briefly gone over what a routing tree is, let me go over how Rota implements the routing tree concept. So let's start with hello world, since that's the simplest case. So this Rota app will return hello world as the response body for every request. And while it does not show off the routing tree aspects of Rota, it does show that Rota gets the response body from the value that the block returns, which is similar to Sinatra. Now in almost all Rota apps, you're going to want to actually use Rota's routing tree methods. So the first routing tree method I'm going to discuss is called r.on, which creates branches in the routing tree. So here you call r.on with the string albums, which will match the current request path if the request path starts with albums. Let me break down what is going on here. So in the first line, we are calling the Rota.Route method, which is the start of the routing tree. All requests that come into the web application are yielded to the block that you passed to Rota.Route. This block is yielded a rack request instance with some additional methods, and by convention, the block argument is named r. The additional methods added to the rack request instance are related to routing the request. So as mentioned earlier, the requests.on method is used to create branches in the routing tree. Any arguments you pass to this method are called matchers and are used to match the current request. So in this case, a single matcher is given the string matcher. And in Rota, string matchers match the first segment in the request path. So if the request path starts with albums, this will match, and the request will be routed to the block that you passed to on. Now that block returns a hello album string, which Rota will use as the response body. If the request path is artists, this will not match, so r.on will return nil without yielding to the block. And execution will continue after the call. Now in this case, there is nothing after the call to r.on, so the return value of the Rota.route block will be nil. And since the block did not return a string, Rota will use a 404 response status code with an empty response body. So that provides the principle of least surprise, where if you do not specifically handle a request, an empty 404 response is used. And while it works, this code has issues, because it returns the same response for all paths under albums, including albums should not exist. And in general, that is not what you want. What you probably want to do is to return a 404 response for any path that you do not specifically handle. So if you only want to handle albums and not any paths below albums, you can use the r.is method. r.is is similar to r.on, but it does a terminal match. So it only matches if the request path is empty after processing the matchers. So this code will not match the albums should not exist path. So the reason for the method naming here is that r.on matches on the request prefix. And while r.is matches only if the match is complete. So routing trees in Rota are built using a combination of the r.on and r.is methods. r.on does prefix matching of the request path. And r.is does full matching of the request path. So if you were routing purely based on the request path, you could say r.on creates branches in the routing tree, and r.is creates leaf nodes. So here r.on albums creates a branch, which handles all paths under albums. Here you're calling r.isList, which will match only if the current request path is list. That may seem odd that this works, but the reason it does is that the request path is being modified as the request is being routed. So when a request for albums list comes in, the routing tree uses the initial request path. When the r.on albums method matches, it consumes albums from the front of the request path. So inside of the r.on block, the request path is empty. So r.is matches, or it's not empty, it's list. r.is matches only if all of its matchers match, and the request path is completely consumed by the matchers. Since the request path is list, and that matches the string that you give to r.is, this request matches and hello albums will be returned. If you get a request for albums list all, the r.on call will still match, but the request path inside the r.on block will be list all. And since r.is list does not completely consume the request path, this request will not be matched, and Rota will return an empty 404 response. So far, I've just been focusing on routing using the request path. As I mentioned earlier, routing usually takes into account the request method as well. So consider this routing tree, which will handle requests for albums new. In order to handle the get and post request methods, Rota has r.get and r.post routing methods. So if you call these methods with no arguments, they just do a simple match against the request method. So r.get matches get requests, and r.post matches post requests. Now here, a get request for albums new will return hello albums, and a post request for albums new will return album added. So the way routing tree is usually built in Rota is by combining these methods. You use the r.on method to branch based on the request path prefix. You use the r.is method to do a complete match on the path, and you use the r.get or r.post methods to handle different request methods for the same request path. As I mentioned, if you do not provide any matchers to the r.get or r.post methods, they just do a simple check against the request method. If you provide any matchers to these methods, they also do a terminal match on the request path, which allows for an API that is similar to Sinatra. So my get request for albums will be matched by r.get albums, and a post request for artists will be matched by r.post artists. But a post request for artists one will not be matched by either. It won't be matched by r.get because it is not a get request, and it won't be matched by r.post because the request path will not be completely consumed by the matchers. So when you are building a routing tree, if you only want to handle a get request for albums list and not other request methods, instead of calling r.is list and r.get inside of that, you can just use r.get list, which is a more succinct way of expressing the same routing tree. So now that we've covered the four basic routing methods, let's talk about the arguments you give to these methods, which are called matchers. So we've already covered one type of matcher, which is the string matcher. And this matches the verbatim string in the first segment of the request path. Strings can contain slashes if you want to match multiple segments in the request path. So this matches albums list, but not albums one. You can use embedded colons in your strings, which will match arbitrary segments in the request path. So this matches both albums one and albums two. Note that when you use an embedded colon in the string, the text that is matched by the colon is yielded to the block. And in Rota, this is the primary way the data from the request path is extracted for use inside the route handling code. Now another way of specifying the previous matcher is to use a separate symbol matcher. And just as with the embedded colon in the string, this yields the matched segment to the block. Yet another way of doing it is using a regular expression. And with a regular expression matcher, any regular expression captures are yielded to the block. So there are other types of matchers that allow for more advanced matching, but in the interest of time, I will not be going over them. I mentioned earlier that one of the main advantages of routing trees is that they have the ability to execute arbitrary code during the routing process. And that may not sound important. But it is the main reason that Rota allows for simpler and drier code compared to most Ruby web frameworks. If you want to make sure that someone is logged in before accessing these routes, you can just put that code that checks for login as the first line in your Rota.route block. And this provides a similar feature to the capabilities of a global before filter in Rails or Sinatra, so it doesn't sound like anything special. Because you can execute code at any point in the routing tree, you can put this check after the routes for logging in. I think this is more elegant than a global before filter that does a login check, which must check that the current path is not the login action or else no one would be able to log in. Now the principle of executing code during routing applies at all points in the routing tree. So if only certain users should have access to View or Update Albums, you can have that check near the top of the R.onAlbums block. And the most common place this is useful is with dealing with separate requests methods for the same request path. So assuming that the get request for Albums 1 will display a form for editing the Album with ID 1 and a post request for Albums 1 will process that form's input, the routes can share code for retrieving the Album, as shown here. Now this is not revolutionary, and you can accomplish pretty much the same thing using before filters in Rails or Sinatra. In both Rails and Sinatra, the before filters are going to be separated from the code being executed, which makes it harder to reason about. And if you use this pattern a lot, you have to specify a separate before filter for every set of get and post routes you have, which is cumbersome, and on Sinatra it negatively affects performance. Now speaking of performance, Rode is one of the best performing Ruby web frameworks. With Ruby's reputation for performance, you may think that's similar to saying Rode is one of the fastest turtles, but it is a much faster turtle than Rails and Sinatra. So for a simple hello world app with a single route, Rode is about two and a half times faster than Sinatra. And the reason for this is Rode has lower overhead than Sinatra. Now a hello world benchmark doesn't really tell you how well Rode will perform in real world applications. So my production applications were always faster using Rode than Rails or Sinatra. How much faster depends on the specific action, with simpler actions performing significantly faster and more complex actions performing about the same as most of the time for those who spent inside the action and not during routing. One pleasant surprise was that my integration tests sped up significantly. The exact same rack test based integration tests run 50% faster with Rode than Sinatra and twice as fast after converting from Rails to Rode. In terms of memory usage, Rode uses about 10 megabytes of memory less than Sinatra in terms of just requiring library, but in my real world apps I've only noticed a one or two megabyte decrease in the amount of memory used. When compared to Rails it's a different story. On the largest app I converted from Rails to Rode I saw memory decrease from 150 megabytes to 80 megabytes per unicorn worker process and the second largest I saw memory decrease from 100 megabytes to 60 megabytes per unicorn worker process. My largest app is probably only about the size of your average Rails app with about 200 routes. So this really does not tell you if Rode's approach will scale to large web applications. Since I thought this would be useful information to know if I was going to advocate that other people use Rode I decided to see how well Rode would scale to an application with a large number of routes. So you may be familiar with the C10K problem which was stated by Dan Kegel in 2001 and said, you know, it was time that web servers should be able to handle 10,000 clients simultaneously. So I'm gonna state the R10K problem which is that web frameworks should be able to handle 10,000 routes efficiently. So I wrote a code generator that generates web applications with 10, 100, 1,000 and 10,000 routes for Rode, Rails and Sinatra and I benchmarked them. So for 10 routes, R10K generates routes from A to J using a single segment per request path. For 100 routes, R10K generates routes from A to JJ using two segments per request path. So this extends to 1,000 routes with three segments per request path and 10,000 routes with four segments per request path. So let's first look at a comparison of Rode, Rails and Sinatra at 10, 100 and 1,000 routes. So here are the runtime results for 20,000 requests. Know that these are using the RAC API directly so this does not include the web server overhead. As you can see from the Rode and Rails lines, there is not a significant performance decrease for either as the number of routes increases. And this is because Rode uses a routing tree while Rails uses finite automata for routing requests. Since Sinatra just iterates over an array of possible routes, performance decreases linearly as the number of routes increases. So at 1,000 routes, Sinatra is almost as slow as Rails. Now regardless of the number of routes, Rode is much faster than either Rails or Sinatra. You can probably tell where this is going, but let's look at the results with 10,000 routes. So by the time you get to 10,000 routes, Sinatra's performance is much worse than Rails. And because of the scale of the graph, you can't tell how long Rode is taking 10,000 routes, but I can't tell you it is less than five seconds even with 10,000 routes. Note that these numbers do not include startup time. Adding startup time does not change the picture in general except when using 10,000 routes in Rails where it dramatically increases the time with Rails taking about as long to startup as it takes to serve 20,000 requests. And when trying to use 10,000 routes in Rails, almost all of the startup time is spent inside routes.draw. And if I had to guess, this is due to building the finite automata for the router. Now part of performance is also the amount of memory used. As mentioned earlier, and as you can see here, Rode uses less memory than Sinatra and significantly less memory than Rails regardless of the number of routes. The trend gets even more dramatic when you go from 1,000 routes to 10,000 routes. So with 10,000 routes, Rode uses less than half of the memory of Sinatra and about a fifth of the memory of Rails. Rode uses less memory with 10,000 routes than Rails uses with 10 routes. Now because benchmarks are worthless unless the source is available for reproduction and criticism, you can find the source code for these benchmarks in my R10K GitHub repository and I encourage anyone to double check my work to make sure I'm not doing anything stupid or unfair to Rails or Sinatra. I've gone over what I think are some design and performance advantages of using Rode. However, the benefits that Rode offers come at a cost and that cost is the loss of route introspection. Because all routing in Rode is done at the instance level, you cannot introspect your routes like you can in Rails or Sinatra. Now in most cases, this doesn't matter, but there are applications that rely on introspection of the routes and those would need to be handled differently with Rode. So now that I've talked about the advantages and disadvantages of Rode, I'm gonna talk a little bit about the history of routing tree web frameworks in Ruby. So the first routing tree web framework for Ruby was RUM, which was written by Christian Newkirchen, the author of RAC in January 2009. Now RUM was never released as a gem, it was basically just a proof of concept, showing how you could use a routing tree to route requests. CUBA was developed by Michael Martins, starting in April 2010, and it started off as a simple wrapper around RUM with support for Hamel templates and it's now expanded to support any template library supported by tilt. So CUBA was the first routing tree web framework for Ruby that was released as a gem and it has enjoyed some modest success with about 40,000 downloads. Now as I mentioned at the start of this presentation, Rode was forked from CUBA because while I liked the idea of using a routing tree, there were various aspects of CUBA's design and implementation that I did not like. I really think forking someone else's software should really be a last resort, as it's better to collaborate and work together to achieve a common goal. Some of the things I did not like about CUBA were fundamental to CUBA's design or philosophy, so it really would not have been possible to use CUBA and still accomplish the goals that I was looking to accomplish with Rode. And in the cases where the goals of the fork are different than the goals of the original software and you can't accomplish the goals of the fork without compromising the goals of the original software, I think forking is appropriate. So when I first started using CUBA in version 3.1.1, status code handling violated the principle of least surprise. So if you had this routing tree in CUBA, a request for albums with no ID would return an empty 200 response instead of an empty 404 response, because the status code was set to 200 as soon as the on albums method matched. Now this was a well-known issue with CUBA, with a whole section in the read me about how to work around the problem, and a pull request to fix this issue had been opening CUBA's issue tracker for over six months. Now this was eventually fixed in CUBA about a week after Rode's initial release using basically the same approach that Rode uses. So the second significant issue I had with CUBA was that it did not have built-in support for terminal routes. So CUBA has no built-in equivalent to Rode's R.is method, which makes sure that there is a terminal match on the request path. When you use CUBA's on method, it only makes sure that the prefix matches. So this code will match albums, but also albums one and albums should not exist. CUBA's recommendation, if you want a terminal match, is to use backslash z at the end of a regular expression. Let's just say I did not think this was very friendly to the user. Another thing I didn't like about CUBA was that it required explicit writing of response bodies instead of using the route block return value as the response body, which is how Snatcher operates. So every time you want to write a response body in CUBA, you have to call the res.write method explicitly. I think Snatcher's approach is simpler, and I don't think there is a net benefit by making the response body writing explicit. Now this is one of the philosophical differences between Rota and CUBA. Now I was originally thinking, I could just work around this issue by using a CUBA plugin that made the response body writing implicit. But I found that CUBA's plugin system was unable to override methods defined by CUBA. So I wanted to write a plugin that just overrode on and called super, and if the on block returned a string, write it to the response body before returning from the block. Now unfortunately in CUBA this does not work, at least not if you add the plugin directly to the CUBA class. And after speaking with the author, I found out this was by design. So I was used to SQL's plugin system where you can override any method and call super to get the default behavior. So it was at this point that I decided to fork and make sure that the fork used a more extensible plugin system that is based on SQL's plugin system. So after I decided to fork, I wanted to fix an issue that I've had with every Ruby web framework that I've used, which is that instance variables, methods, and constants pollute the namespace, which can cause problems for the user of the framework. So one of the things you can see in this picture is that rota trees naturally resist the pollution that is corrupting the rest of the land. Can anyone see the problem with this Sinatra code? The problem is that response instance variable is already used by Sinatra internally. So this clobbers the response variable and completely breaks Sinatra. Now it just so happens that one of the apps I work on deals with the domain object called response. So using response as the class name and response as the instance variable name was the most natural way to express this code. And because I wanted it to work easily in Sinatra, I had to rename the instance variable to agency response. I didn't like this because a name like agency response indicates to me that there are other types of responses that the system deals with, and that's just not true in this case. So in rota, all instance variables that are used internally in the scope of the rota.route block are prefixed with an underscore. So they will not conflict with the instance variables that the user wants to use. Name space pollution is not just an issue with instance variables, both constants as well. Now so can anyone see the problem with this Cuba code? So the problem is that even though you are requiring a top level response class in the first line, the reference to the response class inside the Cuba app references Cuba response, which is a subclass of rack response, not the top level response class that you required. So to avoid pollution of the constant name space, rota prefixes all constants in the rota name space with rota. So the internal classes are named rota, rota request, rota, rota response, and so on. This makes it unlikely that rota's constants will conflict with your application's constants. Finally, rota of woods, including the method name space. With Cuba, all of the routing methods, such as on get and root, are instance methods in the scope of the route block. So you cannot define view methods that conflict with them. I don't wanna imply this as a problem specific to Cuba since Cuba is actually much better than most other Ruby web frameworks in this regard, with only 23 additional methods over what is defined in object. With Sinatra, there are 68 additional methods. With rota, there are only six additional methods. And the reason that rota is able to only have six additional methods is by moving the routing methods to the request class, which is why the rota.route block yields the request instance to the block, and routing methods are methods called on this request instance. Incidentally, if you look at Cuba's routing methods, they all have feature envy, since pretty much all they do is call methods on the request instance. So even if this was not being done to avoid pollution, it's still a good idea from an object-oriented design perspective. So that brings us to the final section of this talk, where I'm gonna talk about rota's plugins. Rota's philosophy is to have a very small core with only the essentials and have all non-essential features added via plugins. That way you get to choose to load only the features that you need. So loading plugins in rota is similar to loading plugins in SQL and Cuba, just by calling the rota.plugin method. And like SQL, but unlike Cuba, rota ships with a set of official plugins, but external plugins can be loaded via the same method, so whether the plugin is external or not is transparent to the user. So in this case, this loads the render plugin, which supports rendering templates using the tilt library. So usage is similar to Sinatra, except that instead of having separate methods per template engine, it just has a single view method. Now in my experience with Sinatra, I rarely use more than one template engine in the same application. So with rota's render plugin, you set the default template engine when loading the plugin, and if you want to use a non-default template engine, you specify it as an option to override the default when you call view. So similar to Sinatra, the view method just returns a string. So if you call view as the last expression in your route block, the result of the view is used as the response body. A special note in the render plugin is the escape option, which switches the default template engine to an E-Ruby subclass that automatically escapes output, which prevents common cross-site scripting vulnerabilities. So when using the escape option, the usual percent equal tag will escape the output, and to get unescaped output, use the percent double equal tag. And the use of percent equal for escaping and percent double equal for not escaping provides most of the security benefits of the default escaping that Rails uses without the complexity of active support safe buffer. Sinatra users may think there's nothing special about this, since Sinatra supports the escape HTML ERB option, which will do roughly the same thing. This is what Sinatra recommends in its FAQ when asked about how to automatically escape HTML. What they do not tell you is that this is at least partially broken, in that it does not support post-fixed conditionals inside percent equal tags. And this is odd because post-fixed conditionals inside percent equal tags are supported when not using the escape HTML option. And the reason that percent equal doesn't work with post-fixed conditionals is because it generates this Ruby code, just using the percent equal tag content as the argument to escape XML. Unfortunately, this is not valid Ruby syntax as you cannot use a post-fixed conditional expression directly as a method argument. In order to make it valid Ruby syntax, you need to wrap the expression in parentheses, which is what Rode does. So Rode ships with another security-related plugin, CSRF, which adds protection against cross-site request forgery. So this loads rack CSRF as one of the middleware for the application. And it also adds some view helper methods, which allow you to easily create the necessary CSRF token tags in your views. So if you are doing server-side rendering using the render plugin and you want to improve performance, in addition to thinking about application performance, you also need to think about rendering performance on the client. And one of the best ways to improve rendering performance on the client is to flush the head tag for the response while still preparing the remainder of the response. And the chunk plugin lets you do that using transfer encoding chunked. So with the chunk plugin, you just call view or call chunked instead of view. And it will stream the response to the client in chunks. And by default, it will flush the top part of the layout before rendering the content template. So you can pass a block to the chunk method, which will be yielded to after the top part of the layout has been flushed to the client, but before rendering the content template. So this allows you to execute code necessary to render the content while the client is making requests to load the assets necessary to display the page. And this can significantly decrease the total time that the client takes to fully render the page. Additionally, at any point inside the content or layout templates, you can use flush to send the partially rendered response to the client. And this is mostly useful when loading large pages where you want the client to see visible content before all of the content is finished rendering. Now the chunk plugin also has a chunk by default option, which switches view to use chunk encoding if the client supports it, allowing you to speed up rendering performance for all the reviews. So one of the issues with Rota's approach of having a single routing block that all requests are yielded to is that you cannot split a block across multiple files. For large sites, it's not really practical to have all your routes in a single file, so Rota comes with a multi-route plugin. And with the multi-route plugin, in your main Rota application file, let's say you have a large routing sub-tree for routes under albums, which you want to move to a separate file. You replace the sub-tree with a call to r.route with the name of the route you want to use. And in most cases, this will be the same as the matched part of the request path. You take the routing sub-tree you removed from the main source file and you place it in a separate file. My convention, these are called routing files and they're stored in a routes sub-directory and you just require all files from the route sub-directory in your main application file. So inside these routing files you call Rota.route but you pass it the name for the route, which is the same as the name that you used inside the R.route call in the main Rota application file. So for large apps, it's common to move all of this routing code to routing files. So assuming that you named all of the routes with the request path prefix, you can dispatch to all of the named routes with a single R.route call. And in addition to drawing up your code, this is also faster as it matches against all route prefixes simultaneously using a single regular expression. Now if you are writing an app that uses the multi-route plugin, it's probably large enough that you do not want to use a single directory for all of your views. While you could just specify the sub-directory each time you wanted to render a review, that's not very dry. So Rota ships with a view sub-dears plugin that allows for setting a view sub-directory to use for a given branch. So with the view sub-dears plugin, you call set view sub-dear anywhere in your routing code and when you call view, it will automatically prefix the template name with that sub-directory. Now that's more dry, but some people only think that's not dry enough. So for the dryest code, you can use the symbol views plugin. With the symbol views plugin, you just have your route block return a symbol which is interpreted as a view template name and it will render the view and use the result as the response body. Now some people only consider this too dry, but the great thing about Rota is that this behavior is loaded via a plugin. So if you don't like it, you just don't have to load that plugin. Similar to the symbol views plugin, Rota ships with a JSON plugin. Now the JSON plugin makes it easy to create JSON API sites. You just have your route block return either an array or a hash and Rota will automatically convert it to JSON and use the JSON as response body. Now a common issue with most Ruby web frameworks is that by default they tend to be too liberal in terms of what they match. So the symbol matchers plugin exists to allow for more advanced matching. So take this simple route which matches albums followed by a segment for the albums ID and while this works in general, it is too liberal. It's kind of obvious it's too liberal since you are converting the matched album ID to an integer. So what you really want to do is only match segments consisting solely of decimal digits. Now you could switch to using a regular expression as your matcher, but then you have to specify the grouping manually and it takes more cognitive overhead to use a regular expression. So with the symbol matchers plugin, Rota automatically treats some symbols specially using specific regular expressions for them. One of these symbols is D which matches only decimal digits. So let's make sure that only albums followed by a segment with only decimal digits will be matched. Now the symbol matchers plugin also makes it easy to define your own symbol matchers. So let's say you have lots of routes in your application that include a user's username, but you don't allow arbitrary characters in your username. So you have a strict requirement of only lowercase ASCII letters and user names must be between six and 20 characters.  And then everywhere in your app where you use that symbol, it will use that specific regular expression instead of the default of matching any sequence of characters. And as shown in the previous examples, this works both for symbols and for embedded colons and strings. So Rota ships with a flash plugin that adds support for flash handling similar to Rails flash handling or the flash handling you get from Snatcher flash. If you want to handle request methods other than get and post, Rota ships with an all verbs plugin that adds routing methods for all of the HTTP request methods. Rota ships with a not found plugin for Snatcher like support of specifying a block to call when no route matches. Rota ships with an air handler plugin for Snatcher like support of specifying a block to call when an air is raised while handling a request. Rota ships with a pass plugin for Snatcher like pass method. And the pass method jumps out of the current routing block as if it did not match allowing it to continue the routing process. Rota ships with an indifferent params plugin for support for a Snatcher like params hash that works both with symbols and strings. Now you could call this stealing from Snatcher if you did not know that I am the one that introduced indifferent params to Snatcher in the first place. To be fair to me, Snatcher originally symbolized all params which opened it up to denial of service attacks. So introducing indifferent access was done to keep it backwards compatibility not because different params are a good idea in general. If you want some actual stealing from Snatcher Rota ships with a streaming plugin with an implementation that is mostly borrowed from Snatcher though it does have some significant improvements that make it easier to use safely. And likewise, Rota ships with a caching plugin with an implementation that is mostly borrowed from Snatcher adding support for cache control, last modified, and E tags. Rota also ships with an assets plugin that allows for easily compiling and rendering your CSS and JavaScript files on fly in development and compiling them into a single compressed file in production for maximum performance. And Rota ships with a middleware plugin that turns your Rota app into rack middleware. So if you have a Rails or Snatcher application that you want to speed up but you do not have time to fully replace it with Rota, you can use the middleware plugin to turn the Rota app into middleware and use that middleware in your Rails or Snatcher application. Any route that the Rota app does not handle will be forwarded to your Rails or Snatcher applications which allows you to gradually upgrade. So Rota ships with over 10 additional plugins but as I'm getting low on time, I can't cover all of them. So let me review what I think are the main advantages of using Rota compared to most other Ruby web frameworks. First, I think for simple web applications, Rota is about as simple to use as Snatcher and much simpler than Rails. And Rota code base itself is significantly smaller and simpler than either Rails or Snatcher. As your application gets more complex, I think Rota does a better job than Snatcher of managing that complexity while always remaining a lot less complex than Rails. Rota performs significantly better than either Snatcher or Rails and scales much better than either Snatcher or Rails for truly large sites. Rota does not pollute your namespaces. So you do not need to worry about Rota conflicting with your application code. And finally, because of the SQL-based plugin system it uses, Rota is very extensible. So if you need functionality that is not included in one of the plugins that ship with Rota, it's easy to add yourself. So that's why I think you should consider Rota for your Ruby web application development. And that concludes this presentation. I want to thank you all for attending and listening to me present Rota. If you have any questions about Rota, I'll be happy to answer them now.