A book club for developers.
BookBytes is a book club podcast for developers. Each episode the hosts discuss part of a book they've been reading. And they also chat with authors about their books. The books are about development, design, ethics, history, and soft skills. Sometimes there are tangents (also known as footnotes).
Adam Garrett-Harris
Jason Staten
Megan Duclos
12/17/2018
(Intro music: Electro Swing)
Hello and welcome to BookBytes, a book club podcast for developers. We’re continuing our- No, it’s not even the Summer anymore, we’re like, into the Fall with this Imposter’s Syndrome. We’re talking about The Imposter’s Handbook: A CS Primer for Self-Taught Programmers by Rob Conery. So we’re gonna go over the last two chapters, chapters 14 and 15 which is “Testing” and “Essential Unix.”
I’m Adam Garrett-Harris.
I’m Safia Abdalla.
I’m Jen Luker.
And I’m Jason Staten.
So, we’ve been doing this book news section and one we haven’t mentioned yet is the sequel to this book is coming out, which is Season Two of Imposter’s Handbook and it’s for sale right now, currently in presale which means you can read it in advance and then submit issues on GitHub if you see any problems with it. And it’s written by Rob Conery and his friend Scott Hanselman.
I’m excited.
Yeah! Did you look at the topics?
I did once before and I do not know them off of the top of my head right now but I know looking at it I was like, “All right, I’m ready for this.”
Yeah, it looks like he’s doing a real deep dive into information flow all the way from binary to encoding and network protocols.
Nice!
Yeah, so I’m pretty excited. We, I don’t know if we’ll talk about it on here yet, but it is available for people to read.
Yeah, we’re already lined up for the next one.
Yeah! So I should mention that. Our next book is “Code Girls.”
I’m pretty excited about that one.
Yeah. Yeah, do you want to give a quick explanation what that’s about?
No.
No? (laughs)
(laughs)
So that’s about the women who helped crack the enemy codes during World War II and yeah, I’m pretty excited about that, too.
I didn’t give my description because I haven’t started reading it yet, so.
(laughs) I mean, yeah. I’m… I’m into it, I don’t know how far, but it’s kind of a long book.
Hmm. But we’re breaking it up though, aren’t we?
Yeah, yeah.
Into not chapters but…
Parts. I think there’s three parts.
Yeah, three episodes.
So, let’s get into testing.
(Typewriter Dings)
This is definitely an opinionated-
(laughs)
Topic in the industry, for sure. And I guess, sound off real quick. Do you do test driven development and with that is it all the time, some of the time, or rarely if ever?
Some of the time.
For me it depends on the context and the open source project that I work on. We’ve got pretty heavy test driven development going on, good coverage and all that. At work I think it depends on a lot of different factors and tends to be like a personal choice with the developer, but we do have things like tests running on pull request filters and tests on pre-commit hooks and pre-push hooks and stuff like that. So there’s like, set up an infrastructure for it but it’s not like a super strict, “You have to put in a test first and then start coding.” It’s just, “You should have a test with every pull request you merge.”
Yeah. So for me at work we do test driven development almost all the time. The exception is for things that are harder to test or would be more fragile like how the UI looks. So all of the backend is TDD and in the frontend where it makes sense. What about you, Jason?
I would say that I fall in somewhere between that sometimes, not too often. I used to be more of an advocate of it, and like, I guess more of a practitioner of it and that kind of fell off as time went on. Like, I guess when I was writing Ruby it was just what you did and so that’s what I did and a factor in that was that with Ruby because when you have so many dynamic features related to it if you are not running a test suite then you will find all sorts of issues at production time and so, it was really necessary. ‘Cause it was like, full on spell checker. Like, if you typo’d something you would not know until your code was executing whereas in other environments you have a little bit more help from the tooling on that. And so it’s led to probably a little bit more lax standards than where I should be at, but that’s my realm.
Yeah, I feel like things like TypeScript or aesthetically typed languages really reduce the number of tests you need. So with JavaScript you might have a test that ensures that it returns a number or something and you don’t need those kinds of tests with TypeScript.
Yeah, that’s a thing that I’ve really liked about working in Rust over the course of this book, has been its type system. It’s pretty rigorous on many of the things that you’re doing and not doing. It’s not even just the semantics of like, are you returning the correct type but also are the contracts you’re making about like, are you going to mutate this data? Or like, if you’re trying to mutate data but you haven’t said that you want to then the compiler will actually prevent you from doing that. And so you get a level of guarantees that just come from the tooling that you don’t actually have to write a test for. And so it’s not that you don’t have to write tests but you get a good number of them checked for you all the time just as you write and compile the code.
Yeah, that’s a good point, Jason. And I think it touches a little bit going further into the chapter on the distinction that he provided between behavior driven development and test driven development with the notion that, you know, when you’re writing a test using TDD you’re generally doing something like, testing all of the inputs, testing different values, all of that stuff. It’s like, very, I think the word he used to describe it was clinical. And when you’re doing behavior driven development, you know, you’re testing kind of user workflows, and I think one of the things with TypeScript is that it takes away a lot of that clinical checking that you would have to do in tests like you mentioned and it puts it in the type checker.
And that’s why as I was reading this I realized that nowadays when I’m writing code most of the tests I’m writing are not like, tests as in the TDD style but more behavior driven tests like, testing out the full user workflow for a feature that I’m adding, and that tends to just kind of fit better in with the way I develop software. So, you know, you get assigned a task to do and usually the task is “add a feature,” and when I’m adding a feature I think about like, the full user story and the behavior around it and test that, but not necessarily test like, “Does this button render this way when I do this?” Or, “If I pass null to this will it do that?”
Hmm.
Yeah. When I think of behavior driven development I think of the idea that the names of the tests should be readable to a stakeholder. And I think he mentions in the book it’s very rare for a stakeholder to ever actually do that, like nobody exports the names of their tests and then hands them over to a business person and then says, “Here’s what the code does.” But it gets you thinking in more of that mindset, I guess.
Yeah, and I definitely do find myself thinking in more of that mindset, like around business logic when I’m coding.
Now are those still unit tests or are they more like integration or acceptance tests?
The way I’ve written them they’re set up as unit tests, a few of them are integration tests just ‘cause they made sense with the existing set up that we had, but yeah, for the most part they’re unit tests.
Cool.
I do tend to think of them as being something that’s a little bit higher than unit, at least like, when I hear the comparison of them. And maybe not full on integration, like starting up your whole application, but the thing that I like about doing that sort of style, like testing multiple pieces or like the bigger picture of things is it gives you more flexibility when you’re writing code, and I guess in particular more flexibility to make changes to your code. One thing that I’ve run into before with doing test driven development is because the model of my coding was driven by all of my tests when I was to go back and make changes to my code, any time I would do that potentially you would get like, 10 tests failed because I went and removed this line. And it’s kind of discouraging to have like, a whole bunch of tests fail just because you changed like, one thing.
I mean, it’s good that they’re there and they’re checking it, like that’s what you want. But at the same time, like, the amount of maintenance that can come from a test suite made it that way can be burdensome. And I know that if done properly, like, it should be straightforward but I maybe hadn’t gotten to the point of doing it quite properly, but doing some of those slightly higher level, or behavior style tests where it’s like, these things need to happen, but the details are a little bit less important and may not be asserting on those, but like, as long as I give this input and get my desired end goal output in terms of more feature or behaviorish, then I’m happy. And you know, the details can slide a little bit more.
Yeah, I’ve had that kind of issue. Typically when that happens it means I’m testing something that should be like, a private method because it’s just implementation detail and I’m tempted to want to test those things because it’s part of the code that I’m writing, but really, if it’s not part of the API or something I shouldn’t be testing that method, probably.
One other thing that I came across during the process of doing Rust, and I’ve seen it in the past as well with other languages, and it’s called QuickCheck, which is for property testing. And I think I originally saw it in Haskell, but QuickCheck is a way of saying that I want to test the method and assert some property about it. Like, for an example, if I were to go and create a reverse function that reversed an array then I could go and say that for all inputs that are an array that if I reverse it and then reverse it again, it will be equivalent to the original input.
Hmm.
And so what QuickCheck will do is it will call your function some number of times, like a huge number of times with a whole bunch of randomly generated inputs, and if it succeeds then you just get like, a passing test. But if it fails then what it’ll try and do is actually reduce the input set to the smallest possible reproduction case. So that way like, if it fails with a list of 1,000 items in it, it may just be that your reversal algorithm doesn’t handle having nulls in the list or something like that, and it can boil it down to like, that “It’s having null in here that is actually making the failure case.”
That is interesting. It sounds a lot like in Elm, there’s a thing called Fuzz Testing.
Mm-hmm (affirmative).
And you kind of just say like, “Hey, run this test 100 times with various inputs.” And then if it fails you can see why.
Yeah, that sounds really similar. I used the same mechanism for testing when I was writing the various sorting algorithms for earlier in the book to assert that any of my sorting algorithms, whatever output they produced had to be the same as whatever the built in output of Rust built in sort was.
Hmm.
Because I assumed, like, Rust’s built in sort is going to be correct.
(laughs)
Like, if not there’s something seriously wrong. And so knowing that I am fallible and likely to write an algorithm that is not quite right, if I go and put QuickCheck against it say, for any given input it needs to match the Rust implementation then I know that my implementation is true for that property.
So, I want to ask y’all, for those of you that don’t use TDD very much, which I guess is all three of you, why not? I guess I should say who don’t use it all the time.
Yeah, I would say for me sometimes it’s like, things need to get pushed out the door really quickly ‘cause there are deadlines and there’s just like, no time to test. And I know this sounds bad and terrible and all that, but like, usually they’re kind of the first thing to go or, you know, you’ll add tests later but it never gets done, things like that. And usually it's just like in situations where there’s urgency around getting something shipped and there’s not a ton of time to be like,very formulated about it. I would say that’s one example, and other cases mostly it’s just been like, the testing infrastructure isn’t there. You’re trying to test this new component or interface and like, you don't know how to set up the mocks properly because no one’s ever done it before. And there’s all of these weird, like, modules being injected and how do you test that?
So just like, sometimes, the setup for tests isn’t really well done and that discourages you from writing the test because well, now you have to go out and like, set up your testing environment before you can even actually get to work. But other than that, if I know, like, a test is going to be easy to add or I know what I need to do to actually like, set up a unit test and like, I’m in no rush to get something out the door, I’ll do it.
For me, it’s not that I don’t do it all the time, even though it’s not really all the time, it just depends on what it is I’m writing. It just seems like not every single bit of code needs to be unit tested. It’s mostly the crud functions that most specifically need it more than, I don’t know, a small little function that doesn’t really do much.
Yeah.
Yeah. I think trying to achieve 100% test coverage is not… not good.
Right.
Yeah, I agree.
So, for me it’s more like the test driven development happens much more efficiently and much more effectively if I know what I’m writing is going to be larger than a 3-line function. So-
Mm-hmm (affirmative).
It has to do with the purpose for the test. It’s not just for testing the method it’s for making sure that what you’re writing is also clean and efficient and doesn’t include a lot of extra code that you won’t necessarily need. It’s about trying to make sure that you only write the bare minimum of what you need in order to get a test to pass, and then making sure that it fails in the right spots, too.
Mm-hmm (affirmative).
So it just seems like, for me, it’s more to do with complexity of the thing that I’m testing than it does with the function of that class or object or function.
Cool.
I’m kind of in that same camp of not having quite the same infrastructure, or correct infrastructure to build out stuff well. Like, sometimes it is the mocking story and I know that like, that is a sign that whatever thing that I’m depending on may not be correctly, like, isolated or something like that.
So like, if it’s hard to test then that may be a sign that it’s not designed well? Is that what you’re trying to say? Or…
Yeah. I would say, like, if your code isn’t testable, like that can be, it can be sign. Like, it doesn’t necessarily for sure like, say like, “Oh, this is poorly designed.” I mean, sometimes there are things that are difficult to test and have to be for one reason or another. I mean, maybe they’re just inherently complex or involve a lot of dependencies. Maybe it’s like an orchestration type class that pulls in a lot of stuff. Then yeah, that can be pretty painful to test.
I actually find myself blaming, in particular working with React during the day, I find myself that I don’t really enjoy writing tests for React. When it’s a small project it’s not too big of a deal, but like, if it grows and it’s something that say, has like, Redux and internationalization and other things that involve React-like context, making those tests and like, the setup process for them is just a pain to deal with. And please direct me if I’m not right on that front, but I find myself more prone to writing tests for if I’m making a just straight JavaScript module that has a bunch of more, like, utility-esque functions that take in an input and give out an output. I am more apt to actually go and do those TDD. But with React I find that it’s painful and it doesn’t excite me to actually go and write the tests. I’m like, “Oh what’s all the boilerplate that I have to write to even make this thing successfully run?”
And then the other thing, too, is a lot of times, at least in the way that I try and write my code, is that there aren’t too many branches and conditions so it’s basically just asserting it like, if I set this prop on this thing, like, it’s gonna render this way.
(laughs)
And that’s that. And then I feel like this is a super valuable test.
Yeah, but then you don’t want to test like, “Oh, the background color is this, and the borders are rounded, and how’s this text?” Because-
It’s-
That’s gonna change all the time.
Yeah.
Yeah, I totally agree. With React it’s not fun and probably not necessary.
I still feel like there has to be some sort of… I mean we have different types of tests for reasons, right? Like, we have our unit tests for trying to make sure that the complexity that we’re coding is limited, whereas the other tests that we’re writing, such as behavior driven, would be much more closely related to like, crud processes making sure that what we’re coding actually functions the same way in the long run. So even if we go in and modify our code to be completely different and fail our unit tests, it may still pass our behavioral or functional tests because of what we need it to do is still the same. I feel that no matter what, you need to have some sort of behavioral tests when it comes to your crud processes. Crud being like, create, read, update, and delete.
Yeah.
Whereas the unit tests are much more for us and making sure that our complexity stays limited.
Yeah, and I think that’s why oftentimes the things that I see most unit tested, like Jason mentioned, are things like, utility files where you’re like, checking that something formats a date correctly or makes some kind of, like, numerical computation correctly as opposed to like those entire behavioral workflows.
Yeah.
I’ve talked about Gary Bernhardt a couple of times because I really enjoy watching his talks and screencasts, and one of his screen casts that he made was one that was called “Functional Core, Imperative Shell.” And the idea was that you have, kind of two different segments in your application, there’s not like a specific hard line drawn, but it becomes obvious as you’re building out different components or different module of your application in that like, the core of your application should be written in more of a functional style where it’s very much a pipeline of things. Like, it’s functions just passing output to other functions and not really stateful. And those types of things are pretty straightforward to test and so, like, you’re able to go and make a nice test suite against them and they're not dependent on external things like databases and whatnot. And so they are also really fast because he’s adamant about having a really fast test suite because slow test suites also are discouraging.
Mm-hmm (affirmative).
I thought about that today because I have been refactoring a massive amount of tests at work. And then on the flip of it there is the imperative shell so it is the code that is very stateful and deals with things like user input and like, database and/or screen output or something like that. And on that side it says like, testing here is, it’s way more difficult and way less beneficial. And so the goal is like, you want to have that core as big as you can, so you can have a like, a thoroughly tested application, but those things on the edges, like, because they’re difficult like the benefit of actually doing it can be much lower.
Yeah.
Yeah, yeah. I really want to take that business logic out of that shell and make them as dumb as possible and just very presentational. Yeah, I like that. That like you can test those things, but it’s hard and it has like, decreasing benefits.
I think like, one of the things about testing your code is you have to like, really analyze and understand the complexity and interconnectedness of how the software you’re working on works to be able to like, isolate things and test them well enough. ‘Cause I’ve definitely seen situations where like, someone will like, write unit tests for something and they’ll like, look good, and you know, you’ll merge them and you’ll go ahead and then like, three months later there’s like a huge bug discovered that those same unit tests didn’t catch because there wasn’t an understanding of like, the complexity and the side effects caused by a particular bit of code.
Hmm.
Like, writing unit tests in and of itself is like writing a feature or fixing a bug. Like, I don’t think it’s just like icing you put on a cake or something like that. It definitely is part of like, the cake batter. That was a terrible, what am I doing with this analogy? (laughs)
(laughs)
I like it. I like it, keep going.
Yeah.
Yeah, but I definitely think it’s like, test code is code in and of itself, and like, architecting it, when we were talking earlier about having good test infrastructure, figuring out when you write test and when you don’t is the same as figuring out when you write code and where you don’t.
Yeah, and refactoring your tests can be as important as refactoring your code.
Yeah. And I think one of the things even when we like, maybe I’m just getting the wrong impression of it, even when we talk about test driven development it still treats tests as this kind of entity that is separate from your code base and like, additive. When really I think what makes it hard is you have to figure out a way to write code that is like, customer facing, and code that is developer facing. For example your tests, this could also be like your configurations and stuff like that, that like, work as one. And when those two things clash together I think is when it gets really hard to write tests.
Yeah, I really like having my test files right next to the thing I’m testing as opposed to stashed away in some other folder that you forget to look at.
Yeah, I agree. And I think that’s one of the reasons that for the open source project I work on has a really good testing culture, it’s ‘cause we kind of adopt that kind of philosophy of having your tests in the same directory as your components or your source files.
So I want to add to that a bit in that one of the benefits of having the files themselves co-located in the same folder, and not just your tests but also your CSS and you know, any other additional pieces that you have and that nesting them is that when that feature no longer used you just delete the entire folder.
Yeah.
So it’s writing code for deletion later.
Yeah. And I feel like this whole putting your tests next to your source thing, maybe I’m just not as experienced with this, was like, kind of a fairly new approach to get popular? Or was this something that was just always done and I was not aware of it?
I don’t think it was necessarily always done. I do think that with increased understanding of Webpack and how it’s utilized it’s starting to become much more popular. Before it was just easier to say, “Okay, it’s in this folder. We’re just gonna do it that way because you can just import it and test it and run it that way.” But I think as people just dive deeper into our bundlers it’s easier to understand.
Yeah.
Yeah, that’s a good point. It used to be easier to say, “Here’s all my test files in this folder. Run those tests.”
Mm-hmm (affirmative).
And tell your bundler, “Here’s all my source files, bundle every single file in this folder whether I need it or not.” So you don’t want to put your tests in there and then ship those to customers.
And I don’t think it’s that complicated anymore. I think the people understand how to set it up initially in a way that you can do both without complexity.
This is another case that I actually get to share a little bit of love for Rust, and that is that you don’t even write your test in a separate file, but you actually write them in the same file as your code. Like, in terms of unit tests, you would go and you’d just make an additional module inside of your current file that you’re working on, generally it’s called test. And it gets compiled away like, during any production build, but it exists during test builds.
And secondly when you go and you set up a new project using cargo, their package manager, it’s got cargo test built into it, so you don’t have to go figure out a testing framework whether you want to use TAP or tape or Jest or QUnit, or whatever other thing that you ought to. Like, they have one that’s just there that’s built in when you start a project. Like, you have testing infrastructure that already exists and you don’t have to make any decisions on that front which is really nice for getting a good testing culture.
I think those two things are really closely connected, like culture and infrastructure. ‘Cause I think when you’re writing a test, like, you’re not just writing it for yourself, you’re writing it for everybody who’s going to be reviewing your PR or touching that code after you. And I always think like, that’s the first… well, I think for anything code related, the first thing if you want to change your code base you have to change your culture first. And sometimes some teams have a poor testing culture, some have a medium, some have a really good one that’s stringent. And I think it tends to be like, super dependent on the business.
Like, I remember one of my first jobs was working at Bank of America and they had like, a really solid testing culture, obviously because they were a bank, but also because they would get audited before every software release and part of the audit was looking through their tests and making sure that like, everything was tested correctly.
And so that kind of like, I guess business climate influenced team culture which influenced how well their testing infrastructure was set up. Like, they had really good testing infrastructure there. I don’t know, we could probably talk for hours about infrastructure and culture and tests and all of that good stuff.
I also want to say that there’s a difference between a stringent testing culture and a good testing culture in that, you know, as we’ve mentioned before but I really want to reiterate it here, that reaching 100% test coverage is really brutal and isn’t always necessary. So there can be cases where it’s too stringent and that makes it much more painful for anything to happen. So I think that separating those two things and saying healthy test culture-
Hmm.
Is better than saying stringent is equal to good.
Ditto what she said, basically. But I agree, I think that it’s not just about the stringent ness. I don’t think anything software related should be judged on how stringent it is because I think that’s where you get into areas that are very dark and not good and bad. But I do think just… There’s a certain level of like, accountability that you have to have as a team to make sure that you’re building a healthy testing culture.
Nice. Shall we move on to Essential Unix?
Yes.
Sure.
All right, but first we’ve got a sponsor.
Yay!
(Typewriter Dings)
This episode of BookBytes is brought to you by V School. Established in 2013, V School is Utah’s highest ranked coding boot camp, and the first of its kind in Utah! They really care about diversity, they partnered with Adobe to provide inclusion based scholarships to foster a diverse workforce. And you can choose to learn full-time, or part-time in the evenings.
You’ll immerse yourself in learning new skills like React, or full-stack development. They take care of everything you need so you can just focus on learning, including free housing if you need it and this is really cool ‘cause it’s just a few blocks from school and you can, or you can actually learn from home in their virtual classroom. You’ll get a super transcript when you finish, it’s like a portfolio, transcript, and letter of recommendation all in one, and it will help an employer to quickly understand your strengths, abilities, and then the work you’ve accomplished.
They encourage you to take a campus tour, meet their students, faculty, and even shadow a class to see if it’s a good fit for you. If you go visit, tell them you heard about them on BookBytes. Check out VSchool.io, that’s the letter “V” School dot io.
V School. Life awaits. Launch a career in code, design, or data. And thanks to V School for sponsoring the show.
(Typewriter Dings)
So, Unix! I always think saying unix out loud is really weird because it sounds like something else.
It sounds like a pokemon.
E-, it sounds like E-U-, how do you spell it?
Mm-hmm (affirmative).
You know what I’m talking about?
Yes.
E-U-N-O-C-H?
Yes.
No. I know the word you’re talking about but I’ve never said it out loud or heard it. So…
Yep, yeah. It’s, a eunuch is a man who’s been castrated.
(laughs) I was not expecting that definition to come up.
You learn something every day.
Yeah.
Moving on.
Okay.
Yes, please.
So what did y’all think of this chapter?
I thought it was interesting. I had prior understanding of a lot of the things that were mentioned so some of it wasn’t, it wasn’t as like, eye-opening as some of the other chapters. But I really appreciated the like, Make section and talking about the history of BuildTools and why most programming languages tend to have their own build tools, because Make came from the deepest pits of hell.
(laughs)
Wait, did it say that in here?
No, that was my language.
So, I’ve never used Make. I’ve heard of Make, I’ve heard of Jake and Rake, but yeah, when I learned about Make in this book I thought, “That’s really cool! Like, you could just use that in pretty much any language you’re writing code in.”
Yeah. It gets really complicated really fast. I remember-
Yeah, I’m sure.
Working on some things and you’d just have like, Make files and you would have to like, track down references within the Make file, and it just got like, really hard to navigate.
Yeah.
Also, I did on the topic of Make, he talks about going and building a JavaScript project with it as an example and that was something that you, I guess, you can still do and did previously used to where he goes and just concatenates all the files together, and it brings you back to the days of like, having a whole bunch of self-evaluating functions wrapping everything ‘cause it all got dumped on the global. And so you didn’t really write stuff in modular form.
Or I guess you did and you wrote it in like, AMD syntax which like, wrapping everything in a “define” or something like that. Like, that’s what that brought back memories of and I don’t miss doing that. Especially because like, you still have, there’s some concerns about like, ordering and whatnot. And like, the solution of numbering things doesn’t really work out well as you really scale stuff out and so it’s actually like, the case where I started to see value in some of the bundlers such as Webpack or Rollup or Parcel or whatever other slew of other ones.
Like, in terms of like, grunt and gulp you could use Make in place of them or NPM scripts for that matter, which is just a task runner that’s even, it’s even simpler than Make ‘cause it doesn’t have like, depencies and whatnot in it. But things like Webpack and the others, they actually go and are parsing your code base and creating a dependency graph in order to figure out ordering of loading of things. And so like, they certainly do a lot more than just going and cancatinating your files together. So I think some of the additional stuff that they do, like the going and minifying after the fact is something that you could go and hand off to like, a piping, like, using Unix Pipes, which, hey we haven’t really talked a lot about yet but we can get into, but you know, like handing it off through that process. That is something you could do. Like, with minification after the fact, but there is value in what they do and like, just substituting Make for it is going to mean that you’re definitely down in those pits of hell trying to figure out your dependencies.
Make is not recommended for JavaScript in 2018.
(laughs)
No.
Totally agree, yeah.
(laughs)
I was like, that’s an interesting example, but I don’t do it.
It definitely is a good way to like, look under the hood of what’s going on in some of the build tools that exist currently, ‘cause I definitely do think one of the like, overwhelming things about BuildTools is that they are a little opaque for some people, especially if you’re like a beginner. So I think this chapter would be really helpful to go through if you just want to like, get a sense of what’s going on under the hood. Or what it looks like is going on under the hood.
Yeah. So I thought this chapter, speaking of pipes, I thought this chapter was gonna be more about really kind of basic commands you would run in Unix like CD and LS and kind of the Unix philosophy of each of these programs or these tiny little programs that do one thing and do it really well, and the open/close principle where we’re not gonna change that program if you want some additional functionality. You pipe the output of that program into another program to extend the functionality. It kind of got into a little bit, I guess. ‘Cause he writes a shell script later on in the chapter.
It is true. Like, I mean we talked about standard in and standard out but...
Yeah.
I don’t know if I actually caught it. Like, the whole like, Unix philosophy that like, everything is a file. Like, that’s kind of a core concept as well is like, you should be able to go open up anything. Like, if you want to go and like, open up your mouse device and start piping that through sed or something else, you can do that. You may get complete garbage that’s handed through, but everything lives on your file system, but just like, as a file. Like, and-
Hmm.
It appears the same with, you know, caveats here and there because modern Unix doesn’t do that.
So what does that mean, exactly? Can you expand on that idea of everything is a file.
Yeah, so for example, if you go and, this is speaking more to Linux. I am, I find myself digging less at the internals when I’m on OS10. And like, say you were to go and like, plug a mouse into your computer then if you look under a directory at like, the root of your file system, like you’d have a folder called /dev inside of there.
Hmm.
And if you list everything that’s inside of /dev, yeah, it exists on OS10, too. But if you list in there, like, you’ll notice that there’s a whole bunch of things in there that are like, devices. And it’s like, a device is not a file, but in fact, like, the way that the kernel handles it it actually does turn it into a file. Like, every USB device is just a file that you can go and you can write to and read from if you want to.
Is it using that file? Like when the mouse moved around? Is it like writing stuff to that file?
Yeah, like if you... I don’t know which particular file that it would be, but like, yeah you could find your mouse and you could start piping that into cat if you wanted to and you could watch what it looks like when your mouse moves. And like you could create any application to go and to listen to that. What’s cool about that is like, it’s sharing that same interface across like, whatever thing that you’re using. Like, if you actually writing to a file or if you ‘re talking to a piece of hardware, or yeah. It’s just everything winds up being a, having that same interface of just being a file that you can go and open up and read from and write to. It’s like, just an input/output system.
Yeah, that’s cool.
Yeah, I guess I don’t step back and appreciate the value of that enough and so that is a positive that came from the chapters, thinking on that. Also I’m glad that he brings up Vim as well, ‘cause I’m a Vim user, myself.
Yay! Vim!
(laughs)
(laughs)
Heh, yeah. Yay Vim! I would say that like, it seemed a little strange. Like, if you’re trying to learn Unix, like, getting dropped into Vim, like gives you the sense of like, I brand this command and I can’t escape from it now.
(laughs)
Like, does that…
(laughs) Yeah.
That certainly happens and so like, I mean, having to learn how to bat, like-
And also your Vim will not look as pretty as his if it’s the first time you’re using it.
Yeah. Like, it will be be pretty plain and you… Yeah, it won’t even have like syntax highlighting or anything like that to begin with and so I also would say with caution, like if you’re going to learn Unix, like, you don’t have to learn Vim and the same time. You will only-
Or Emacs.
Or Emacs-
Mm-hmm (affirmative).
Like, I’m not a big promoter of GNU Nano but it is also like, what you would probably expect.
It at least has the commands at the bottom to tell you exactly which ones to do when, so…
Yes.
Yes.
I end up using GNU Nano when I’m in it more often than the others. However, I do like the fact that he kind of jumped into dot files for a minute to talk about basically saving them to GitHub and how lots of people do it and how that’s how they get their cool configs and how you can get their cool configs, too.
Yeah! So I’ve got my dot files up on GitHub. I think, Jason, you have yours as well, right?
Yeah. I’ve got mine up there, we can link to them.
So do I, but not as well.
Yeah, I’ve got mine up there, but I don’t think I’ve updated them in a while, mostly ‘cause I’ve found my like, sweet spot of my configs, so.
Yeah, mine change all the time because they have all sorts of things in there like installing gooey applications with homebrew cask.
Hmm. Cool
And then I’ve got one for MacOS and I’ve got one for Linux.
The only weird thing, or I guess not weird thing, but for a while I was working in Vim with no syntax highlighting.
Oh man!
Why did I do it…?
(laughs)
Sorry, I’m remembering now. It was kind of just like a mental exercise I was doing to like, make myself more alert when I was coding ‘cause usually when you have syntax highlighting on it tends to like-
Like, turn your brain off?
For me, personally, I didn’t pick up- Yeah, I didn’t pick up as many of the patterns and subtleties so one of the things I’ve found is when I had no syntax highlighting on I was like, making less typos and having less verbose code and things like that.
Hmm. Yeah, it’s like whiteboarding.
Yeah, it wasn’t that bad. One of the interesting things is, like, after a while your brain will, or my brain, I will not generalize.
(laughs)
My brain just kinda like, started filling in things like, “Oh, function’s not a word you care about.” Or, “Def is a keyword you don’t care about. Or if, or elseif are words you don’t care about.” Like, my brain took care of that in and of itself, which was kind of cool to see. Like, it kind of learned to filter out the things that weren’t relevant on its own.
That’s cool
Which is also a problem when it’s spelled incorrectly.
Hmm.
(laughs)
Yeah, but that was only for like… Like language-specific keywords. Like, your ‘Def’, your ‘function’-
Right.
Your ‘if’, your ‘elseif’, yeah.
Right. I’m just saying if you said F-I instead of if in the wrong language then…you know...
Yeah.
Your mind still might autocorrect.
Funct key on.
Is it Ruby that your if statements like, you end them by putting F-I-? No! It’s-
That’s Bash.
It’s Bash, yes. That’s why I was thinking about it. Got it.
Ah, yeah.
Yeah, Ruby is “end”.
Yes.
You have “end” all over.
Mm-hmm (affirmative).
Yeah.
So I actually learned to code in Notepad. So…
Yeah, I did, too.
I spent years coding in Notepad before discovering that there were other IDEs that actually color coded things. And-
Yeah. Did you upgrade to Note++?
No.
Notepad++?
I still didn’t, even when it was out. I found it annoying and stuck with just notepad.
Hmm.
So, it took me a long time to get used to color coding. (laughs)
Yeah, and I was going through a course one time called Startup Engineering on Coursera I think, and one of the things they had you do, and it was like, it was about learning how to code and making a, creating a startup company. It like, made you use Emacs instead of Screen on a like, remote server and I was like, “Man, if you didn’t know any better, like, this is a really high bar of entry just to start typing some code.”
(laughs)
(laughs)
At least you could exit the file though.
Yeah!
Without, you would have to break a few fingers in the process.
Yeah (laughs).
We just had a few Emacs users close out the podcast of this episode (laughs).
(laughs) Oh, no. This house is an Emacs house, so…
(laughs)
We don’t Vim in this house. We don’t Vim, otherwise I’m getting divorced, so…
Oh! (laughs)
This is an Emacs house.
Actually, ed is the one true editor.
Right!
There-
This is why I use GNU Nano
You keep going on with ed.
This is why I etch all my code into a stone tablet.
Right? It’s even easier actually-
I think I’ve made that joke before which is kinda sad.
(laughs)
VS Code, VS Code, peeps.
Aren’t you supposed to like, go one deeper and like, say like, it’s the flapping of the butterfly’s wings that I use in order to make that happen?
(laughs)
Like…
The butterfly effect, yeah.
We need to find relevant XKCD, ‘cause there’s definitely one.
Yeah, there is that joke.
(laughs)
One last thing that I really appreciated about this chapter, and it was kind of sandwiched in at the very end, was the section about cron.
Mm-hmm (affirmative).
Yeah.
I feel like cron is, maybe it’s not super underappreciated but it took me a while to start using it as regularly as I did. Though it’s mostly because the syntax for it is really confusing, so cron is used to kind of like, schedule scripts or programs to be run on a regular interval within your machine and the syntax for scheduling when that interval is can get a little hairy if you’re new to it and it’s one of those things where you have to kind of like, memorize what number goes where and what it means.
So it’s just one of those things you end up always having to look up, but I think cron is like, super useful for things like, in the example he referenced like, scheduling backups of your database, but also you can just kind of like, use it as like, a developer on a regular day-to-day basis. Maybe set up something like a reminder every 30 minutes to stand up. See, you don’t need an Apple Watch for that.
Yeah, you could use the, there’s a command in MacOS and probably in lots of Unix versions called “say.”
Hmm.
Okay…
Oh!
You could have a reminder that says it out loud and they have different voices. There’s a voice called whisper and it’s super creepy.
(laughs)
Mm-hmm (affirmative). For Say you can do a really great prank when somebody moves away from their computer, you know, open up a terminal session and then sleep for a certain number of minutes and then after sleep do “say something”. So they’ll like get back to their desk and be working and then like, 20 minutes later-
Yeah (laughs)
Their like, computer will whisper something at them.
Yeah. Or you could put it in their Bash login or ZSH login file, and it will-
Yeah.
Do it every time they open up a new terminal.
Yeah.
Uh…
So if you’re listening, please tell us what fun pranks you can cook up with the Say command and share them on Twitter with us, ‘cause I’d love to know.
(laughs)
Yes.
And prepare yourself for revenge, too because I know for me, like, if somebody messes with my machine if I’ve stepped away from it, all bets are off. And, uh...
(laughs)
(laughing)
You may not have a good experience.
I mean, they did call it Hasselhoffing for a reason.
On the topic of cron there were a couple of things that I was curious about and thought, the first one is cron and daylight savings. And so daylight savings time can be problematic with cron. Depending on the implementation, some will attempt to immediately run it afterwards and others will just skip that run. So, if you’re running database backups and you happen to have a machine time that is on a timezone that’s not ETC or something and you’re dealing with daylight savings, be wary.
Don’t schedule anything at 2 AM.
(laughs)
No. (laughs)
Between… Just don’t do it-
No.
Because it will run twice. Anything between 2 and 3, that’s when daylight savings time actually switches for some weird reason, is at 2 AM. So-
Hmm.
Really?
Don’t schedule anything for then and you’re fine.
Huh, that’s odd.
Yeah.
Yeah, you either skip the 2 AM hour, or you repeat the 2 AM hour.
Wow. I guess ‘cause that’s more than likely when you’re asleep than midnight?
I don’t know, but that’s what happens. So…
Huh.
As far as computers are concerned, that’s when it happens and therefore if you just don’t schedule anything between 2 and 3, you’d never run into the problem.
Just, UTC all the time.
(laughs) Yeah.
And one other thing that you can run into with cron as well is if you happen to have a long-running task with it, like say you’re running a cron that happens every five minutes and your task takes longer than five minutes, then you can also wind up with cases where you have the same process running more than once because cron will just go and start it up. Like, by default. It doesn’t say, “Oh this thing is already running, I’m going to stop what I’m doing.”
That is something that you have to take care of yourself and there is a utility, I’ve got a link to the man pages for it, it’s called FLock, or F-Lock which goes and creates a file, Unix-like right? And you tell FLock that you want to give it a file descriptor which is the way that Unix handles files. Like, it has some number that represents actually opening or closing a file, and if it can access it then it gives a zero return from it, which zero is good in Unix. Like, that means all systems go.
Zero good, one bad?
Yes. Zero and greater than zero, or I guess non-zero, is bad. And so it, yeah, it gives a zero when it’s able to go and access that file. Otherwise it will fail and you can go and exit the program early. And so, yeah. I’ll offer a link to FLock, but it’s something you may want to use if you have the potential of an overlapping cron jobs; otherwise you can do bad things, like, I mean, yeah. You can do double processing and other things like that.
And I had a friend of mine who wrote a cron job for a company where it was sending text messages and yeah, the task was running like every minute or five minutes or something like that, and his tasks started taking longer than he expected them to because they interacted with remote services to send actual text and then he started sending like, double texts out to people and it was not good.
Hmm.
And it was really expensive for him. So-
Oh yeah.
Yeah. Be wary of double jobs running.
And the Ides of March.
(laughs)
(laughs)
Okay. So the final chapter is called “Final Thoughts”, do y’all have any final thoughts about Final Thoughts?
(Typewriter Dings)
Reasons why you take notes online, is because your Wunderlist might become a book.
Hmm. Yeah. Or your Evernote notebook might become a book. Or your blog post series might become a book.
Trello, Todoist, who knows. Whatever your decide to do, keep track of some of these things.
Yeah, that’s really cool. I didn’t think of that. He just mentioned he had a series of tasks in Wunderlist, things he wanted to know someday, and to turn it into a book. That’s pretty cool.
But it obviously, definitely, was not that easy.
It- No, it just magically just turned into a book! (laughs)
Yeah-
He woke up one day-
Oh gosh, you should have told me that before I wrote mine! (laughs)
Yeah.
Is there some incantation I forgot about?
It’s good marketing for Wunderlist.
(laughs)
Yeah! (laughs) ‘Cause I believe he worked there, yeah.
Point is, take notes. You never know when you might be able to use them to write a book. How about that?
Yeah. My final thought it you don’t have to want to write a book or write blog posts or any, produce anything. Just having like, a methodical and curious and eager approach to your own learning is really helpful, and just recognizing that computer science is, although a new field, one that is built on like, centuries of discovery across like, math and physics and logic and all of these things. So there’s always more to discover.
That’s very inspiring.
Yeah, I think that’s where we end the podcast.
(laughing)
Just end it right there. Yeah, totally.
Forever.
We don’t need to do-
(laughs) Oh, boy!
Whoa!
Social media promotion- Forever! (laughs)
(laughs)
(laughs)
Or until next episode. I’m like, it is the end of the book so…
So next episode we’ll be talking with Rob Conery about this book and other things, I suppose. So be sure to tune in for that! And keep up with the show by subscribing in your podcast player or on Twitter and you’ll find out about that episode. Thanks! And I’ll see y’all next time.
See ya!
Bye, folks.
Bye!
Bye.
(Exit music: Electro Swing)