A book club for developers.
BookBytes is a fortnightly (or biweekly) book club 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).
(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.
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.
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?
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?
Into not chapters but…
Parts. I think there’s three parts.
Yeah, three episodes.
So, let’s get into testing.
This is definitely an opinionated-
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, 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?”
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.
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.
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.
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.
Because I assumed, like, Rust’s built in sort is going to be correct.
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. I think trying to achieve 100% test coverage is not… not good.
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-
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.
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.
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.
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.
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-
That’s gonna change all the time.
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.
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.
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.
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. 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.
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)
I like it. I like it, keep going.
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.
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, that’s a good point. It used to be easier to say, “Here’s all my test files in this folder. Run those tests.”
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-
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?
All right, but first we’ve got a sponsor.
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.
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?
You know what I’m talking about?
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.
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.
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.
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.
Totally agree, yeah.
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...
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-
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.
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.
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.
Like, does that…
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-
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…
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.
And then I’ve got one for MacOS and I’ve got one for Linux.