S11E09 Static Code Analayzer with RenŽ Fohring & Marc-AndrŽ LaFortune Intro: Welcome to another episode of Elixir Wizards, a podcast brought to you by SmartLogic, a custom web and mobile development shop. This is Season 11, where we're branching out from Elixir to compare notes with experts from other communities. Owen: Hey everyone, I'm Owen Bickford, Senior Developer at SmartLogic, Dan: And I'm Dan director engineering SmartLogic. Owen: we're your host for today's episode. For episode nine, we're joined by Rene Fohring, creator of Credo, and Marc Andre La Fortune, head maintainer of the RuboCop AST library. In this episode, we compare static code analysis with Elixir and Ruby. So welcome to the podcast. Before we jump into static code analysis, , Renee, can you tell us a little bit about yourself, , where you're coming from, your history in programming RenŽ: Yeah, so my name is Rene. I'm 40 years old, married, have a daughter, and we're living in the countryside in Germany, in the MŸnsterland. I have used a couple of languages in my career, from Java over C Sharp to Python, Ruby, and Elixir. What brought me to Elixir was a deep desire to, to learn a new programming language almost 10 years ago, and my, friend and mentor, Peter, told me if you want to learn something really new, you shouldn't learn like Go or Rust, but a functional programming language, because that's a real paradigm shift, and you have to modify your thinking around that paradigm, and that's how I We landed here, and I'm very fortunate, because I code no more in my day job. I wanted to say less and less, but if I'm honest, I'm no longer coding. And, coding Elixir in my free time is, , the great, , guilty pleasure I have left. Owen: I don't be guilty. All right. Mark Andre, , same question, personal history, where you coming from programming backgrounds. Marc-AndrŽ: So I'm French Canadian, and sadly I'm even older than Rene. I started programming on Apple II Plus and BASIC way back when. And I did a lot of Ruby, and I've switched to Elixir for the past something like three years or so. Owen: so we're going to be talking and comparing notes between Elixir and Ruby. I know the Elixir community has a lot of overlap with Ruby, a lot of, you know, kind of experience learned from Ruby, has been brought into Elixir as well. We'll start with Renee, for anyone who's kind of unfamiliar with static code analysis and kind of the concepts that, , we'll talk about the tools and the details a little bit later on, but how would you introduce static code analysis to maybe a junior engineer who hasn't crossed this concept before? RenŽ: So, when we are talking about code analysis, there's the difference between static code analysis and dynamic code analysis. Dynamic meaning we are running the program, we're analyzing, and static, that we are not. And within static code analysis, there are the two big, schools. One is we're looking at the source code, which, Credo and I think Rubocop does. And there's also a set of tools that looks at object code, like Beamfiles or JavaJars. And that's basically it. A static code analysis tool just reads the code. Dan: And so what inspired you to create Credo? RenŽ: Well, like 8 years ago there, there was actually a code analysis tool in uh, Elixir called Dogma, which, claimed for itself to be the Rubocop of Elixir. And I was actually, I think until today, the, , top contributor on that project, besides, Louis, who Was the, creator. And so Credo is in that respect standing on the shoulders of Giants, because Louis did all the hard work of making the Elixir community accept the fact that we're having some code analysis tool, but much like so many other code analysis tools , they are just screaming results at you and all of those results are something where you missed the mark. And I wanted to create a tool that was much more lenient in the way that it said. Okay, I'm not giving you all the issues unless I run in strict mode, and if I give you an issue, I can also give you an explanation with a code example and some of the rationale behind the issue so you can feel empowered to say, Oh, that isn't really a problem for me. I want to deactivate this check, and that is what mainly, motivated me to, to develop another code analysis tool for Elixir. Dan: Great. And Mark Andre, anything you'd like to add around static code analysis or how you got involved in rubocop? Marc-AndrŽ: Well, on my end, I wanted to write a code coverage tool. But that would be a little bit brighter than the one we had in Ruby. The one we had would tell you if a particular line was run when you had all your tests running. But it wouldn't tell you if every single bit, every single part of your line, was actually being run. And to do that, I had to delve into What is Ruby code? What does an AST look like? And, uh, RuboCup was the big user of the AST. I mean, it still is. And then I started looking at how RuboCup was doing things. I was like, hey , why are you doing, why are you doing things this way and not this other way? And I started, contributing, in this way. And I ended up Rewriting some of the, the tools that we use in ruboCop to deal with the aST. Owen: So I'm curious how the nature of Ruby and Elixir, you know, Ruby's object oriented, , maybe hybrid, programming language, and then Elixir, which I'm much more familiar with, is primarily functional programming language. , how does that affect your approach to. Building a static code analysis tool. Is it really just, I need an AST and then I write messages or is there a little bit more to it than that? Marc-AndrŽ: at some point I was still contributing to RuboCop and already thinking of jumping on the Elixir band. And one of the big issues in RuboCop is, there's many, many checks. And I'm very glad that Rene is focusing on checks that are solid and that people will actually want because there's so many things in RuboCop that you're like, no, but I really want to write it this way. Stop, you know, stop yelling at me. But there's also a lot of false alarms in RuboCop and part of it is because, , as Rene explained, when you do static code analysis, you only look at the source code. And it's actually very hard in Ruby to know, and it's actually hard in Elixir also to know if you're calling a particular function. So, which function are you actually calling? So, I don't know, if you call the function map, is it the map on an array, for example? Or is it some other, I don't know, a geography based function where you just want the map of a particular point? , and there's actually no really good way to know. Maybe you're gonna, you're in RuboCop and you're thinking, Oh, I want to make sure that the users of the map function on array is , correct. And you're going to read, Oh, I'm calling this function map. And then you're trying to understand what's going on, but maybe it's not the map function that you're thinking about. And I was like, Oh my God, I can't wait to see what we can do in Elixir. Because in Elixir at compile time, you know exactly which map function you're calling. And naively, I thought, wow, we won't ever have this problem when we do any kind of analysis in Elixir because we know, are you calling enum. map or some other myGeographyModule. map function? And, but as it turns out, when you do the type of static text analysis that Credo does. Sadly, you don't know which functions you're actually calling. So, and it's actually, it's just even worse, in a way, in Elixir. Because the way the language is built, you don't know much about anything. As soon as you call useSomeModule, everything else after that You don't know. Maybe use has been redefined. Death has been redefined. That pipe symbol that you see afterwards, it's not a pipe anymore. It's, I don't know, something else. So at least in Ruby we actually knew when you were defining a class it had to be a class definition if you were defining a function. Well it was a function definition but in Elixir we don't actually truly really know this . So anyway I was like very excited that I thought we would be able to have even more powerful tools and it turns out that Elixir is the way it's built and with macros in particular. It just means, well, we know even less about what the code really means and what it really is going to be. Owen: I've, I've definitely run into pain points. Macros, especially, are a little bit overused. I Can see this happening, especially with importing functions from another module. I think my, my personal preference tends to be alias everything and import as little as possible. And that way you get a lot more clarity just as, as you're working day to day about where things are coming from. But I could also see now that you're talking about this AST, when you're looking at the AST for a function that's been imported. You no longer know where it came from. Is that kind of what you're saying? There is like, is now a function that's been imported and you don't really have the same level of detail of where it came from. Marc-AndrŽ: you don't know which function it is. In a sense that, if I do use something, maybe that use does a bunch of imports, and then afterwards I'm calling this function foo, I don't know which module it's from I mean, when we compile it, you know, Elixir will know exactly which function it is. But if we only look at this particular source code, There's just one single file. We don't really know which foo it is. So, and that's, that's trouble. Owen: and I see you're nodding renee, so is this a pain point you've experienced working on Credo? RenŽ: Well, I think it's, just something we're sticking because there are certainly some challenges which would be easier to solve if we would be looking at the object code, meaning the compiled beam files. And the most obvious downside from that is that if the code doesn't compile, you're not going to run any kind of analysis. And I'm also not sure if it's In all cases, slower because you have to compile as a first step and then run the analysis on the, beam file. So there is some argument to be made for static analysis and looking at source code because it's super simple. You can integrate it in other processes, you can write a language server, you can do all those things for interoperability, and I think that's very much an upside you can't ignore. But on the other hand, if you have a, put in or map function or something, you don't know where it's imported from. It's just, yep, I'm pretty sure this is a function call and I can't say anything else. Dan: So Renee, are you seeing, or have you seen in the years working on this changes in the Elixir language that have helped or hurt this effort? RenŽ: I wouldn't say Dan: Okay. RenŽ: Neither way, so it's actually that I'm pretty impressed how, how few changes are necessary to Credo with every minor release of the Elixir language. We're sometimes having things like the new requirement in Elixir 1. 16 for negative step functions to be I can't really remember, explicit or something. Where we had to do some backport magic, so that we can still support Elixir pre 1. 12. But it's also amazing that, that you don't have to make a major rewrite. So Credo is eight years old, I'm not even sure which Elixir version was, was the most current then. I think it was 1. 2 or 1. 1, something like that. And basically, we did not really change that much to keep up with the development, but it's also not like I Or anybody, uh, responsible was ever super tempted to say, let's throw everything overboard, let's make Credo 2. 0 with no backwards compatibility, because then we can use this new feature from Elixir 1. 14 or something like that. And that is also, I think, an interesting aspect that Elixir in, in, the stewardship that the language receives from, uh, Jose and other core maintainers. And how carefully it's evolving is, I think, handed down as a, as a culture to some of its tools. Owen: Yeah, I think. So Dan, I know, we're both basically web practitioners, we're building web apps. We're not so much working in low level tooling typically. , And I'll come back to that in a minute, but I'm curious since you've written more Ruby than I have, and I've written a little bit. Yeah. More elixir. Do you have like a favorite, RuboCop alert favorite in quotes, like when they get you all the time? Dan: I was, gonna say the thing I feel like I see most often was going to lead to my kind of the similar question to Mark Andre, which is, I feel like the thing RuboCop yells at me the most about is often, you know, the exact point version of Ruby, not matching the gem that's installed or what have you, because I believe that the AST, I guess, is either changing so much or, or whatever makes the, the Ruby version matter quite a bit to, , what RuboCop is doing. Um, Marc-AndrŽ: Yeah, it's true. I mean, you're, you only get one warning though, and it's, Dan: What's the first thing you see? Marc-AndrŽ: it won't, complain too much, but it's true. so RuboCup based on the parser gem from WhiteQuark. So that's not the built in parser. There is a built in parser in Ruby, but it's, it's just not very good. Um, and, uh, the whitequark parser is just simply amazing, and they just want to make sure that they get everything. Completely, totally, perfectly accurate. So even a 0. 1 release is going to be like, Well, we're not quite sure that we match the AST. But yes, every, as far as I know, every single, uh, release of Ruby, so once a year, there are syntax changes, and those will always have an AST change. And the parser gem aims to be 100% Compatible. So it's going to be new nodes or, or something so that it doesn't, uh, the, the AST from previous versions for the same code doesn't change. Only the new code that wouldn't even compile in an older version of Ruby will have a new AST. it's a hundred percent, compatibility ensured. Yeah. And I, it's true that Elixir has been I've only been here for three years, but it's like rock stable on that end. Much easier, job. Dan: Owen, I think back to your question, I feel like the thing I see from both tools probably the most is like just complexity checks. Owen: Bingo That's The one you were reading my mind That's so yeah, my favorite quote unquote favorite credo alert or warning is cyclomatic complexity which you know, when you're a junior, you're spending like probably 10 minutes on Google Like what does that mean But, this is one of those rules. So I love credo I think we touched on this earlier. It's configurable. We could just turn this alert off and say, I don't care what things will be as complex as possible. And you know don't worry about it Credo but I like this warning because it usually forces me to kind of rethink usually it's a big con statement, right? So like in Elixir we have a few different flow control mechanisms. Cond is kind of like a big branching logic tool So whenever I've got too many different cases in there, or, there's too many kind of and ors that really blows up the complexity and credo likes to tell me that I'm a bad programmer. And that's when I go back and like usually the way I solve this is pulling things out into separate functions So I can use pattern matching Renee, did you write that check or, was that a community contribution I'm curious if you have some kind of other insights from the tool perspective about cyclomatic complexity RenŽ: Well, point in the very early of, of the Credo project was for one to, think about which checks I personally really wanted which were sort of the, Table stakes, I need this kind of check to complain it. And that's the reason why there is a max line length check and a taps versus spaces check and the cyclomatic complexity check. I think all of those are very much debatable. The last community event I went to was It was a code in Amsterdam in the fall of 2019. And I gave talk that basically with me complaining that code analysis tools are all garbage and I them. But one of the reasons why they are all like going on our. sanity heart is because we don't them tools. We use like oracles for guidance. Just because there is some check that's always complaining doesn't mean that I'm doing take the second and think, I hate this check. It doesn't make any sense for me and my code. And I should just put a general config in my home directory, which disables us for all my credo projects by default. Marc-AndrŽ: I want to say that, uh, when I started contributing to RuboCup, RuboCup, you know, does, dogfooding. So, I think all, if not, at least most of the rules of RuboCup are enabled for RuboCup itself. And, there was so many times I would be like, Oh my God, why is it complaining about the length of this, this method? Because the length is actually set, in my mind, to something very, very short. And I actually, well, I had to follow the rules because it's not my project. I can't just decide to change the rule or something like that. But I must say that after a while, it actually made me change my style. And I started actually writing more smaller functions and naming them. And I actually started liking the way It read when I was actually reading the code afterwards. Early returns were another thing in RuboCop that I started using. I mean in Elixir it doesn't make sense, we don't use that, but I must say, I was very skeptical about some of those, checks in RuboCop at first. Uh, but I think my style improved because I was actually forced , to use some of those, checks. But I've actually not run into Cyclomatic Check in Elixir yet, so I'm a bit surprised. Owen: Your control flows must be very pristine then Dan: I don't think I see it in Elixir as much as Ruby. I think there's something about pattern matching that just lends you to. Build things in a way where I think you're less likely to do it. But I think in that kind of like early draft of something, you get too many nested conditionals, too many nested case statements, and it'll, it'll scream at you. And it's kind of one of those things where you're like, okay, I know I'm wrong, but like. I'm just going to deal with it for now. And then I'm going to come back and do it . But I think, to kind of both your points, like that early feedback , you know, and, kind of informing the design, you know, you do end up in a better place and it's, it's kind of that thing where you, it can frustrate you, but at the end of the day, it gives you consistency on a project and it can really kind of help. I was curious if either of you have seen maybe common rules that aren't part of the default set, but you see organizations or, or projects add on their own, often, , I know at least there's a plugin system for both, because I think there's lots of plugins for, for RuboCop to add like RSpec and cucumber and all sorts of other things. But maybe starting with Renee, is there something that you see get added to credo a lot, but is it in credo core? RenŽ: Well, I think if I would see it, I would encourage people to contribute it. But since there is no telemetry in, Credo that, somehow tells anybody People are using these custom checks, these plugins, these rules, or even this, this config, so I wouldn't know which are the most disabled checks, which is also the main I am hesitant to, for example, deactivate cyclomatic complexity by default and put it so that it has to be enabled because you don't know who runs into which predicaments if you just change the default set of checks that are running in, preferably a patch version. Yeah, so I think, people are building plugins to deliver custom checks to all their projects, that's a discussion I've had on Twitter and GitHub several times, and I guess more people are building small Credo plugins than I would know. Owen: Yeah, I think we, we see some of these on hex, so if you, I guess if you or your team builds, and I mean, I mean, like Renee, you, but I mean like the Royal, the listener if you build a custom credo check and you're like, Oh the world would benefit from this One option is, , hex dot publish Owen's great credo checks. Another option is go to credo. The repo open a PR, maybe an issue and discuss with the credo maintainers. Like, should this be part of credo, Standard, what, what's your preference for ideas? if people are thinking about checks that they think should be in core, how do you, prefer to be approached about those types of ideas? RenŽ: So there is actually a separate repo for proposals, but it's linked , in the main credo repo when you create an issue and I think I just want to encourage people to, to contribute their ideas in, in form of an issue or, a suggestion, a proposal, because I think we have merged much, many more checks than we have sort of discarded and, and said, well, thank is useful, I can see it for your organization, but I don't think it's, it's something we should include , in the, , standard credo set of checks that has happened, but It has more often been the case that we slightly modified it to it then merged it into greater core, so to speak. Owen: Yeah I think something as a primarily elixir developer something I really appreciate is The language, a lot of the packages that we use, especially the most popular packages are extensible So if there's something you want and you can't wait for someone else to build it you have mechanisms to write a custom credo check or to Extend the functions that are already in place to add a little bit more functionality. So is that something that, you can kind of do with Rubo cop as well Marc-AndrŽ: There are checks for Rails, RSpec, Cucumber, and it's actually very easy to write your own checks. One of the things that makes it quite easy is that, there's a, some kind of a, a little bit like a grep, but for aST. In RuboCup, , which is One of the things that I rewrote, , in the RuboCup AST. So there's basically a way to say, I want to figure out every single call where, a method of this particular name is called with as many arguments you want, but second one or the last one must be a literal integer or something like this. To actually do this. is very, very simple. In Elixir, it's not bad the AST is kind of simple in a way, so you can do pattern match. But, , one of the issues that the AST is, just a little bit too low level in a way. So, just, what I mean by this is, for example, the pipe operator is really just a, different way to write a function call. At least. In practice, in theory, it could be anything you could redefine it to be anything like you want. But, it's, it's kind of a pain that if you want to write, hey, I'm just curious, any call to this particular function with any particular form, you kind of always have to write at least two ways. , two pattern matches. One for, is it called with the pipe operator, and another one, is it called without the pipe operator. So, there's this, cup in Credo that will check if you're calling map and then join, which I always forget that there's map join, so thank you for this check. But that particular check has like four different patterns. because you can call the map and then you can call the join like with, the normal call with parentheses or you can call the double pipe or you can pipe the first thing and then not the second one or pipe the first one and not the second one which you really shouldn't be doing but I mean you can write it this way And that particular check actually doesn't even check for four Which would be another way to write your map and if you Imported enum and then you just call map and you call join that check will also not find it so you have to write four patterns For that particular check and it catches only a certain percentage of those instances, so that's the that's why what I mean by the AST is kind of low level, it would be really nice to have a little bit higher level, which is here we're calling this function called, you know, map and join, and we don't really care if it was called with a pipe operator or just with a simple dot, , but the complexity of actually generating that AST would be pretty big. I mean maybe we could just eliminate the pipe operator and then, you know, not care about everything else, but there's lots of different issues like this, you know, Owen: Ooh, you're going to start some drama We're not going to tell anyone you said get rid of the pipe operator Marc-AndrŽ: Oh no, that's, Owen: There will be a. Marc-AndrŽ: that's not what I meant at all. What I meant is the AST generated code that has the pipe operator before we want to run it into credo, for example. it might be a good idea to simplify it or at least have another version where we're like, like a semantic AST where we don't have any pipes anymore. They've been replaced by the non piped version because we want to analyze it on a slightly higher level where we don't really care if you wrote it with a pipe or not. We just want to know what you've called, and ideally if we could You know, we could know exactly which function you're calling. Is it enum. map because it was imported, or is it, you know, was it written enum. map, that it would be with all the function calls, resolved, but that would imply looking at the beam file. I mean, it's, the complexity of doing that is, , super, super high, but until we do then it would be very difficult to have some kind of an easier way to have a pattern match to write custom cups. then the other thing is, Since you both, , Dan Owen are doing a lot of web, you probably generate lot of heeks. And, well, heeks is not parsed, correctly, not correctly, but it's basically just oh, we're calling this sigil called capital H And we have this huge string And that's it. It's just a string. It's completely unparsed where that's not really what we want, right? We would want to have some kind of an AST for the Higgs file so we can actually, Analyze that if we wanted to But right now like without any further tools, we just Can't do anything with it. So we have to do like a grab search if we want to look for anything in particular in a HEX file, which is, well, not what we want. Owen: So I, it does seem like the Phoenix HTML, library or package has some understanding of HTML structure. It will report errors whenever you're missing a closing tag. , or if you got some incorrect syntax in your HTML inside of a Heeks template it can support SVGs other types of markup as well. Rene is there it doesn't seem like Credo really has any understanding of, Heeks though. Is that true? Or am I way off base with that? This RenŽ: No, that's, that's basically, an insufficiency from the very beginning that we never were able to pass Phoenix's view templates and say, look, we to be able to provide people with even for custom checks, give them a way to say, we don't want to use this particular helper maybe even our own, because we did some stupid stuff there and we have to leave the code in, but want to discourage using it on new PRs or something like that, just because of what Marco Andres said, there is no, AST representation of it It's also funny that in, in so many, domains, uh, the community ends up building sort of alternative AST parsers. So, I've seen that in Ruby, I've seen that in, TypeScript, and I've also seen that in Elixir. Owen: I'm talking about sorcerer. RenŽ: Yeah. And I've, I've naturally thought about, writing my own, because, I'm still, an engineer at heart, but, that I also have a family and a job, and, Yeah. Owen: 24 hours a day. Okay. Well, you know, to each their own, I guess. RenŽ: Which brings us to the sponsor for this episode. Yeah. Owen: drink unnamed unpaid sponsorship yeah, so I'm glad we're on ASTs. Typically my work focuses on building features for web applications. , over the past year, I did release a, , kind of alternate authentication, Package. And this summer I wanted to take a similar approach to the Phoenix Auth generator where you could run a command and generate a bunch of modules and files so you wouldn't have to hard code all the stuff as a user of this package. So that was, over the summer, that was the first time I was really getting into the weeds with the AST. Before that it was, you know, it's simple, maybe a little bit in hindsight. I mean it is a fairly simple data structure but it is nested data structure so it can be kind of imposing to look at, especially the first time I'm kind of curious what, does, and I, I am using sorcerer cause I think it has some kind of niceties some kind of helpers there I think I could probably do most of the things I was doing with the default , Elixir standard library now but are there particular features with sorcerer that you see as, as adding value over the standard lib? RenŽ: If I remember correctly the The one, which also prompted the creation of Sorcerer with the inclusion of comments, right? Owen: right comments, Yes. It's aware of where, of when there is a comment in your code and we're talking about like, hash text outside of the doc tag, essentially So like you write some notes to yourself, like, Hey, I should probably fix this later or Dan don't worry about this It's going to be okay And then you write your messy code and sorcerer can actually take that comment and even after the AST is parsed it can make sure it lands back in the right spot RenŽ: Yeah. Owen: to like to put it in layman terms Marc-AndrŽ: So one thing that's interesting for me to compare AST built in in Elixir and the wonderful AST that the parser gem generates for Ruby is The AST for Elixir really was built for the compiler. So, for example, comments, we don't care about comments. just discard because, well, compiler just ignores which makes a lot of sense. And many literals are, you their own AST is themselves. So if you have 42, well, the AST is 42. You have , an array, well, you know, the AST is going to be that particular array. So function calls are the, you know, the ones that get modified the most. And and tuples, You know, bigger tuples , than three, three or more are also changed. But, in, Ruby, every single thing is, you have an object that is, You have a node, so it could be an integer node because it's a literal and it's 42. And the value, type int, and you have all the source map. So it knows where started in code, where it ended. So you want to go, you know, I was talking about getting higher level , than the AST that is generated. But sometimes you want to go. So, you want to know exactly how that 42 was written. And, , in Elixir there's just no way. So if you wanted to write a check that every single Integer that is like a literal integer in the code if it's higher than a thousand you want to enforce that there's like Underscores for readability. You just can't you just I mean you cannot do it currently with credo or with anything because you when you parse with elixir then you only have the integer. So you'd have to check on which line it comes from to figure out exactly, how it was written, because you don't know how it was written. thEn if on that line there's different instances, because I don't know, someone is writing some kind of tricky code and part of that is in a string, then like, good luck figuring out how exactly it was written and where it comes from. And in Ruby with this beautiful parser gem, it's trivial. You just look, oh, I have this literal integer. I can check the value. The value is greater than a thousand. Okay, I want to check. What's the source? And then you, check if the underscores are there, where the, you want them to be. Owen: excellent Marc-AndrŽ: So, it's , this, idea that you want to have an AST to compile the code is one thing, and you want to have the AST to have the complete full picture of what both the source code was like and what it means, that's a completely different thing. And really we don't have the later in Elixir. It would be really nice if we did and I think Sourcer wants to go a little bit in that direction, but we're still pretty far. Owen: Is that possible in Credo? When you get an AST, do you also get kind of the raw string so you could check for the number formatting RenŽ: Yeah. so, we, we do actually have that check with the underscores in the numbers, but since we're using some heuristics to determine if we are on, let's say the right line and if we are looking at the right, occurrence in text. This check also has a lot of tests try to minimize false positives because it's not like deterministic that we are really looking at the 12, 000 that is formatted wrongly Dan: combining the AST and the actual file, just text. RenŽ: Yeah, we're combining, I think, the AST, the token representation and the binary of the file. So the string, we're making string comparisons, which is like not really super good. Marc-AndrŽ: I actually didn't know there was this check and I'm, I'm actually impressed you implemented it because it seems so complicated to do with the current information. I see it's like 250 lines of code. , but I mean, kudos. I'm impressed that it exists in, in, in Credo. RenŽ: Well, one thing with, these kind of checks that I try to do is they, they should, if, if they're not 100%, they should yield false negatives rather than false positives, because I think people would be much more frustrated by I, I did not do the thing this is telling me I did. If you had a string where a number is contained and you would, , complain as a tool, hey, this number is formatted, , in the wrong way, and you're thinking, gosh, this isn't even a number, how stupid is this tool, then I would always err on the side of caution and say, let's, let's risk some false negatives, but avoid false positives, because I as a programmer would be so annoyed by by that. Dan: So kind of carrying on from that then as far as like frustrating or helping the developer, you know, Renee, at the top of the episode, you mentioned , it's a tool. It's supposed to help you. I was curious if you have thoughts on, , integrating it into workflow, where you see it fitting, working with like CI integrations, when you? say it's a tool, what does that mean to you? RenŽ: Well, I think it means that it should give people a sense of, for the lack of a better word, empowerment to enforce the rules that are really, , worth enforcing Because I think there are these effects that Marc AndrŽ described, when you have a really good code base that is just bit particular about certain things, and you have to find, your footing before it becomes your second nature to write code in a certain way, to structure code in a certain way, then that is, at the end of the day, probably a net positive. But I've also worked on code bases where there was in, in my mind, a lot of cargo culting and every time some young IT service firm says, Oh yeah, we have a style guide. We just took the Airbnb or the Google style guide, and then we modified it to our liking. And when was, . A bit younger, and a bit more cynical, and, , not yet a father, and did not realize I have to be a role model in certain situations. I always ask the young engineers, , what the, the third check from the top of the file does, they enabled so bravely. And most of the times they couldn't tell me what all those checks did. So I think the, the most important thing is that It's a tool, and you have to use it with a goal in mind. I'm not buying a kitchen knife just because I call in now I get three more for the same price. I, I buy a knife to cook something, and I should have an idea of what I want to cook, otherwise I cannot choose a knife. Dan: Marc-AndrŽ, do you have anything you'd like to add to that Marc-AndrŽ: I, I have many knives, actually, and I agree that you, you want to avoid the frustration of having, , false positives or anything. There's just like, why? But then again, there's definitely some rules that No one is ever going to agree on, sadly, there was endless discussions , with RuboCup about which rules should be, and sometimes I would come and I would say, Oh, I completely agree with this rule, except it should be reversed. Instead of saying don't do this, do that, I would say no, don't do that, do this, just to show the extent of how difficult it can be to decide which way, something can, can go. Uh, I don't know if there's any Credo rules that are like this, actually, where you have to choose Owen: a wonderful retreat Marc-AndrŽ: which style you prefer, RenŽ: there are a couple of consistency checks. Where you have to, for the, the most obvious one, tops or spaces for indentation But with a, with a standard set of checks, and the fact that, , people are not happy about one, or two, or three, or all the checks. I'm always reminded, about a quote I read from the inventor of C who famously said, there are two kinds of programming languages. Those people complain about and those nobody uses. Dan: I think that's, that was something I think, and I guess it's the heuristics aspect of, of Credo that works really well in that, right. Where it's like, it will tell you this is different from how you've done it everywhere else. Not that you must do it one or the other, but it's just like, this stands out. And I think as a, developer, especially on a, if you're bringing it to an existing code base, like that's a much more kind of gentle, like, Hey, I'm not telling you you're wrong. I'm just telling you you were inconsistent. And there's an approach that I think is really. And I remember having like, warm feelings about that, you know, in early, early days with Credo. RenŽ: It was also one of those things I, I could not have forced in, in the dogma code base in my mind, because I, for those checks, we, we have to, have a runner that can differentiate between running it on a single file or running it on all the files, because he's looking for consistency. And I think today we, we even have lowered that barrier, but in the early days, that was something where I thought, like, I wonder if I pull this off in, in a way that's actually usable. Owen: so if I understand correctly, what we should all be doing, all the listeners and all the companies who listen to the podcast should go out and create their own Credo config, like SmartLogic Credo, and then release that so everyone else can CargoCult. That's the point you're making, right? RenŽ: Yeah, and you should definitely, the first step is to run mixcredo, uh, dash dash first dash run, because I think then you, can also get some help around that. Owen: All right. So you heard it here. We're, we're all going to be cargo culting our credo and RuboCop rules. That's 2024 static code analysis cult we'll see who comes out on top Dan: I hope everyone can hear your sarcasm. Oh, I really do. produced and Owen: What are you talking about? I'm totally serious. All right. I think we are out of time. It's been great. analyzing our code and thinking about how these tools actually work. I personally, and I think I can speak for the team I work with as well, like we our code base is improved by having these checks, whether we're working in Elixir with Credo or Ruby with RuboCop, makes you think a little bit more deeply sometimes when you're in a hurry. So I think that's helpful as well. thank you for your contributions to the community. Both of you, before we go any final plugs or requests for the audience, we'll start with Mark Andre. Marc-AndrŽ: no, none, Owen: Do you need more knives? All right. And then Renee. RenŽ: No. Owen: All right. We'll keep your knives to yourself. thank you both for joining us and, we will be back next week with more Elixir Wizards. RenŽ: Thank you, bye bye. Marc-AndrŽ: Thank you so much. Outro: Elixir Wizards is a production of SmartLogic. You find us online at smartlogic. io, and we're at SmartLogic on Twitter. Don't forget to like, subscribe, and leave a review. This episode was edited by Paloma Pechenik for SmartLogic. We'll see you next week for more as we branch out from Elixir.