 you to look at while I talk about me. About four years ago, I started using Scala. My company at the time, right now, Technologies, needed some big data web servery stuff. And it had to be JVM. So Java made me sad. And I did this. About three years ago, I was eating breakfast with my daughter. A friend sent me a link. And I dropped the F-bomb into presence for the first time, because Oracle had just acquired my company. I'm still out of Oracle. Nobody's made me stop using Scala. And I've been having fun with a great team for a few years. And they're walking out the door now. No, I'm kidding. Because they've already got this. If you're having trouble seeing my slides, I've posted them at 10yearold.com, PNWS, lint, and moving on. All right, so I think you should use static analysis for your Scala. One is because Scala C enables some things that demo really well, but cause problems in more of a production environment. I think you should have a coding standard. And when I say a coding standard, I don't mean you should have a markdown document somewhere that tells people what to do. And there's just a vehicle for passive-aggressive behavior. I think you should have an executable coding standard of best practices. And then finally, I think you should figure out ways to automate your code review. And by automate that, I mean have best practices that people can see, even when there's not an expert around or if you've got an open source project. You've got ways that you can help people understand what you expect when they're submitting pull requests before they actually send that pull request in, and you have to bounce it back to them. So I think static analysis can give you these things. You deserve a better compiler. So when Scala C infers any, for example, you get a terrible error message that doesn't help you until much later. I think you deserve more hygienic code with consistent indentation and things like that. I mean, just shouldn't be a question anymore. It should just always be right, because the compiler tools help you get it. I think you should have higher quality code with fewer nulls, fewer vars, that sort of thing. And then finally, I think you should have fewer hidden bugs that you only find later. And I think static analysis can give you all of those. There are a ton of places you can get static analysis in the Scala ecosystem. I'm gonna try and cover all of these quickly. Yeah, all right, here we go. If you are using your IDE for static analysis, I'm really sorry for you, because although it might do a great job, that doesn't mean the other guy in your team is using the same thing, and there's nothing preventing you from committing code that we know would have problems and have it go through the release process. So I'm not talking about that. What I will talk about is a bunch of other things that can be integrated into SVT. I'll give you a traffic light approach to how I think they're doing on a few different axes. Their signal-to-noise ratio, how well you can say, no, really I know what I'm doing and suppress problems that aren't problems, or maybe are, and how easy it is to get started with it. How good the documentation is, that sort of thing. Okay, so here's somebody complaining about Scala and they didn't like the way it behaved. So we've got an object, we've initialized A to B, we've initialized B to 42, and then we print X dot A. What does it print? No, no, it's not null. Zero, right. Go home, Scala, you're drunk. Great news, in Scala 211, the compiler will warn you when you've done this. Bad news. You only see warnings when you change the file that has that bad thing in it or you're doing a clean build, which means you can still ship that stupid thing that's gonna blow up later, right? Well, I agree with Seth's tissue. He says, you should enable X-Fatal warnings. And I, yeah, you should. If your project is well-managed, this is probably a great place to start. So in SBT, you'd do something like this and you'd be probably breaking your build. All right, so does this code compile? Sorry, I'm gonna really protest at that point because if you wanna have something that works cross-billed, you wanna have a library that supports whole versions of Scala, new versions of Scala, you are basically seeing a problem in a hard place because you want better warnings, you have to use a newer version of Scala and you'd say, well, I wanna enable bigger warnings while in the new version, right? But you're gonna need to have stuff there if your library is there and that's just for the older versions of Scala. That is, there's gonna be things that you've broken right, there'll be more and more now, but you have to do it in the new ways because you have to do it for the old versions because the good new, the new partners, is not available when you go back to the older busted. So to summarize, Stephen has been bitten by cross-version Scala builds, which is an unusual problem because most people aren't making libraries. I empathize with your position. I'm not going to pay attention to it and I'm going to roll out. Does this code compile? What does it return? False! What the, right? So what happens is the compiler infers that those last parentheses are unit, they're being passed to equals and no, the set is never equal to unit. Okay, does this code compile? What does it return? Hooray! Exact same problem, right? We're calling apply with unit, the set never includes unit, great. So adapted arguments are the name for this sort of thing. It was deprecated, but deprecation is just a warning. So because it's just a warning, you can merrily ship this because it's deprecation that you use to find this thing. You're kind of in an uncomfortable place. If you depend on libraries that have deprecated things, then to get this warning, anyway, not the best situation, but that's what it is. So if you can, it'd be really nice, in addition to ex-fatal warnings, sorry, Stephen, to turn on deprecation. There are also other ways to do this. There's, go ahead. No, just to address the problem which I think was alone is that if I'm going to understand correctly, you can address this in SVT, you can look depending on the scalar version or you wanna add this to the scalar option or not. Probably. I'm not an SVT master. The comment was that you should be able to look at the current version of Scala being compiled in SVT and add the flags appropriately. So does that seem reasonable that you could only apply these higher level of warnings when you're under the most recent version of Scala? Okay, I don't know how. Probably. Eugene could teach you, I'm sure. Okay, so this here code, what happens when we compile this, compiles great and when we run it, we get an exception at runtime because we mismatched the format specifiers and the number of arguments to format. Right, great news. Eventually we got string interpolation in Scala, so we shouldn't be doing this as much any longer. So now I've gone through and I've changed my code and I added my interpolation and I shipped my code and it doesn't work and I go look in the log and oh, great, I get dollar signs because I forgot to put the S on the front because I'm clever like that and I've done it plenty of times. Good news, you can enable dash x lint to Scala C in 211-ish I think and it will tell you when it looks like you've done something like this and they've done a really good job not having false positives on this. If they see dollar sign and some random stuff in your string but it doesn't match an identifier in the neighborhood, it won't complain at you. So kudos to the nice people that made that in the Scala compiler. So here's my recommendation, excellent deprecated and fatal warnings. If you're using 211-4, you can selectively enable parts of the excellent. They've broken it up and made it possible to enable incrementally. Does this code compile? Sorry. Are we inside like a larger audience? Yes, soon, sure. Sure, okay and once it's compiled, I don't want it to because nothing sensible is going to happen. My ADT includes this member that's garbage. And the reason it's happening is because Scala is nice enough to infer any for us. Here's sort of a similar thing. I'm making a cross product from a sequence of numbers in the sequence of strings and I probably should be sticking that into a tuple but I was in the mood for sequence and so now I've got this weird sequence of any and nothing good is going to come of it later because again, we're gonna infer any. So once you've been able to excellent, you'll get this wonderful type error and I love this one because whenever I see it, I just saved myself three minutes of reading confusing error messages later. So thank you to the nice people in Scala C that implemented this check. So seriously, enable excellent, if you can, deprecation and fatal warnings. So Scala C, they've done a great job. I got no false positives about it. You can't suppress the warnings. If there's a compiler, it's a compiler, you gotta fix it. The options aren't very well deprecated. It's kind of a process of stringing together log posts and I don't know. It's not the best documentation so it's kind of hard to get started. Okay, moving on. There are other things in the ecosystem that we can use to check stuff. There's this thing called FineBugs that came out of the University of Maryland. It was intended for Java. Somebody who went along and made an SBT plugin which made it just real easy to drop into SBT and that's great because you can quickly find out that it's almost completely useless for Scala because all of the lambdas and all of the vowels generate variables in ways that confuse it and all that synthetic code with the mangled names comes pouring out and yes, not worth it. So anyway, signal noise, just stop right there. Don't, yeah. Moving on. There's a thing called Scala Style. It's Martin Ordeski used it in his Coursera classes to help people identify the happy path for Scala. It doesn't use the Scala C, it's not a Scala C plugin. It has its own parser, Scalariforms parser. It has a nice SBT plugin for easy integration. By default, you run it with the Scala Style command. You could hook it into other parts of your build if you chose to but in general, the kind of things you're gonna find here aren't the things that you wanna be told about in making your compiler better. It's more, I'm about ready to command my code. Oh right, our rules say this. So I'm happy leaving it as a separate step and it's a pretty well documented project. I'm happy with it. Okay, here's the bad news. This wall of XML, which I'm really sorry about is how you compile it and I've managed to compile two of the 58 rules in these many angle brackety lines. So that's kind of the bad news. It makes it easy to generate a default config file where everything is more or less, I can't remember if it's enabled or disabled and you can just, you know, set things to enable as you want, you know, incrementally stepping through. Sorry, that default generated two things like way out of date and you have to take over and find new stuff and add yourself. Okay, I've been using it long enough that I haven't generated a new one in a while. I like the way that ScalaStyle does suppression. It's comments, some people don't like this. I like it simply because the suppression travels with the code, so if you refactor and move it to a different file or if you rename the class that it's in, it stays suppressed. I think the ability to suppress is really important. There was a best practices for Scala document going around recently and its rule zero dot one was don't just blindly apply the rules. So being able to say, you know, there's a terrible job at API, I have to pass it null. That's just the way the servlet API is in some cases. You know, we shouldn't break our build for this, it's fine. They also have this shorter form where you can jam it all onto one line. So I would break ScalaStyle's rule set down into three broad categories. Kind of coding standard stuff. I'll talk more about that in a second. Banning, kind of treating Scala as just a better Java and enabling good practices. So when I say a coding standard, I mean things like the length of your files, your functions, your argument lists, cyclomatic complexity, the number of functions you have in a class, indentation, two spaces, don't talk about it, no tabs. No magic numbers, identifiers, matching regaxes, and you know, how you put spaces around your operators. And it's just kind of one of those. Anyway, this is the coding standard kind of stuff and you can tune it how you like. You can ban nulls and vars in return, while and clone to, you know, try and encourage people to think functionally. And then good practices. We probably don't want to ship a lot of print lines unless we're making command line tools. When we are making public methods, we probably should state the return type instead of it letting it be implicit because that's a little bit brittle and we don't want to do that. Remembering to implement hash code if we have equals and vice versa, these sorts of things. Structural types are one of those, you know, things that we've come to think are not a good idea, but we need structural type to do type lambdas. So, if you've got a monad defined in there, you'll have to suppress that rule. Horrible boss structural types, except for the reflection based on runtime. Hi. So the thing that we should be checking for is whether you're structural type and should be for the methods of structural type. Yep, and I don't know of a tool that will do that. This is what seems to be available. You could write a better tool. So, for extensibility, the easiest way to do it is you can just write any regular expression to look for in the code and fail if you find it. For example, that's how the print line check is implemented. You can also write your own custom rules, but it's a pretty cumbersome process. So I wouldn't really recommend that. The rule set is just generally broad and unfocused. They sort of teach both sides of the controversy. There'll be conflicting rules that, you know, if you just enabled everything, you would have code that you couldn't possibly pass. So it is. All right, so in general, the signal because it's executable coding standard kind of stuff is not that great in most cases, but being able to say, well, you know, don't use the return keyword because that's not idiomatic scholar. I like the way they do suppression. The documentation's pretty good. I'm happy with it. Yeah, I think we in general should be moving away from just saying, here's our markdown document for coding standards. Coding standards ought to be something executable and uniform. If you don't supply like one of those, the X and L configuration, is it just does nothing then? No, if there's not the X and L, it fails the build in the sense of I couldn't find a configuration I give up. Yeah. Abide is another tool that has just recently shown up. It is in the skull a bit of GitHub. It looks like I'm not gonna try and say their names because I'm sure I'll say I'm wrong, are working on it. The documentation is very much a work in progress with smiley faces and lulls. There should be something here in places. There's no published artifacts, snapshot quality stuff. So you can see from what documentation they do have that the rules are gonna be more mainstream. It's not just ban null broadly, but try and say, don't put vars in a public place. It's okay to have vars in private. That sort of thing, they're gonna have some ACA specific rules. I really like the idea of these unused locals. I've found in general that there are lots of errors in cases where you do this. Actual bugs where you intended to use some parameter and forgot to. So that's something I'd like to have. Unfortunately, it doesn't really exist yet. And I wasn't able, I mean, I could have downloaded the code and built it and run it, but I think it's more, not so much don't use it as keep an eye on it. I think this could be a good thing. Moving on. Wart remover is a tool that Brian McKenna made. It's living in type level these days. And as you can imagine from being there, it's bent as towards the more haskell side of Scala. It's accurately and well documented. It's easy to extend it looks like. I mean, I didn't do it, but it seems clear how you would do it. And I think this thing's improving quickly. I looked maybe six months ago or a year ago when it just didn't seem put together and they've come a long way quickly. So this here code looks like something I would put in my tests. Will this code compile? And what will be inferred for the type? Man, it's like you've been burned before. Yes. I don't want this to compile. I want something to tell me that I've done it wrong before I get later. That's one of the things Wart remover does. If I generalized it out its capabilities, I'd say it helps you avoid problematic inference like that. Again, it has the banning better Java sort of things and it bans partial methods which throw and I'll explain that more in a bit. So our good friend any is still here. Product and serializable as Eric just mentioned and nothing can be ways to fail the compiler if it infers that. It has a slightly smaller set of better Java sort of things that it bans. And there are these methods like head on a list that throw if you have an empty list. Brendan earlier today was using a non-empty list. Great. We call these the YOLO methods on our team. I expect to see slash YOLO if I've got get.option. When we started we weren't sufficiently hardcore to understand why these weren't a good idea and we have a lot of them still because Wart remover doesn't have a particularly great way to suppress on a line by line basis. We haven't tried to enable this but that would be an interesting thing for us to do. If you want to enable Wart remover's everything you do it like so. You can also more incrementally do it like this and so this will give you all of the don't infer dumb things rules. If you wanna do suppression you do it like this. It's either at a package level or at a class level and so in general I found no false positives when I ran Wart remover on our code. I meant to say our code's about 30,000 lines. It's I don't know like 30 map reduces and a few web servers and some command line utilities, that sort of thing. I'm not crazy about the way it does suppression but that's what it is. The other thing I don't love about the suppression is this goes into your build SBT projects, build.scola, that kind of thing which doesn't feel like an awesome place for that stuff but that's the way it's done and in general the documentation's great. It's easy to pick out the things that you want. It's not like a restaurant with a menu of 200 items and you can't figure out what you want. It's a fairly small set. They're fairly well categorized. Anyway, I recommend that. Yeah. I'm gonna move on. Okay, so this code. What do you see that could be problematic in this mess? Well, what I'm looking for here is right up here I'm concatenating a string with an array and the extra awesome two string on Java is gonna give you something like left square bracket, Java lane, string, at sign, hash thing and that's not really any good. I mean, I was trying to give myself some debugging message and because I wasn't careful with my array I got that. So here's another sort of problematic piece of code. Any ideas what might be? Right, I've got a list and I'm performing a big O and operation on my list for something that there exists a constant time thing. I should be calling is empty on the list. I felt real dumb when I got this one on my own code. So there's a tool called Linter. It's had a lot of history. It's gone through a whole bunch of different people. The original time, as far as I could tell that it hit open source was about in 2012, Jorge Ortiz, open source, some stuff that was, I think this came out of four square. It's been forked. It's been forked. The current guy that's maintaining it, I'm, I got the pronunciation of his name and I probably won't say it right. I thought it was Mati Poshnik. He's on Twitter at Harry Porter. Anyway, the documentation is not as good as I wish it were. It's a Scald C plug-in with no SBT plug-in, which is to say it's not configured in the same way as everything else. And there's no suppression mechanism for it. There are 90 some rules. There's not any documentation other than a comma separated list of 94 things on the GitHub page. And in general, the rules are not style-oriented or banning better Java. It's more like those things that I showed you before of, oh, these aren't good practices. Let me help you do it better. So on our code base, these are the kind of things it found. We were calling string format with the wrong number of arguments. Yay, it was blowing up in our debugger, you know, that kind of thing. Unused function arguments. I found a couple of bugs in my stuff there. I was sad about that. The length, like I mentioned, using string interpolation when there were no variables inside the string to be interpolated on, calling to string on an array as I showed you, failing to close a Scala source inferring nothing, calling to byte instead of, or sorry, calling as instance of byte instead of two byte, and calling collection conversions to convert to the type that it was already, and string likewise. And as somebody mentioned earlier, Java conversions are a perversion. Well, this tool will tell us not to use that perversion. All right, so I really like it, but it's a snapshot, it doesn't have good documentation. I had no false positives out of it. It found real bugs. I wanna, I wish I could recommend it, but I don't feel like I can, because it doesn't have suppression and the documentation's poor and, you know, it's never really properly been released. I've been trying to encourage him to do so. Hopefully he will. All right, in this code, what could we do better? Right, instead of walking down it and then determining if the option is defined, we should just call exists. This code, what should we do better? Contains, right, on a collection, instead of calling exists with a lambda, we should just use universal quality and determine if it's in there. Sorry, what? It's not, this contains, I believe, is type safe. No, you would have to specify, with two elements, you would have to specify the type explicitly or for it to be type safe. This is true, if we have our rules turned on that prevent us from inferring the wrong type, then we're, we can't infer down to any, as long as they didn't have a common base type other than any or those other things. But I see your point, yes, I agree. I mean, are you going to get a type safe? Sorry. Well, this one is not type safe either, you would have to invert it. Could it be type safe for some reason? The compiler doesn't type check them? Yeah. This linter and this tool I'm about to talk about will both detect when you've got this sort of thing, I believe they will, where you're comparing two things that can't possibly be equal. But anyway, there's this tool called Scapegoat, it's fairly new as well. Steven Samuel, somebody in the UK has been pushing this forward pretty quickly. It's been churning a lot, I mean, he's been publishing releases often. Seems to be documenting it pretty well. When I looked, the documentation was just a little bit behind. Suppression is file-based, file-name-based, you can write regexes on the path. So it's extremely ambitious. It seems to try to do everything that linter and scala style and work remover do. As a result, it's really overwhelming because there are 108 rules or something to that effect. As I mentioned, it has this, you know, prefer exists over find and is defined. In our code, it found a sealed class that didn't have anything derived from it. We didn't mean to say what we said there. A pattern that we fell into was we would pass something that took a lambda, a function that immediately matched on, you know, underscore match and then a bunch of cases and what you should just write there is directly pass in a partial function thing. If that makes sense, go ahead. But in that case, though, I thought there was like warrings that you don't get when using the partial function instead of the lambda that immediately matches based on like missing match cases on such a term. But. Yeah. Sorry, what was that? Sounds familiar. I mean, that missing match case warrings, I believe in the case you pass in a partial function and map, you don't get like missing case warrings where you might, if you do a underscore match and then a bunch of cases. I thought I was getting exhaustiveness checking in that case still, but I might be wrong. That would definitely be worth looking at. We had duplicated imports, which was sad. Again, the length zero, like I was talking about, it finds places that you're using vars that you could write it as a vowel instead. Unused method parameters and our friend contains instead of exists, it recommends. What I dislike about this is that it's just simply overwhelming with so many rules coming on by default. Some of them seem misguided, like telling you that you shouldn't mark a case class final. It was somewhat unclear how to disable rules and how to do the mapping from the error that you got on the command line to what changes needed to be made in the project. It bans wild card imports by default, so I'm not entirely sure how you use the bedazzle my library pattern at that point. And I got a lot of false positives relative to what I saw in other analysis tools. Again, I'd say this is one to keep an eye on. It seems to be making good progress, but yeah, what I wish for both winter and scapegoat were that there were documented on their sites. Here are the few things that we think are most important and most likely to be real world bugs. And I haven't tried to take the time to figure that out myself. I'd like to see the authors sort of focus on that. It seems like to ask them to do that is asking a parent what their favorite child is. I mean, these guys love all hundred checks that they wrote. Here are the five that are gonna keep your stuff from blowing up. So here's my summary on this. In general, go turn that on if you can. Sorry, Stephen. I feel like if you're gonna have a coding standard, it ought to be implemented in an automatic way and a war remover does a lot of things right and does them well. So those are the three that I'd recommend right off. Scholacy, Scholastyle, and war remover. So if you've got a new project, I'd recommend that you use those three that I just mentioned. I posted to GitHub a skeleton project that just enables those things. So if you grab the project, you can get there or go to my GitHub page and it should show up. If you have an existing project and you wanna get started on this, I mean, you kinda have to just treat it iteratively and work with your team to get there, you know? It add one of these things to your project with things disabled, with all the rules disabled. Obviously, this doesn't work well with Scholacy. Get a linter gate somewhere in your release process to ensure that you fix these things before you move on. Pick out some rule, clean up the code, feel free to suppress. Keep going on. Go ahead. So the question is, how much overlap is there between the recommended rules and your recommended tools? So it sort of depends on which version of Scholacy you're talking about. They've gotten a lot better in recent releases. That check to not infer any is fairly new. If you want that check for any, and you're on 210, I believe you need to use Wart Remover instead. Between Scholastile and Wart Remover, there's some overlap. I, in this skeleton project, only enabled the bits of Wart Remover that weren't overlapping with Scholastile. So for example, Wart Remover has a check for don't use return. I don't feel like that's something you need to know. Every time you compile that could be deferred to before you commit. So I said put that check into Scholastile. In general, all these tools have a fair amount of overlap. If you just want one simple thing to do, try and get your build clean with Scholacy's lint setting simply because I think those give you guidance about where Schol is going in the future and are saving you from problems, creating more problems today that you'll have to fix when you want to upgrade into a newer version of Scholah for the new hotness. Do you have any other questions? Thank you very much. Have a good night.