Scale By The Bay 2018: Bill Venners, Frank Sommers, Effective Scala
Recording: Scale By The Bay 2018: Bill Venners, Frank Sommers, Effective Scala
you thank you is this on hello I guess you can hear me can you hear me in the back the people reading their email great thank you so Franken are gonna have to go like back and forth just we'll try to remember you because they can't hear you if you don't talk into here so we basically wish talk is about best practices and and there's only you know 40 minutes so we just picked three three ideas we are actually theoretically working on a book called the effective scholar to capture that because after 10 years of Scala we've both been using Scala for 10 years and I think the community has been using Scala for for many years and and and some some ideas have emerged so we were trying to capture them so we wanted to give a couple today so it's a switch Paul actually once you go in the city so we only have 40 minutes so we only gonna give you like a synopsis of what we're trying to talk about in our book but you know I've been doing Scala for over 10 years now I think we started at 2.8 and while Bill did the Scala test tool which so many people use I actually went ahead and sort of company and we have a pretty long and large code base that uses Scala like I said it evolved from two dates and we're now into 314 I think right now and so basically we are we try to keep up today but what is interesting about that is that when I started out we started from a Java background most of our developers have Java backgrounds and now over 8 and 10 years you know we evolved this codebase and what we noticed was that Scala is really a nun opinionated language you could do things in so many different ways in Scala and when programmers come to the code base they often wonder well what's the best way to do certain things in other languages like in Java or Python or languages you probably don't have so much diversity in terms of how you can accomplish and pretty much the same tasks so on the one hand you could program in Scala as if it was put in quota birch tasks on a JVM and I've heard that being said as one of the the possible ways to think about Scala and that certainly is a very valid approach and I like some of that to work it's really interesting and it's it's definitely a way to programming Scala the other way on the other hand a lot of people who come to Scala from Java they program initially as if they were basically writing Java code with Scala syntax without the semicolons but what's interesting is that I heard Martin say this - several times that Scala is really about a third way it's a functional object-oriented language and I often wondered what does that mean and and when he applied to actual daily work in terms of work and a code base what would it look like so this talk really is about this Third Way which we think at least as her opinion that it's it's probably the really effective way to work with Scala yeah so we are opinionated and our effective spell is supposed to be opinionated and so what what we are opinion is is that the third way is the best for most projects and what better Java is really useful for is people who are just getting started they're coming from a different language most of them are parrot comparative most of the mainstream popular languages do things in a very imperative way and you can just do that in Scala and I think that's actually a good thing to get started just get stuff done install the way you're familiar with and over time you will learn more idiomatic functional ways or more idiomatic Scala ways of doing things and that's actually helps people get into Scala I've also seen a very hardcore functional style work in great in in practice in real companies but the thing that has always been present is a strong leader at the top to sort of make sure everybody understands those abstractions and and sort of decides which ones to use maybe which ones not to use and make sure everybody's going in the same direction what I've also seen more often is that people most projects are more like this functional object-oriented but not necessarily Haskell emulation approach style and most people on the team are doing that but there's one or two really passionate Haskell people who do this other way off to the side and then if they leave no one else can understand that code so what's important is that everybody is going in the same direction all these ways I mean Scala is unopp in Yin aided in these different ways work but it's it's not and I want to say in the community it's really exciting that there's these different ideas and people trying different things and go in different directions and coming back and talking to each other but in a single project that's actually not the right place for it we think you should have one way of doing it in the project and the management has to sort of make sure people going in the same direction so in our book we're planning to come up with about 50 guidelines about what has proven to be effective Scala programming at least in our opinion but here we just gonna give you three guidelines so the first guideline really is that even though Scala is really unup enya nated and precisely because it is on opinionated when you start a project you you should form a project opinion you should decide which way you're going to go with that particular project and then you should start you should try to stick with that throughout the project as much as possible and for the whole team and so that's our first guideline okay so this I don't have Jamie Owens here today he might be at the conference but he actually came up with this it's he called it the community he taught it to me in a class he threw it on the on the board he said this is the immutability matrix of pain he's very strong when he says then and I thought that was a little bit harsh so I rebranded at the immutability matrix of pleasure so what this is is an example of stall is unopp Enya nated but we should be opinionated so what Scala has is two kinds of variables vowels and VARs vowels can be initialized but not reassigned they're like final and Java bars can be reassigned like regular variables in Java and then objects can either be mutable or immutable an immutable object once it's initialized you can't observe it changing state maybe has a lazy bowel a net mutates later whatever but from the outside its referenced a transparent it's immutable immutable objects actually just the whole point of them is you can change them over time right so actually we can actually take a boat here I think this so what well okay in your heads you wouldn't have to take a boat what do you think is the the best we think about where you think is the happiest place to be pleasurable the most pleasure or a place to be not the least painful place but the most happiest place okay Frank what do you think well I don't know what you mean by pleasure but the most the most boring place is to be over there in a sense that it's very predictable right so you have basically a valve pointing to an immutable data structure so you pretty much could predict what's gonna happen your program even if you have a concurrent program or single-threaded or actors or whatnot futures if you're there most likely you'll be you'll be happy if you can if you can stay there now you may sometimes not want to stay there and again Scala gives you all these different options you could do whichever you want out with these four options so if you cannot stay that or you don't want to stay there then which one would be the second happiest place what would be would be the second life you can think about now yeah we could take one so who would for this is a second happiest place the point to an immutable data structure 36.7% so it's a vowel pointings to immutability of structure 22.3% how about this guy right here 0% 1% all right how much would you pay for this quadrant so okay we're gonna reveal what do you think it's that guy oh well I'd say I think these two are quite close together the this women this quarter net that one this one but the reason this ended up number two is because because on the JVM you can you have multiple threads and it's easy to close over an object and pass it to a method that may actually pass it to another thread so it's just it's a little bit safer to use a bar pointing to and immutable because if you close over a mutable object then you sure what with a thread and it's um you know mutable state being shared by local threads without synchronization and that could be a concurrency bug it you know especially if you're doing akka programming or concurrent programming that's true so what about the third one yeah well well well the third one switcher I would think this quadrant here so why would you want to do this so yeah so why would you want to do this so here we have a vow pointing to mutable data structure well one reason I can think of doing this is for performance I mean sometimes I'll rhythms are expressed really best in the mutable data structure possibly and it's still better to have a vow like an immutable reference pointing to it but this probably would be the third happiest place and the last one is this guy so here's what I think it's interesting is that this is the regular way of doing things in Java it's like the normal way and install I actually don't recall ever seeing a VAR pointing to a mutable in code I haven't done it myself because there was never a reason to if I haven't made a well object I hold it from a vowel so it's I think an example of how Scala not the syntax or the grammar of the language has an opinion in in Scala syntax it's just as easy to do any of these for combinations syntactically but there's an opinion of the community and also like scholars actually trying to promote that people should do things more functionally which is Val immutable and and so that that's essentially what I think that shows so it just shows the diversity but I mean when people come to Scala first they may start doing this right I think the journey of a Scala programmer is probably going towards that direction but then again sometimes what we're kind of saying is that it's okay to though those two things as well no Scala doesn't let you do all those things so our second guideline number two is that you know Scala is a functional object oriented language so I think when you form a project opinion is probably really important to know for that particular project what are the benefits of opie and what are the benefits of functional programming I'll start with functional programming I think the big benefit of functional programming as you scale up is is that you it helps you reason about code because of referential transparency which means that a pure function if you pass it some data it crunches on that data but it doesn't have any kind of effect that you have to keep track of off to the side it just returns something and everything it does is sort of embodied in that result and if you say that's it the same thing you always get the same thing back so you can actually conceptually in your head replace the function call with the result and you're fine you don't have to remember something in your head that that function did off to the side and in the small you can reason about imperative code but in the large it this really helps you understand code and helps us build things that are more complicated so I want to give you an example of that in the small imperative code is is actually easy to reason about it's not just that imperative code is always hard to reason about so this is the implementation of the exist method and list and if the list holds on to immutable objects if it's elements are all immutable and the function here is pure then when you call exists it's going to return a bool and it will always return the same boolean given the same function and that makes it reference lis transparent from the outside but on the inside it's actually doing side-effects because there's a var there and it's holding on to an immutable so that's the upper right quadrant of that mutability matrix or immutability matrix and then it actually reassigns the bar that's a mutation and then it actually returns out of the middle and this really looks like java code but on the outside its pure right so that's like if you can capsulate your your keep your mutation and little pieces people can reason about the code on the inside and they can reason about on the outside because it's FBI so so I mean clearly this shows that in a small you could you could keep track of side-effects like a little loop everybody could see you know two seconds what it does and I don't think you can make a lot of mistakes about it and even if you do it it's kind of constraining to this function but the real problem in mutable state obviously is in the large and what's the problem that that is that you have to keep keep it in your head you have to track how you mutate the state and I'm my opinion that's really the problem so I mean even going back to something like C programming days or C programming days basically mutating the heap is essentially this problem right we're trying to keep in our head havi mutated the state of the heap Sophie allocate for example let's say 4 bytes there and we keep allocating some memory and then we allocate it now an additional 3 bytes so let's try to free up some memory so these tabs we have to keep in our half right so this is the whole reason why automatic garbage collection became so popular and kind of won out is because it means that you no longer have to keep this in your head however we're still mutate this data structure is just you don't have to track it so this is this is the reason I think by mutable state is difficult not in the small and I would argue in as small as probably ok but in the large you have problems when you have to track it and you forget and I suddenly your program crashes because of a memory leak or because yeah you basically just like you free it again you know you're going to your problems come to craft it's so long yeah like malloc is not a pure function right Malik has a side effect it does return something but it you have to remember that you allocated that so that you have to remember because you have to remember to free it later I also have to remember free is also not a pure function it has a side-effect it mutates this heap saying ok this is now available I just have to remember that I did that because so that I don't free p2 twice because that's when I get it corrupts the heap if it the heap never checked for that it just lets you do it and and then it would just corrupt itself and then sometime later the program would crash the other way is you could you don't you forget to free something eventually the program crashes because it runs out of memory right so that's one example I think of like in the large impaired imperative but is hard to reason about another one is is this thing we've been struggling with for a long time now in the Jade Java land which is it's hard to get synchronized concurrent programs right and I later realize that that's because this is a mutable data structure this is what logically exists for every object on the JVM it's called the monitor it's a fancy mutex with some extra features it essentially like because it's it's a it takes memory they don't create them until they're needed so objects that don't actually have synchronized methods you don't get one of these but when someone calls a synchronized method if it doesn't exist already they're gonna create this data structure and the thread that enters the synchronized block it actually goes into this wait set and that mutates this what the wait set this data structure now knows that threads sitting there and then if no one's in this center room that's like the the room only one thread at a time can be and then that thread can go in there that's a mutation this is well now this fits in here and if it either completes and just returns or eggs itself the end of a synchronized section then it goes out the bottom door that's mutation now the room is empty right if it blows up with an exception also that goes out the bottom door and that mutates the thing if if there's a thread inside there that says wait then then actually the thread will be put over here into the weight set that's a mutation and there they want to like they need to wait until someone fills a buffer or another thread comes in and fills a buffer so they can have theater or whatever right so when another thread does that they'll say notify well that'll change these orange ones and they'll all go to green well notify gives has one of them go down there notify all has all of them go down there that's a mutation and now when this room becomes available the green ones are the yellow ones will compete right so if a green one goes back another mutation so it's mutation mutation mutation and this is every time interesting critize method it's actually having that side effect they'll have to keep track of and in the small you can get it right I mean like you can make a little producer-consumer class with synchronized and wait and notify and get it working it's just when the large you end up like two weeks after you to play the production you get a deadlock and because you screwed something up it's really hard to keep track of it so it's another example I think a really good example of and the large side effects are hard to reason about functions I heard a reason not yeah but in the end of small they actually sometimes work so interestingly enough object rated programming I mean originally it was also kind of designed to deal with large-scale complexity right you have a large complex problem domain and the classical design essentially breaks down their problem domain into classes and objects which in some way model that domain and secondarily they would allow you to bundle data that's related to get her into the state of an object so this the whole purpose of this was originally I think to help design complex systems and to manage the data of the state associated with those objects so here's an example that anyone could pretty much instantly understand this is an object-oriented API this is not scholars map it's actually a Google's map API this is in fact the facade that be created for the Google Maps API one of our projects and what's interesting about it is that everyone can understand this instantly what this code does the reason for that is a couple first of all all the function names clearly designate the some operation that you near had you already know that the map does and this just corresponds exactly what you would expect for example if you want to set the map to a street view you know what a Street Muzik use Google Maps it doesn't exactly what it says the methods names are not some kind of an abstract operation they don't define some abstraction they define exactly what that object is you think will do and that's probably one reason why so many hundreds of thousands of people could use this API instantly the other interesting thing about this is that this object this map object actually has state it contains the state of that map it's if it's displayed in your browser and for example you can mutate that state this returns unit and you get meat tastes what type of you present for example a satellite for your street view so it manages state it actually is a it's a mutable object and the point I want to make here is that this is actually very easy to reason about for a developer right because you know exactly what it's what it's doing it encapsulates the data and it bundles those functions together with the data so that's this is really one example as when object or programming can help you deal the complexity because the programmer understands exactly what that code does and that's one reason why it's helpful yeah we know I'm gonna I'm not as good a marketing person as Frank because now I know you really all want to use object on your program because you'll know exactly what it means by looking what and it is actually an abstraction it's a domain abstraction it's not a mathematical abstraction I think that's the kind of thing that I think actually oh oh decomposition usually does in terms of domains I mean when you see map you may think well you make I think it's a like a collection of key-value pairs but when you see get Street View and it's from Google Maps you're gonna say oh I'll bet you that method returns to be at least said that kind of thing helps people reason about code domain naming and that's what oh oh you know the nouns of class names and verbs of method names can really help people understand master code I would say it makes it accessible to programmers so that's the OL part of of it okay so let's go to the next one okay so I wanted to show a example of another example where you have side effects in the small and what this is is the implementation of list dot make string and it's you know it takes three strings the start stirring the separating string in an in string and it's on list so what what is supposed to happen is it's supposed to return an immutable string that has you know the start string at the beginning the in string at the end and then you know to string and all the elements separated by self and the way it does is is it creates a string it actually uses this helper method called add string and that takes a string builder that could have some state in it already but that we create an empty one and we just passed these three strings in there and and then it returns the same string builder that has been mutated that's what ad string does it's a helper string inside list and then it then you convert it back to an immutable on the way out so this is again pure from the outside as long as list has got immutable data in it which usually that's what we do when I call make string and pass in the same strings as input get the same string as output so it's referentially transparent from the outside but on the inside it's it's a lot of mutation going on but I want to show you the inside the add string method the string builder coming in is referenced from a parameter named B and that is a vow because parameters in in Scala cannot be resigned so this is a this an example the third quarter down at the bottom left we've got a valve holding onto a mutable object and the reason it's being done here is because that's faster I could do this all with just string concatenation and I were to get a bunch of garbage strings and it's everybody does it this way if it has to be fast because it is faster it like sometimes the fastest algorithm that we can figure out is with mutating state right so when you have a reason to do that oh it was a great way to do it it's nice to have that state xn capsulated inside the string builder class but note that the schema turned from the helper function but it's not returned from the the string itself is returned from the functions none of our span entire mutable state is saying considered inside inside a particularly function data Mayock string sword and final guideline is kind of to summarize what we're trying to say here which is basically that when you blow up a larger Scala application what you're finding helpful is to think about it in this way if you have i/o coming into your app you should try to confine that region to some well-defined part of your program and in that region you probably will be interacting with mutable api's with java api s with input streams or whatnot but that region should be well defined in your program inside your program like in that make string method you would see that there's also a mutable state in that case you should try to confine that to to just one pair of execution and from the outside that region should be functional everything else in your scholar program you should stay pure as much as possible so we so we call this outside region at the wilderness because basically you're interacting with the wild this essentially whatever goes there you just have to interact with the world from your program and you know very often the best way to do that is to to use strap synchronize to do whatever you can to manage your i/o there and very often again you may have to interact with the existing Java API simply exist in the Java ecosystem in your pure region of your code you should really stay our referendum sparrin completely that would really help you reason about your code and most of your Scala program should be in that region and then in a confined regions confined because we'll be confined to one thread of execution you pray you can use mutable state we think it's okay to do that and it's partly for performance but it's also partly if you need to use existing Java API is that are mutable and that are not functional in any way that would be a confined region okay so one way to think about it is as a call sex so this is a picture of a call stack that grows downwards so like the thread starts at the top and each one of these rectangles is a stack frame that's been pushed on to the stack when a method is called and so at the top is where you know the weather's region I might be doing i/o I'd be calling into Java libraries that are useful to me but once I hit a pure function everything actually has to be pure all the way down because otherwise it wouldn't be pure I mean if there's something down here that isn't pure then I'm not pure up here right so once you hit it you're gonna have to but the you know that what we try to show in this picture is that hopefully most of your code is pure because that helps you reason about floating a large but down here there's a hotspot a lot of times what you're going to do is call into scala libraries and like list out exists you might call that a list up make string and that's actually doing mutation on the inside but it's confined to one thread those mutable objects are not synchronized like string builder is not synchronized so it has to be used by one thread but it's done it just in it's a local mutable object locally that thread and so that is fast so whether you do that yourself or not you're it's sort of happening down at the the hot spot that the part of your code that has to be fast if you have a performance problem then you might need to actually do that yourself like you fight oh this method is taking too long so let me use a mutable object instead but if on the outside is still pure I mean if it isn't pure that boom the wilderness went way down here because it's not pure anymore on the outside so if it's pure on the outside then then you can do all the all the mutation you want locally and in Scala you can just write it you're gonna write a while loop at the bar yeah and I think that they are that's basically our guideline is you should always try to think of the boundaries between these different regions very clearly so here's one example this is actually something that our code doesn't our enterprise out it's basically what we're trying to do here is to have some input some data and anarchist stream and we try to create a PDF document merging this data into some format and then return this PDF document in the Aqua stream so this is a really common enterprise task probably and so basically we get this i/o request through some some kind of a socket or it's an HTTP request or something like that that's gonna be a lot of mutable data structures there if it's a servlet you're going to have a service request which is completely mutable it's a Java class it's really what you have to deal with though and this is something that many enterprise apps would have to deal with but once we get this request the answer is pure region of our of our program so this function here takes an immutable data structure here which is a PDF request in this case and it returns an immutable data structure as well and the mutable object which is PDF data so this entire region here is will be referentially transparent to this region here so given the same input always return the same output and then in this region we would do basically pure functional data transformations for example formatting this PDF data filtering it building whatever computations we need to arrive at the data that we would need to create this PDF given the input not to generate the actual PDF we happen to use our Java library which is in our case I text which is a totally imperative library it keeps some object and it keeps mutating that object like string builder yeah large string builder basically step by step by step I have to say it's a very effective library it lets you basically manipulate PDF extremely powerful way so we can find the use of this API into this confined region again even this function takes an immutable data structure and it returns an immutable data as well but inside is function the mutable data in our case is primary because we're using very very imperative mutable Java API yeah in that case it's not for performance it's just there was a mutable library that that he wanted to use and as long as you know he use it built the PDF but then he converts it to like to string on the string builder he converts it and returns a vector byte which is immutable so another way to think about it is with a Venn diagram and this is just a if you space the spaces here are like your code base your code space so this is like all of your code there that you could think of as placing in these three categories and you hope that the the kind of yellowish category in the center is the biggest one the purple category here that confined regions that's there if you're calling into the skull API and but you you may not do that yourself but for example that app Frank did that you know his you know calls to I text are in that purple region right and then the wilderness is on the outside and that can be greater or smaller and that's sort of one of the things we wanted to say was that it's okay if it's whatever fits your team and your project is actually fine I mean you want to make this as big as possible though the pure region it's ok on the inside to use some mutation for performance or for using a library it's ok up on the outside you make it razor thin and you use IO monad that's okay if again if the whole team is kind of up to speed on that but it's also ok if you just actually keep it small and if it's small you can get the program to work and it's fine right so it could be smaller or bigger or whatever but that to me is not I mean we want to compare it with some other things this is sort of Scala's pattern for for application a name like I just think this kind of happens in everyone's codebase like so we try to give it a name and Bill and I like to eat bagels so we just thought it looked kind of like a bagel well because it has a round Center but the ronster and a bagel is empty so it didn't quite fit this was very good part of the bagel right but then we kind of like to stay in that part but it didn't quite work so we sort of Saturn perhaps but the Saturn here so that didn't quite work either and then we gave a similar talk in in Berlin there was Fela days this year and in Berlin we discovered the Berliner that's a that's a jelly filled donut and it's like I was eating this for breakfast I'm like oh my god that's actually the perfect shape you know because it's not empty on the inside and it's kind of gooey like mutabal so so it tastes really good the jelly part I have to say yeah it tastes good because it's fast so so we called it the Berliner pattern but but that's I think you know and notice the other thing I liked about it is the outside was very thin right because we really wanna that's like idealistic right we want to make that as small as possible especially because sugar it's not that good for you keep it thin okay yeah it's usually powdered sugar in the potato right okay so so if you if you don't do this then you can also do this with Scala right you can basically try to eliminate the inside and just keep everything few early referential the transparent basically excuse pure transformations in Java and I'm notorious Scala allows you to do this as well it's kind of like a verse has called on a JVM so what so yeah one little comment about this myself the the actually I think the wilderness part is to thicken is the diagram it would actually be razor thin and conceptually but but really if you think of like your main method being included in that there's got to be some IO somewhere so that it actually does happen and there's really the purpleness center too because if they're gonna be calling into the skull a pair they're gonna call this thought exists it's actually doing the patient on the inside but you know what you're trying to do in Haskell is just everything is pure everywhere right and this works in scar so you could totally do this it's just it's important to have a project opinion that goes back to guideline one if that's what you're gonna do then there should be a decision and probably you should try to stick to it otherwise but your buddy knows everybody knows this so so what would Java a better Java and Scala look like well with Oh actually we think it would look something like this and this was actually from last night we had dinner and we were looking at this clam chowder soup so we figured that before the San Francisco sourdough bread bowl sourdough bread bowl it would actually kind of fit this right so here we have a really gooey inside right and then we don't know what's happening here dr. Cooper it's a lot of leaking abstractions there but so it basically would look something like this like so basically you have no suede all over the place where you you you essentially perform I or so this is basically Java right there's no clear Delia nation and upon your trying to make is that this is probably not very good in scala but some programs are like that probably you shouldn't choose this as your project opinion but it works in Scala so it's good or bad one other thing I would add to that is that Scala doesn't Java doesn't talk about pure functions and the Java community we didn't talk about that much but we did talk about making things easy to test so like if you write your test first a lot of times you'll end up with a pure function because that's easier to test I think that's sort of where it's snuck in in Scala so a job I mean but anyway so anyway that's that's the the pattern that that we think is is scholars you know that's what Scala is is trying to visit the opinion that if what you should use Scala to do most of the time so before we take questions I wanted to just mention we do we do it we don't have a I don't think have we written the first word of the book so we did make a workshop just to try to flesh out the idea so this is all two days of best practice so if you're interested in that that's something we just gave it earlier this week as a public one and we'll do another public one in a I don't know a few months or we come in house and then the other thing is I our team as my company I do we do consulting so we're always looking for programmers so if anybody's interested come talk to me or email that email and we are available if somebody's helped with Scala we're just focused on Scala and then I'm also a member of the Advisory Board the Scala Center Advisory Board and I represent the community so I'm supposed to like know what you think and what your concerns are and people don't ever complain to me so I would like to invite you to come up to me at conference and tell me what your concerns are so I can relate them to the so thank you and we are okay yeah that's a great question now if I need to repeat it but I might need to repeat it for the so I need to read it for the video anyway I'll repeat it yeah unfortunately forgot it by by now but no it was essentially a great question which I don't actually know the answer to is imma let Frank answer it it's there is there a way like you would organize the code to make it clear that this is what this region this is the region and that's the other reason so I gave you a couple of examples how many have seen this working with developers who come to our code base so for example leaking something out from here if you return a mutable data structure right away you leak some instruction into this region right because this can also mutated so right away I would say in that case he would need to return a mutable version of it so that's just one example so basically the second thing I would say is that when I first like really try to do functional programming in Scala or I really thought I was gonna go all the way to like the Haskell style I really kind of thought that that was an ideal to strive for I really felt guilty using mutable data structures inside my functions but then again we didn't know what to do with all these java api is that are just super useful views and they're very intuitive and that's where I think this region comes in that this has some value to it so I would say it's a larger organizational principle and whenever when we use those API as we make it really really clear that we're going to confine that to as much as possible to one of execution and we going to be functional from the outside of that function so I think in code reviews that's probably a good principle in general speaking and the second thing I have to say is that we don't use use monad for you try to keep this layer thin but not super thin because we just didn't see the payoff don't keep it super thin it could be but you know in our case yeah I want to just say I actually don't I can't think of how to make that clear in the code but I'm gonna think about that that's a good question I don't either use you know a lot of cats for Scalzi but I'm very interested in it and I think I have there's things for me that I mean one thing that I would like to get rid of is dependency injection I hate that and that would let me do that so I think you know it's just it's I guess what we're trying to say is it's okay it's actually there's a lot of value there but it's not like you're not done yet if you haven't if you're not programming that way most people don't program in that way and what if if the you know this part is actually just Java on the outside that's actually fine you still get the benefit of having mostly pure functions so any other questions yes thank you the question is okay so repeat the question so this is very java ish it's it's a immutable object essentially it was a set method set heading right to get headaches I think that's very choppy excuse me and it's wrapping it's wrapping a JavaScript API lets you switch which interesting Lee's compliance is lost relative execution with JavaScript so it's a good example it's mutable state but it's confined to one thread just by virtue of the fact that runs in the browser but yeah so basically type classes versus this well I think this is kind of oh oh so like in here in a sec piece which I think everybody in the you know not just Scala but learned that big inherence hard keys are hard so we usually keep them pretty small and when something cuts across inheritance small these smaller and here entire keys that's a great use case for a type class because it can go it can be independent over I mean it's another small inherent circuit actually so you have these two now and so that's that's how I think of it is the oo way is the inheritance way is good and in the small you can actually do big ones like Scala test is actually kind of like a big one you know you mix in these traits and you use a straight-line ization and super dot you know and all that stuff but most of times that's that this is too much and you just have these little inherits hierarchies so things like how to order a type that that cuts across lots of different inherent hierarchies then you you can you would use a type bus for that so it's time for another question okay alright yeah okay anybody have one more or are you also a complaint it's time for one complaints right yeah okay alrighty well thank you very much for coming to our talk [Applause]