186 RR The 4 Rules of Simple Design with Corey Haines

00:00 4047
Download MP3

Special Offer! Get 33% offUnderstanding the Four Rules of Simple Design! 

02:20 - Check out JS Remote Conf

  • Text JSREMOTECONF to 38470

02:31 - Corey Haines Introduction

04:25 - The 4 Rules

06:51 - The Origin of the Rules

14:20 - “Generative”

18:12 - How Do the Rules Make Us Happy?

24:51 - Thinking in Processes

28:57 - Code Duplication

47:32 - Grouping Methods and Classes

  • “Separation of Responsibility”

52:49 - Testing

See Also


AVDI:  So it’s like, “Are you there? Are you there? Are you there? Oh, hello robot.” JESSICA:  [Laughs] CHUCK:  Yeah. And then when you talk it’s like [growls]. [Laughter] COREY:  You might say it really ups your game. CHUCK:  Yeah.[This episode is sponsored by Hired.com. Every week on Hired, they run an auction where over a thousand tech companies in San Francisco, New York, and L.A. bid on Ruby developers, providing them with salary and equity upfront. The average Ruby developer gets an average of 5 to 15 introductory offers and an average salary offer of $130,000 a year. Users can either accept an offer and go right into interviewing with the company or deny them without any continuing obligations. It’s totally free for users. And when you’re hired, they also give you a $2,000 signing bonus as a thank you for using them. But if you use the Ruby Rogues link, you’ll get a $4,000 bonus instead. Finally, if you’re not looking for a job and know someone who is, you can refer them to Hired and get a $1,337 bonus if they accept a job. Go sign up at Hired.com/RubyRogues.]**[This episode is sponsored by Codeship.com. Don’t you wish you could simply deploy your code every time your tests pass? Wouldn’t it be nice if it were tied into a nice continuous integration system? That’s Codeship. They run your code. If all your tests pass, they deploy your code automatically. For fuss-free continuous delivery, check them out at Codeship.com, continuous delivery made simple.]**[This episode is sponsored by Rackspace. Are you looking for a place to host your latest creation? Want terrific support, high performance all backed by the largest open source cloud? What if you could try it for free? Try out Rackspace at RubyRogues.com/Rackspace and get a $300 credit over six months. That’s $50 per month at RubyRogues.com/Rackspace.]**[Snap is a hosted CI and continuous delivery that is simple and intuitive. Snap’s deployment pipelines deliver fast feedback and can push healthy builds to multiple environments automatically or on demand. Snap integrates deeply with GitHub and has great support for different languages, data stores, and testing frameworks. Snap deploys your application to cloud services like Heroku, Digital Ocean, AWS, and many more. Try Snap for free. Sign up at SnapCI.com/RubyRogues.] **CHUCK:  Hey everybody and welcome to episode 186 of the Ruby Rogues Podcast. This week on our panel, we have Avdi Grimm. AVDI:  Hello from Pennsylvania. CHUCK:  Jessica Kerr. JESSICA: Good morning. CHUCK:  I’m Charles Max Wood from DevChat.TV. Quick reminder: go check out JSRemoteConf.com if you’re looking to level up on JavaScript. We also have a special guest this week and that is Corey Haines. COREY:  Heidi-ho. CHUCK:  Do you want to introduce yourself real quick, Corey? COREY:  I’m Corey Haines. I’m a developer. I live in Chicago. I’m just a guy, you know? [Chuckles] CHUCK:  You just wrote a book, didn’t you? COREY:  I did just write a book. I just wrote a book on the four rules of simple design, with examples and the most nitpicky of nitpicky examples I think. CHUCK:  Yeah. And the last three years, you’ve also flown from what, Australia to Hawaii or something once a year for the Global Day of Coderetreat? COREY:  Yeah, so the first couple, the first two Global Day of Coderetreats where we do Coderetreats in, I think this year there were 170-some cities all on the same day. CHUCK:  Wow. COREY:  And the first two years I would do the first event in Sydney and then take a 6pm flight, land at 6:45am the same day in Honolulu and do the last event of the day. And everybody thinks that I must have been really, really tired. But I actually sleep really well on a plane so it felt like two days for me. [Chuckles] But it was fun. It was just a fun way to raise awareness about the event and everything. I haven’t done it the past two years. I’ve relinquished influence and thought around the whole Coderetreat thing to a couple of the more up and coming leaders of the community. And so, they’ve been running and growing the event the past two years. I’ve been on and off involved for the last, I guess it’s coming on six years now that we’ve been doing Coderetreats. JESSICA:  I love that as much as developers abhor time zones you found a use for them. COREY:  [Chuckles] I did find a use for them. CHUCK:  [Laughs] COREY:  Traveling back in time. CHUCK:  Very cool. Well, I’ve been a fan for a while and I’m really excited to talk about this topic in particular with you. So, the four rules of simple design. I think I’ve probably seen a few versions of this. They’re mostly the same ideas but they’re stated differently. So, what are they for you? COREY:  So, the first one is generally accepted as tests pass. This is usually I tell people that if you can’t prove that your system works then it doesn’t really matter whether your design is simple or complex or anything like that. Number two, I usually list as expresses intent, which is simplified as good names. A lot of it is your system should, you should be able to look at the code and it tells you what it does. And when you read the code, it doesn’t surprise you. So, method names actually describe the activity that the method does. Variable names describe what they represent. Third is no duplication. This is the really subtle one of the four, I think. It’s also the DRY principle. And most of the time when people start thinking about duplication they start thinking about code duplication like, “oh, I’ve got these two for loops at the same place. I got to extract them into a method. But it’s really about knowledge centers. The DRY principle states that every piece of knowledge in your system should have one representation. And so, as you get more and more understanding of duplication you start abstracting away from the code and more into what this represents in the domain, and making sure that those are isolated in one place. And then the fourth one is small. Basically, don’t have pieces you don’t need. The two and three, the second and the third one are usually you’ll see people flip them. Some people will say no duplication is number two. Some people will say expresses intent is number two. But it’s really the fact that they cycle. So, as you clean up names you start to notice duplication. As you eliminate duplication you start to notice naming issues, things like that. Joe Rainsberger wrote a great blogpost where he talks about this and how people like to argue about the ordering of the four rules. But it’s really the two and three cycle like crazy. CHUCK:  So, I want to take them in order but I don’t want to get into how to test as much as just all the tests pass. AVDI:  Before we dig into that, did we already talk about what the origin of the rules was? CHUCK:  No. COREY:  We haven’t yet. [Chuckles] AVDI:  Can we just go over that real quick? Because I’m a little fuzzy on it. COREY:  Yeah, so Kent Beck codified the rules back in the late 90s. And he actually wrote… he was kind enough to write one of the prefaces for the book where he talks about the origin of them. And it really comes down to he had been seeing a lot of cycling where you have a lot of speculation about your design. And then you implement it and there are problems with it. And that means that you have to speculate more about it and you have to do a lot more upfront design. And he has a tendency or had a tendency to really just cut things down into the simplest fashion and also for bringing ideas forward in the process and merging things together. And so, he put down these. He said, “What if you don’t worry about any future thing? You just focus on making sure that your system is, the code represents what it’s actually doing and you start eliminating duplication.” And so, he said that he used to like to lay things down into rules and then abide by those rules. And so, that’s where these four rules came from. So, it was really a way of answering people when they asked him what he meant by simple. AVDI:  Answer’s always Kent Beck, isn’t it? CHUCK:  [Laughs] COREY:  It’s always Kent Beck. It’s always Kent Beck, Ward Cunningham or Jerry Weinberg. It’s one of those [inaudible] JESSICA:  Somebody’s got to be first. COREY:  Yeah. It’s like pretty much everything boils down to, “Oh, that was Ward Cunningham.” JESSICA:  That’s the modern corollary to, “All ideas were written about in the 60s and 70s.” COREY:  Yes. AVDI:  And all songs were written by The Beatles. [Laughter] CHUCK:  Awesome. JESSICA:  Oh wait, does that make Kent Beck and Ward Cunningham, and who was the other person? Does that make them The Beatles of design and programming? [Laughter] COREY:  Jerry Weinberg. Yeah, of course. CHUCK:  Aw, now I need to get smart enough to be the drummer. [Chuckles] COREY:  It’s funny because when I started looking at history and looking at the people who influenced a lot of the thoughts that we have, Ward’s there. Kent’s there, a bunch of other people. And then it seemed like everybody eventually ended up at Jerry Weinberg, which surprised me because I always thought of him more as ‘The Psychology of Computer Programming’ and the consulting books and things like that. But he was really actually just a fantastic developer back in the day and influenced a tremendous amount of the thought that we hold dear. Because we talk about how Kent invented TDD but it’s really more, people have been doing TDD for a very long time before that. I had the opportunity to talk to Jerry Weinberg and he said that yeah, he’s like, “You guys complain about your compile times. But our compile time was: put the cards in a box in California and fly them to New York to run.” JESSICA:  Wow. COREY:  “And then fly the results back to us. So, we basically had to do some form of testing before we ran the code just because it took so long to run the code.” CHUCK:  That’s funny, a compile step that involves burning oil. COREY:  Yes. [Laughs] JESSICA:  Tracing the ideas back from your book to Kent Beck all the way back to Ward Cunningham and then Jerry Weinberg, it reminds me how having an idea isn’t enough. And coming up with a new idea isn’t the part that helps anyone, everyone. Everyone who takes an idea and expands on it and combines it with other ones and talks to people about it is a part of that idea. Your book on rules of simple design brings these ideas to more people and makes them relevant to more people than Kent Beck ever could by himself. COREY:  Yeah. JESSICA:  Given that he’s doing other things as well. COREY:  Yeah. And that’s what I like about our industry, is even though it seems like everything was done back in the 60s and 70s and if you have an idea you can probably find a paper in the 60s and 70s that describes it, it’s the understanding, our understanding of these ideas evolves over time. The more we use it, the more that we apply it to our systems, the more that… our systems nowadays are I think fundamentally different than the systems that were written back then. But the ideas can be applied to them. And so, we evolve it. We explain it better. We’re constantly improving our understanding of it. And it’s a lot like how TDD originally, if you look at it originally being just, “Hey, what if we wrote our tests first?” to very subtle understandings of its influence on the design of our system. The whole idea of duplication, what does that actually mean? And that’s one of the things I tried to do with the book was give concrete examples of what it means to have duplication. What does it mean to name something poorly? And it’s okay to be very nitpicky about these sorts of things and just expand the understanding of it. JESSICA:  Yeah. Just like TDD, just like our programs, just like these rules of simple design, the ideas themselves that we use in programming iterate. COREY:  Yeah, absolutely. And the cool thing too is that as we start to use them more and more, we start to apply them. We start to see other techniques come in. One of the real, the things that I’ve spent a lot of time over probably the past, I think the first time I started really thinking about it was about eight years ago, was the idea of generative principles. JESSICA:  Ooh. COREY:  So, when I was first introduced to the SOLID principles and a lot of that, fairly quickly as I was working with them I started realizing that you could… well, realizing, I started believing [chuckles] that you could generate the OLID principles from single responsibility. And you could generate the others from open/close. If you really sit down and apply it in certain situations you’ll get dependency inversion just by applying single responsibility. And I ran with this for a little while with some friends. And I like the idea of what I’ve come to after spending the past, really probably about five years intensely thinking about the four rules of simple design, that they’re generative principles for… I have started looking at the SOLID principles along the same lines as I look at design patterns, which are really great ways to communicate things almost after the fact. So, I can look at my system and say, “Hey, here’s an instance. This part of the system is expandable and extensible because it abides by the open/close principle, not because I implemented it to abide by the open/close principle but because I very aggressively applied the four rules. And because of that I ended up with a system that could be described with the open/close principle. JESSICA:  What do you mean by generative? COREY:  Well, it’s that idea that if you take the four rules and you really apply them, then you will get the other principles. And so, the SOLID principles are not foundational. They come from the four rules of simple design. CHUCK:  Are the four rules foundational or do they derive from something else? COREY:  Well, clearly they are the foundational ones. JESSICA:  [Laughs] Because you wrote a book about them. COREY:  Yes, clearly. [Laughs] Just like atoms are indivisible. JESSICA:  [Laughs] COREY:  But I don’t know. I doubt it. Why would they be? It seems odd that they would be. There’s probably a more fundamental concept about it. But I haven’t really gone that far. I’ll leave that to the next generation maybe. [Laughs] JESSICA:  It’s one thing to… CHUCK:  You got to leave them something. COREY:  Yeah. JESSICA:  [Chuckles] Oh, I don’t think they’ll have any trouble expanding on all of this. COREY:  Yeah. JESSICA:  Software is so fascinating. COREY:  Yeah. JESSICA:  But yeah, there’s a difference between reducing the number of axioms in the system which is what you’re doing when you derive all the SOLID principles from the S. And there’s a difference between axioms that you can use to prove things and heuristics that you can use to produce things. The rules of simple design strike me as heuristics that are productive or in your word generative. They generate the right kind of code. COREY:  Yeah. I think that’s a good way to put it, is it is different from all you have to abide by is single responsibility. JESSICA:  Yeah, this is Ruby, not Idris. We’re not trying to prove our code correct. We just want it to be good. COREY:  Yeah. Yeah, we just want it to be good and maintainable. That’s really what it boils down to, because it does… we’re building, most of the time we’re building software that we’re hoping is going to last long enough to be maintained and to need maintenance. And all of these principles are about that one core idea of, “I’m going to have to come back to this code later.” And I would prefer if I didn’t have to curse past self. And if past self actually would do something nice with the code so that when I come as future self, I can be happy and go, “Oh yeah, I can make this update.” I recently had to make an update to a system that I wrote. And it was a hack weekend system that Sarah and I wrote. And it was, I came back to it after a couple of years. And it was like, “Oh wow. Okay.” It’s very small, simple, very small simple system. But it was nice because it was fairly easy to make the update that I needed to do, because I had been very aggressive about it. JESSICA:  Mm. It’s MINASWAN, right? Ruby may be optimized for developer happiness, but is your Ruby code optimized for future developer happiness? COREY:  [Laughs] That’s a good way to… that should be the second part. CHUCK:  Okay, don’t look at mine anymore. [Laughter] COREY:  Yeah. But it really fundamentally is that thing though, is you want to write code that you’re going to come back to and be happy and not get into that crushing, “I’m working for a couple of years on something and it’s awful.” And I do spend time with people pairing on their systems. And so often I hear, “Oh, you know this system’s seven years old. It’s horrible and we’re trying to clean it up.” And it takes time to get horrible. It takes time to clean it up. But if you abide by some small little principles, then it’s going to be much less horrible when you come back to it. And if you can be rigorous about it, then there’s a good chance that it can be much less horrible when you come back to it. CHUCK:  So, can I nudge us a little bit into these four principles? How do these four things help us with that? How do they get us to the point where our code is happy, pleasant? I don’t know what the right word is. COREY:  Yeah. Well, let me give you an example of the names and then give you an example of the duplication that I’ve personally run into. One is the names. A couple of years ago, I had to go and I was using Cucumber for some system I was working on. And I wanted to add the ability to do something slightly different with the data tables that they support. And it’s open source, so you always put your open source hat on and download the code and hope that you’re actually going to be able to spelunk through it and find things. CHUCK:  Well, and if you’re like most developers you could have written it better in the first place anyway. COREY:  Well, clearly. CHUCK:  [Chuckles] COREY:  But I went in looking for it. And at the time, this was probably 2010, 2009 timeframe, I haven’t looked at the code lately but I don’t think it’s changed that much. But the names they used were so clear that I went, it took me about five minutes to figure out exactly where I needed to make the changes to Cucumber to support this in a fairly large, Cucumber’s a fairly large, complex environment. But the idea of names is coming back and going, “Where in my code do I need to make this change?” And the example that I give to people a lot is, have you ever run into a method called process_transaction? And then when you look inside it, it doesn’t process anything and it turns out it has nothing to do with the transaction? CHUCK:  [Laughs] JESSICA:  Totally been there. COREY:  Yeah, I’ve been there. And then I ask myself, “Why did I write this?” or “Why did I let this get this way?” Most of the time, we don’t write that sort of method. We refactor our way to that method and don’t update the names. But being able to come back to a system, read it, know that the method called process_transaction does process transactions makes it a lot easy to maintain. The no duplication one, let’s see. When was it? 2010 was when we built MercuryApp. And we had put in a payment system and you could sign up your group to have different levels with different numbers of members and things like that. And there’s a whole authentication, authorization system in there. And about a year after, maybe a year and a half after we’ve been trying to get MercuryApp up as a business, we decided that we were just going to leave the site up. We were going to not make it a business anymore. And so, I needed to take out all of the payment processing stuff. Or not really the payment processing stuff as much as I needed to take out all of the authorization code. It doesn’t matter if you are a premium member or super-group member or something. Everybody gets access to everything. And I went in and it turned out that the knowledge about whether or not someone could do something was entirely encapsulated in one place. CHUCK:  Oh, that’s convenient. COREY:  And it actually returned. And there was an object that, or there was a method that the rest of the code would call and say, “Hey, here’s a user. Can you give me their authorization object?” And then I’ll ask the authorization object for different things. So, there was this idea of an authorization object that had all of the questions on it that you could ask. Can it add a member to the group? Can it create a new group? Things like that. And so, I made a new authorization object that answered yes to every single question and simply returned that one. So, the taking out any sort of levels or questions about authorization, it just all went away and rippled through the system, just by returning this one object from this one method. And it really struck me at that point. I was incredibly anal about keeping the knowledge of whether or not someone, a user could do something or not, in this one place. And whenever another part of the system needed to know that information, it always asked here. There was no getting around it. And because I isolated that knowledge in that one place, when I came back, and this was coming back after probably about six or seven months of not even looking at the codebase, I was able to find this place, write the new object, return it from the method, and the system just completely started working where everybody had access to everything. It was probably one of my more proud moments of coding. [Laughs] I was like, “It worked! It worked, paying attention to this.” JESSICA:  You could say to yourself I’m so smart I predicted the future. I knew this was going to change and made it easy. But the real question is, are other changes easy as well? Did this fall out of some sort of magical foresight that you had or was it just a side-effect of following the rules that you follow everywhere? COREY:  I think it was a side-effect. We were trying to make this a business. So [chuckles] I was not intending to ever return a dummy object that let everybody have access to everything. JESSICA:  Awesome. COREY:  And the codebase for MercuryApp, we actually applied a lot of these principles very, very rigorously. And it’s still one of the nicer codebases that I’ve put together. But it was one of those moments where you come back and you don’t expect that you’re making this change. But because you followed these principles, this change was fairly easy to do. It doesn’t make every change easy to do. But it certainly makes a large class of them, when you have to change knowledge in your system, if you isolate it. JESSICA:  That’s wonderful. So, instead of spending time on our big design or even just guessing what we think will change in the future, we’re much better off keeping our code small and intent-ful and tested, and what’s a short word for not duplicated? CHUCK:  DRY? COREY:  DRY. CHUCK:  Don’t repeat yourself. COREY:  [Chuckles] JESSICA:  Says the person from Utah. You must… COREY:  [Laughs] JESSICA:  Be more comfortable with that than I am. CHUCK:  Oh, totally. Now I need to come up with an acronym for arid. Anyway. COREY:  [Laughs] CHUCK:  So, it’s really interesting because it sounds like you probably had other objects or other classes that were that authentication object. So, it’s not like you had this massive hash builder or something in there that did the work. It was just that you had one place to go to, to get the information you needed. And so, what strikes me, and this is something that I’ve run into in the past is that I’ve built this… so, early in my programming career I wound up being a team lead and we built a pretty complex system. And everything was tightly coupled to everything else instead of having one place where they could go. And the way we solved it was we built a service-oriented architecture. And looking at this, it seems like this actually would have been a better answer in that you have the one place where the authentication stuff is defined once and only once. And everybody uses the same object or the same API to manage that. And so, you’re thinking about things in processes instead of having everything coupled to everything. COREY:  Yeah. And a lot of it comes down… this is a natural step from those. You’ve got what is generally called the service-oriented architecture and then you have this mid-layer which still is a service-oriented architecture but it’s all in the same process. CHUCK:  Mmhmm. COREY:  And then you’ve got the extreme of a bunch of if statements everywhere. And what we had done was rather than take and put if statements throughout our code that said, “If I’m this I can do this. If I’m this I can do this,” we jumped from what I call procedural polymorphism which is the large set of if statements, to more of a type-based polymorphism which is calling to a service or a method saying, “Give me an object that I can then ask these questions?” CHUCK:  Yeah. COREY:  As long as the interfaces are the same, then I can rely on that. I don’t care what individual type is there. And so, we’ve masked the determination of which authorization behind this method. And I think it had a, there was a hash in there that said if the user has this plan, then this is the type of their authorization object. And then I just new-ed one up and returned it. And so, we took… it was a natural progression. And then of course the next step I think is moving to where you take that, the determination out of the codebase itself and move it to somewhere else. The cool thing about that though is if you use this technique of really relying on type-based polymorphism then you can just return an object that talks to the external service. And the rest of your system still doesn’t care. I don’t know if that makes any sense. [Chuckles] CHUCK:  Yeah, it does make sense. JESSICA:  It does. It does. The important part about who cares about what and the optimal answer is very little cares about only a few things. COREY:  Yeah. And it is this big move from this procedural polymorphism which is about the if statements where you are writing very much a procedure that says, “If this then that, if this then that,” and you get different behaviors based on the values that you’re checking in your if statement versus type-based polymorphism where you’re just saying, “Give me an object and I don’t care what type it is at all. I just care that the interface, the behavioral stuff, I can ask it for it.” JESSICA:  Yeah, or in tell, don’t ask parlance, you can tell the object your intent versus asking it for a bunch of data, and then making your own decision. COREY:  Exactly, yeah. JESSICA:  Chuck mentioned service-oriented architecture. And I had a question for you on that. The number four principle, keep it small. Is that total code size or do we just need to keep each piece, each service small? COREY:  I’m not going to answer as an authority on this, because I actually haven’t done… CHUCK:  [Chuckles] COREY:  A tremendous amount of long-term work on real service-based stuff where you have a lot of individual pieces working together as opposed to more monolithic kind of things. So, I don’t have a really great sense of how to expand this out to that idea. The way I would approach it is to simply look at each of the service as their own object and design it similar to how I would design everything else, is have the services be focused on their responsibility. And not have too many extraneous parts and not have too many extraneous behaviors in there. But I look at service-oriented architectures as a progression towards people wanting to do Erlang. [Laughter] COREY:  Where your processes take the role of objects and you’re sending the messages between processes. And it’s Erlang for the rest of us, kind of thing. CHUCK:  [Chuckles] I love it. [Laughs] JESSICA:  What you said about the objects, you could look at that as keep it small at every level. Keep each object just aware of a few other things, so each object is small. Ideally each service is only aware of a few other services, ideally. COREY:  Mmhmm. Yeah, ideally. [Chuckles] COREY:  Yeah. And the small is one of those interesting ones that if you really keep duplication to a minimum and you name things well, you tend not to have too many extraneous things. I find that when I finally get to applying the small rule, a lot of it is going back and saying, “Oh look, I extracted these two methods. And they are effectively the same thing,” or, “I extracted these methods out but, oh that’s a little over. I don’t need it that far.” JESSICA:  When you say these methods are the same thing, I actually have a vendetta against the DRY principle. But I agree with you about keeping the knowledge in one place. So, when you say these methods are basically the same thing, you don’t mean these methods look the same in the code. COREY:  No, no, no. It’s very much, these methods represent the same knowledge in the system, or they represent the same concept or the same behavior. And I just extracted them out because I didn’t realize that I had already extracted it out somewhere else. CHUCK:  So, can I give a couple of more concrete examples here? So, what we’re talking about is if you have two pieces of code and they’re both a block that makes a variable assignment on an object that’s passed into a parameter on the block, and then reorders a string and then returns, those may be two completely different processes that do completely different things to different objects. And so, that doesn’t capture the same knowledge in the same place. It’s just that the code structure looks the same. COREY:  Yes. CHUCK:  Where if you have process_creditcard on your book sales and you have process_creditcard on your digital video sales, you can probably extract that to one place so that the knowledge on how to process a credit card is in one place. And that’s what we’re talking about. COREY:  Yeah. And then pulling the differences, whether it’s because of, you’re processing a credit card for a book or you’re processing a credit card for a video, the differences aren’t going to be in there. But you can extract out that idea of processing a credit card. JESSICA:  And then when you do extract out the differences, that’s adding clarity and intent because you can see why they’re different. COREY:  Yes. CHUCK:  Right. So, in one case you email the link to the digital video and in the other case you actually ship a physical dead-tree copy of the book. And so, those go off to different pieces that encapsulate that knowledge. And then you have something somewhere either on the book sale or something else that actually determines that one or the other happened. COREY:  Yeah. And one of the nice side-effects that I find when I really extract out the commonality and the knowledge, so in that case you’ve got this little piece of the system that knows how to process credit cards. And then you tell it, here’s what I want you to do after you’ve processed the credit card. And it’s email out the book or provide the link to the video. Well, now if you want to process PayPal, you can put something together that knows how to process PayPal and you can give it the same code for what to do after it processes PayPal, of sending the email. So, you’ve taken the differences out from the processing credit cards. And those differences can be put into other payment processors as well. And I find that I get a lot more reusability when I’ve aggressively isolated the behaviors in there. AVDI:  It’s interesting how ideas get trodden down over time. The way we’re talking about DRY right now is explicitly the way it was defined in the book ‘The Pragmatic Programmer’. It says right there that it’s about keeping knowledge together, specific items of knowledge together and only having a particular piece of knowledge in one place. But I think it’s one of those things that have been cargo-culted to mean: anywhere that you have code that looks alike then those should be brought together. And you can actually do a lot of damage that way. And it’s one of those things where it’s like, the first time you see, you hear the DRY principle it’s like, “Oh, I could write a code analyzer that would find all the code that’s similar. And then I could bring those bits of code together.” JESSICA:  And that gets you to the dessert. AVDI:  Yeah. [Chuckles] AVDI:  Yeah, and the classic example in the Rails world is of this incidental duplication that looks like essential duplication is controllers and the way a lot of people have tried to come up with ways to get some of the boiler plate out of controllers and add stuff on top of controllers so that you only have to only write a little bit for the bits that are different from one action to the next. And it turns out to be incredibly complicated, because a lot of the duplication that you see in this off the shelf, boilerplate controller, is incidental duplication. That stuff changes over time. It’s stuff that looks alike now but it’s not going to look alike six months from now. It just happens to be a sensible default. I think there’s also the way actions are not their own objects I think plays a huge role in this. I think if they were, people wouldn’t go down that bad road as much in the first place. But I’m perpetually, by the way I’m perpetually on the lookout for really good examples of this kind of incidental duplication, duplication that isn’t really. Because I’ve tried to elucidate that idea a couple of times on Ruby Tapas and each time it always feels like it wasn’t the perfect example. COREY:  Mmhmm. David Chelimsky gave a fantastic talk at the 2010 RubyConf called ‘Maintaining Balance While Reducing Duplication’ that really goes into this. AVDI:  So, he was talking, if I recall correctly he was talking about how it’s really tempting to remove all of the duplication from your tests, right? COREY:  Yes, yeah, from your tests. And he has a wonderful example where he removes duplication between two strings. AVDI:  Mmhmm. COREY:  And ends up with ten constants, like a constant for the word ‘don’t’. He takes it to very much the extreme. AVDI:  Yeah. COREY:  But that idea of duplication as code that is the same rather than duplication that is knowledge that’s the same… AVDI:  Right. COREY:  Which the controller example is a good one of that. AVDI:  When I was new to RSpec I did a lot of stuff with deeply nested contexts because I thought, “Oh, well this context, this test fixture only differs by one little thing from last test fixture. So, I’ll make that the super context and make that one little thing variable. And yeah, you can eliminate a lot of duplication that way, but now you have six different places to look for where the actual context of the test that you’re looking at came from. COREY:  Yeah, and that goes into that idea of for me, I use contexts a lot in RSpec. But I use them to capture a higher level concept rather than using them to eliminate incidental duplication. AVDI:  Mm, that’s an interesting delineation. JESSICA:  Indirection should add meaning, not hide it. COREY:  Yes, yeah. So, I’ll find that these two examples are talking about the same behavior. So, I might add a context around those examples. And oftentimes my contexts in RSpec don’t have anything in them. Like, I don’t have a context and at that layer I have a bunch of lets. I just use a context as a way of grouping things. And so, one thing I wanted to mention though about, I’ve talked to a lot of people about duplication and code duplication versus knowledge duplication. And one of the things that I’ve come to realize is that the general thing that we talk about how, “Oh, well people do code duplication and that leads us to a really bad situation.” What I find is that the knowledge duplication idea is a fairly advanced concept. And I’ve spend time with more junior level developers and beginners and people who don’t have a lot of experience with a wide range of code and with them, I tend to say, “You’re at the beginning. Just focus on finding code that looks the same. It’s going to lead you to some rather hairy places but I would rather you isolate code that looks the same and then later find out that that was a bad idea, than confuse you with this advanced concept of knowledge in my system.” JESSICA:  Advanced concept of knowledge, is it that? I see this knowledge, the distinction between duplicate knowledge and duplicate code, is it about how to write a program and get the computer to do something? Or is it about the business domain? COREY:  I think it’s about the business domain. JESSICA:  And that’s the hard part to understand and also, the valuable part to understand. So, if you really get the business domain, does it become much easier to identify duplicated knowledge? COREY:  Yeah, this idea of understanding the domain and mapping the domain into the concepts in your system, if you’re still at the level where you’re struggling to have a system work or struggling to not write methods that are a hundred lines long, then bringing on, layering on this other thing that you also have to be really good at, mapping, it’s not necessarily just understanding the business domain. But it’s mapping it into the concepts in your system, especially because a lot of the concepts that we’re mapping into our system are processes, not specific things. It’s easy to map a, “Oh, I have a tax table.” But it’s harder to map the process of doing taxes. JESSICA:  Maybe that’s where functional programming excels over object-oriented programming. COREY:  There’s definitely something there. What I think it is, is it’s functional programming, when I’ve talked to people in the bit the I’ve done in the past, it tends to emphasize the state change and the transformation rather than this idea that you’re supposed to model things. JESSICA:  The delta, right. It’s about the change rather than the snapshot. COREY:  Yeah. If you go back to core OO principles around message passing and encapsulation, there’s not that big of a difference if you look at it that way and you don’t… if you don’t stay at this level that OO is about this horrible idea that OO is about mapping and designing and modeling the real world and so: find, write your use cases, underline the nouns. Those are your objects. Underline the verbs, those are your methods. If you don’t do that and instead you go to this idea that, take your use case, underline the verbs and those are the things that you are modeling. And then everything else is a way of grouping those verbs in appropriate forms. And there’s not that big of a difference. I think the functional stuff these days is emphasizing it and it’s bringing people out of this concrete entity mentality and saying, “Hey, what if we talk about transformations instead?” But I think OO has really fundamental things in it that do effectively the same thing. JESSICA:  That’s great. So, you can still do a verb-oriented OO style? COREY:  Absolutely. Most of my systems have a large chunk of the classes with verb phrases as names. So, things like ProcessesTransaction or ProcessesPayment, I would have a service object that would be called ProcessesPayment because I like to have my objects define what it is that they’re responsible for rather than what it is that, trying to find the thing that it represents. AVDI:  It’s almost like you’re taking off, you’re cutting off the title of a CRC card and just using the left-hand side as the title. COREY:  Yeah. The core idea came when I started doing TDD and I started looking and building my objects entirely with TDD. I had to have a method. I had to be testing some behavior rather than, “I have an object and its class is this.” I was testing the behaviors of the objects. And then, of course you get frustrated always calling things a manger, such and such manager. And I was in C# at the time. And I really liked the fact that interfaces in C# the idiom was that you started them with a capital I. And it felt weird when you would say ICreditCardManager or something like that. So, I thought what if I changed it and have the interface say I do something. JESSICA:  That’s awesome. So, you took the I that stood for interface and made it the subject, which left the rest of the interface name to be a verb? COREY:  Yes. JESSICA:  Awesome. COREY:  And so, the really neat thing is that the interface, a concrete example is I was building a software distribution system. And it was the frontend management part that could interface with Microsoft’s SMS and Radia and a couple of different software distribution and desktop management systems. And the code that managed which one you talked to and what the protocol was to talk to each one, there was an interface called ITranslateToSoftwareDistributionSystems. And the specific classes, the concrete classes were, TranslatesToSMS, TranslatesToRadia, TranslatesToSecurity. And they all implemented ITranslateToSoftwareDistributionSystems. And it really, the code started reading as this is the activity, this is the process, this is the business process that my system does more so than these are these things and you have to figure out how they interact together. And I really like it. That tends to be the a style, it does lead to oftentimes to what people call anemic objects and anemic data structures where you have some classes that are, if they’re entities, if they’re structural and they have attributes to them, then the methods and the behaviors on those objects tend to only be the things that affect and mutate those attributes. And then my processor and the behavior objects, they tend to be stateless, tend to be immutable from what state they might have, things like that. AVDI:  So, they’re enacting changes upon other things? COREY:  Yes. They tend… AVDI:  Or are they taking in other things and then… JESSICA:  Spitting out other things. AVDI:  Spitting out new modified versions of other things? COREY:  It depends. A lot of the languages that we work in don’t perform very well when you’re constantly creating new objects. And so, the idea of immutability is, you can have… AVDI:  Is that something, I’m sorry. I just want to butt in and say, is that something that you’ve run into in practice? Like, this is bogging down the system because we’re creating too many new objects. COREY:  I have, actually. AVDI:  Okay. JESSICA:  And how recently was it? And was it on the JVM? Because the JVM’s gotten really good at that. COREY:  No, this was on MRI. And I actually had a Rails app, the most recent Rails app I was working on, there was a view layer helper library OO framework thing that one of the developers had written. And there was a fundamental flaw and then it created new objects. It also blew the method cache, but we’ll ignore that. But it created a ton of new objects for every request. And we were seeing GC hits, two or three per request. And when we took this out, I think we cut the response time in half. And so, this wasn’t because of immutability but it was creating, the idea of creating a bunch of objects caused us real performance issues. JESSICA:  It is a consideration. COREY:  Yeah. JESSICA:  You mentioned a minute ago though. You talked about anemic classes, ones that have only data versus ones that have only methods? COREY:  Mmhmm. JESSICA:  And some people would call that a smell, because why shouldn’t they be together? But I call it using the language features that are right for each individual class and leaving the others. COREY:  Yeah. Because I think in terms, or I try to think in terms of the behaviors over the entities, my classes oftentimes group common behaviors together rather than grouping behaviors that are related to the name of the class. And so, what people do call an anemic object where it’s just data, it’s basically a Struct with some methods hanging off of it that do formatting or updating of the data or virtual attributes or things like that, I really think of it more as separation of responsibility. So, there’s a class whose responsibility is acting out a process. And then there’s a class that its responsibility is managing certain data. And this isn’t a design that works everywhere. And it’s not like this is the greatest design ever. But it allows me to separate the things I do from the things that I do it on. And I find that it puts a clarity when I’m building. For me, it really allows me to think about my system in terms of the things that I’m interested in thinking about which is what the system is doing rather than the pieces of it. And one of the things that I tell people too is that I don’t like, when I tell me about the designs I use on the systems I build is that I don’t like to call it a good design or a bad design, because that implies a Aristotelian ideal of what is good design or bad design. But it’s all context of what you’re going to be using the system, how long you’re maintaining it, what are the parts that are going to change, things like that. And so, I like to talk more about better design. If I have two design decisions, there are times when the better design is to do it my way. And then there are times when the better design is to have a concrete entity and all of the behaviors that are related to that entity are hanging off of that class. We sometimes call those god classes. Everybody has that. I was working on a student’s, helping them out with a Rails app, I was helping out at one of the development code schools. And they had a user class that was starting to get big. And they mentioned it. And I was like, “Oh.” I said, “Oh, welcome to every Rails app has that one god class.” And it’s usually user that has a ton of methods off of it, because you don’t know where to put it. This kind of is related to the user, so let me put it there. And sometimes, that’s appropriate. But I tend to want to, my systems tend not to have large god classes because I hang those objects off together off of a behavior class. CHUCK:  That is such a great idea. I just love all of the stuff we’ve talked about here. I’m just loving this. I wish we could talk for another couple of hours. But we can’t. COREY:  Alas. CHUCK:  So, I’m going to push us into the picks. JESSICA:  But what about the other principles? COREY:  [Laughs] CHUCK:  I guess we’ll have to have Corey come back. AVDI:  Sequel. COREY:  Yeah. JESSICA:  We’ve talked a bunch about knowledge and related that to duplication and to the small pieces. I think once you identify those pieces of business knowledge, you also maybe acquire better names? COREY:  Yeah. You acquire better names and then once you get better names you start realizing that you are missing parts of your business knowledge. And then it cycles so much. JESSICA:  And from there maybe you get better tests because you have a better idea of what’s really important to test. COREY:  Yeah. And if you are writing tests while, either before or while you were designing your system, then those tests really are a part of that. So, your tests hopefully are testing the correct things, they’re testing the right things, because you’re bringing in this knowledge. And like you had said earlier, so much of this is about knowing what the domain you’re working in is and how to map that over to your codebase. And having tests that verify that your mapping works is a really, it’s a valuable thing. And honestly, I think it’s essential. I tell people it’s important to remember that this doesn’t say automated tests pass. And it doesn’t say TDD tests pass. It just says tests pass. And if you’re interested in getting very, very fast feedback then you’re going to want to automate these tests. But it’s okay if they’re not. Don’t tell anybody that I told you that. But it’s okay. [Laughter] COREY:  If they’re not. This isn’t going on air, right? We can cut that. [Laughs] CHUCK:  Yeah, no. [Laughter] COREY:  Okay. JESSICA:  Okay, we talked about all the principles. I’m happy now. COREY:  Yay. CHUCK:  Yay. AVDI:  I have one little question about testing, Corey, since I think the programmers that I know, you’ve been banging the drum for fast and isolated tests longer than most. I’m just curious, these days. How do your tests break down in the applications you write? How many fast, isolated testing are you doing? What other kinds of testing are you doing? COREY:  I pretty much run like I’ve always talked. I write most of my business logic in plain Ruby classes and have, when I’m writing a Rails app have Rails then depend on those and call into those. AVDI:  Mmhmm. COREY:  I create dummy versions of my Active Record objects. There are a couple of rules I use to help me out. I tend to only allow calls to arrow methods from inside the Active Record class. AVDI:  Okay. COREY:  So, from a method inside there. So externally, you can call scopes and user-defined methods. AVDI:  Mmhmm. COREY:  Almost always. Now, every rule has its exceptions. But almost always, it’s like that. And that allows me in my tests to spin up a dummy version of the object, of the Active Record class, and stub out the return value. And then when I need to actually test it hitting the database because your scopes are writing SQL for you, why not hit the database? If you’re testing an Active Record scope, you should be hitting the database. AVDI:  I agree. COREY:  However, if you wrap that in a scope or a method then the rest of your system can just get dummy data from that and doesn’t need to hit the database. And so, that’s how I tend to isolate myself from the database. But there’s this Active Record Spec helper that I use that when I do test my queries I don’t load Rails. I only load Active Record and initialize my database. And that helps. That cuts the time dramatically, because loading Rails is slow. And no matter how many pre-loaders you have… AVDI:  [Chuckles] COREY:  That’s just covering up the issue which is, the thing I tend to say is that the difference between test first and test-driven is how you react to the pain of testing. With test first, you bring in pre-loaders and you change your testing system to make the pain go away. With test-driven development you change the design of your system to make the pain go away. And that’s how tests can influence design. And so, I use, I write pure Ruby objects. I don’t load Rails when I don’t have to do it. And it’s painful to test controller actions because you have to load everything up. So, I pull almost, I have a general rule that controller actions can find an object, call a method on it, and render. AVDI:  That’s very similar I think to the architecture that Sandi Metz recommends, I think. COREY:  Absolutely. And I like to say that my book is a preface to Sandi’s book. JESSICA:  Nice. AVDI:  Nice. COREY:  Because her book is, it’s absolutely a must read. AVDI:  Agreed. COREY:  Yeah, which leads us into picks. AVDI:  Woo. JESSICA:  Good job. CHUCK:  That’s my line. COREY:  Oh, sorry. [Laughter] CHUCK:  So Avdi, what are your picks? AVDI:  I’ve got a bunch of new hardware. I’ll just talk about one piece of it today. In my endless quest to improve the comfort and ergonomics of my workspace I have progressed onto mice. I love my TrackPoint dearly on my ThinkPads and I love trackballs. But unfortunately, many of these things aren’t as ergonomic as they could be. So, I started poking around, noticing the positions that my hand didn’t like to be in as my nerve irritation has gotten worse. And I started poking around online and ran across vertical mice and decided to give one a try. And I first tried out the Adesso Vertical Mouse mostly because it was cheap, relatively. It’s $30. And I liked it a lot. I decided I liked the concept of a vertical mouse. It seemed to work out pretty well. But I looked around and the mouse that everyone compares it to is by a company called Evoluent which is the worst company name ever. I have no idea how it’s supposed to be pronounced. But they make a vertical mouse which has a nicer shape. It’s got a bit more heft to it, a nicer shape. It’s got a lip at the bottom so that the bottom of your hand is resting on the mouse instead of sliding around on the table. And it’s more of a true straight vertical. And it’s got some other nice things about it, too. So, I’ve been using that lately. And it is definitely a more comfortable position to have my hand in, to have it vertical rather than horizontal on the mouse. So, that’s been improving my comfort level a lot. You will drop a fair amount for this one. It’s $90 I think. But I think if you’re got some hand pain, it’s probably worth it. I will say, don’t expect it to be as precise a mousing experience as you’re used to. I’ve been using it for a while and it’s still a little bit dodgy precision-wise. And a lot of people say the same thing. It’s just not the same as having your fingers flat down on a table. You’re controlling it with the side of your hand, in a sense. But it’s good enough for most things. And boy is it more comfortable. COREY:  Do you think it’s going to get better as your hand-eye coordination adjusts to the different motion on your hand? AVDI:  I hope so. I think so. At the same time, I’ve also seen people online in reviews and stuff say that the coordination is never quite as good. COREY:  Okay. AVDI:  So, I suspect that if I start to do more PC gaming, I’ll probably switch back to a regular mouse for that. And also, I’ll probably use a regular mouse for art and stuff like that. But at the same time, I’m trying to move more towards touch screens and direct manipulation where I can for that stuff. So, that takes the mouse out of the equation. That’s really it for me today. CHUCK:  Alright. Jessica, what are your picks? JESSICA:  My pick is an article. It is about ‘Dancing With Systems’ by Donella Meadows. And it’s a rather old article. When I first read it, I was like, “Oh my god. This is the most beautiful thing I’ve ever read. We have to get her on Ruby Rogues.” Unfortunately, she died in 2001. But please, we’ll post the link. Go read this article. Even if you just read the introduction, just a few paragraphs, it’s a beautiful description of how when our programs get big enough and they’re not just programs, they’re systems, when our applications and systems get big enough we can’t approach them as omniscient dictators anymore. We can’t expect to predict and control how they are going to behave every minute. As soon as the network is involved, give it up. [Chuckles] JESSICA:  But what we can do is observe them and influence them and in her words, dance with them. And it’s beautiful. That’s what I want to do as a programmer. I don’t want to limit myself to things that I can control absolutely. I want to grow with the system that I’m working on. That’s it. That’s my pick. CHUCK:  Very cool. Alright, well we were having a discussion in the background and I realized that Avdi was pushing my buttons. [Chuckles] Anyway, so I started looking at ways to automate my Mac. And it turns out that Mac comes with its own automator. And so, this is sort of, it’s more of a plea for help than a pick. If you have good resources for a Mac automator or ways to automate things on your Mac… [Chuckles] CHUCK:  For example, when I plug in a drive or an SD card for it to do certain things automatically, that would be really cool. So yeah, so if you could help me out with that I would appreciate that. Just tweet them at @cmaxw or email me, chuck@devchat.tv. I would really appreciate that. Corey, what are your picks? COREY:  Okay, I’ve got a couple of picks. I recently got a high-capacity portable charger to carry around with me when I go on walks and stuff to charge my phone. And it’s awesome to have one of these things. I’ll put a link up to the one that I have. And it just, phone starts to die in the middle of the day, it has a couple of USB ports on it. It’s fairly compact and not very heavy. So, I just got it recently and I wonder why I didn’t get one before. My second pick is a book. I think I’m one of the few people in the world who isn’t too keen on ‘Confederacy of Dunces’. And I’m convinced that the latter, the second half of the book happened entirely in his mind, which nobody else seems to think. And Sarah thinks I’m crazy about. But I wasn’t that big of a fan of it. But I found a book by Drew Toothpaste called ‘Veins’. And I always laugh and say it’s a better ‘Confederacy of Dunces’. But I highly recommend this. I’ll put a link up to it on Amazon. It’s a short book, really good feeling to it. Two more, podcasts. There are a couple of podcasts. 99% Invisible which talks about the things in the world that you don’t really notice, tunnels and things like that. Song Exploder which talks to a band where they deconstruct one of their songs and talk about building it back up and what are the pieces to it. It’s really fascinating. And then Hardcore History by Dan Carlin who does these epic five-part series on World War I or something. And each one is three hours long. It’s this epic, really wonderful stuff. And they’re all stories about history rather than detail or data and timeframes and stuff. We talked earlier in the show about the idea of looking back over time as to where some of our ideas came from. So, I highly recommend just going and perusing the c2 wiki which was the original wiki, Ward’s wiki back in the day. And you can see discussions amongst people developing a lot of the ideas that we take for granted right now, way back. Way, way, way back in the 90s. And so, it’s a fascinating thing. There’s still activity on it. It’s still a wonderful resource to get lost in. And my last pick is walking. I love to walk. And I walk with podcasts, I walk with books. I walk without books. I walk with destinations, without destinations. And I highly recommend to everybody to get out and go for a long, long walk because it’s wonderful. And those are my picks. JESSICA:  Awesome. Bipedal motion stimulates your brain, so it can totally help you to go for a walk during working hours. COREY:  Exactly. So, I had days where I would walk 16, 17 miles. Incidentally, walking not only stimulates your brain but it’s fantastic form of procrastination because nobody’s going to say you’re wasting time… [Chuckles] COREY:  Because you’re walking. So, not that I use it that way of course. AVDI:  I totally use running that way. COREY:  [Chuckles] AVDI:  It’s like, I do not want to do this. I’m going to go for a run. [Chuckles] I’m going to procrastinate while feeling good about myself. COREY:  Yes, exactly. CHUCK:  Usually it works for me the other way. Sometimes I just get totally stressed out and I can’t focus. And so, I go for a run and it lowers my stress level to pretty much zero. And then I come back and I’m all stimulated and happy and not stressed anymore. And so, then I can get to work. COREY:  Yeah. JESSICA:  Works for me in a different opposite way. AVDI:  [Laughs] JESSICA:  If I don’t get to work on this I have to go for a run. Alright, I’m working. I’m working. [Laughter] AVDI:  I wish it worked like that for me. For me, I usually come back just hungry and wanting to sleep, but still worth it. COREY:  Yeah. CHUCK:  We’re all weird in our own unique way. AVDI:  [Laughs] COREY:  Yeah. [Chuckles] Yeah, so those are my picks. Yeah. Also, I put a coupon together for my book if readers want to, or listeners want to go read it. So, I’ll put that up in the show notes as well. CHUCK:  Yeah, we’ll get that in the show notes. One thing I forgot to mention, I’ve been talking about, especially on Parlay I talked about it. I’m pulling together a series on Ruby on Rails called Rails Clips. And I’m going to do a presale. So, if you want to get in now I’m actually going to be offering it. I’m going to be doing $10 a month. But if you get in on the presale, it’ll be $5 a month. And if you go to RailsClips.com, I’ll have it set up by the time this goes out, so you can just sign up. And yeah, so go check that out. And other than that, we’ll wrap up. We’ll encourage you to buy Corey’s book. We’re very happy that you came, Corey. Thank you. COREY:  I’m honored to be on here. We’ve tried a couple of times over the last few years and I’m happy that it finally worked out. I appreciate it. AVDI:  Thanks a lot. CHUCK:  Alright. Well, we’ll wrap up. We’ll catch you all next week.[This episode is sponsored by WatchMeCode. Ruby and JavaScript go together like peanut butter and jelly. Have you been looking for regular high-quality video screencasts on building JavaScript done by someone who really understands JavaScript? Derick Bailey’s videos cover many of the topics we talk about on JavaScript Jabber and Ruby Rogues and are up on the latest tools and tricks you’ll need to write great JavaScript. He covers language fundamentals so there’s plenty for everyone. Looking over the catalogue, I got really excited and can’t wait to watch them all. Go check them out at RubyRogues.com/WatchMeCode.]**[This episode is sponsored by MadGlory. You’ve been building software for a long time and sometimes it’s get a little overwhelming. Work piles up, hiring sucks, and it’s hard to get projects out the door. Check out MadGlory. They’re a small shop with experience shipping big products. They’re smart, dedicated, will augment your team and work as hard as you do. Find them online at MadGlory.com or on Twitter at MadGlory.]**[Hosting and bandwidth provided by the Blue Box Group. Check them out at Blubox.net.]**[Bandwidth for this segment is provided by CacheFly, the world’s fastest CDN. Deliver your content fast with CacheFly. Visit CacheFly.com to learn more.]**[Would you like to join a conversation with the Rogues and their guests? Want to support the show? We have a forum that allows you to join the conversation and support the show at the same time. You can sign up at RubyRogues.com/Parley.]

Sign up for the Newsletter

Join our newsletter and get updates in your inbox. We won’t spam you and we respect your privacy.