Practical Problem Solving with Algorithms Course Overview
Transcript from the "Course Overview" Lesson
>> I wanted to give a brief TL didn't watch, too long didn't watch. This is a quick summary of kinda the takeaways that I'm going to illustrate throughout the entire workshop. These are principles that you might take at face value or you might not fully appreciate, but hopefully by the end of this course, you appreciate that these things are really important.
[00:00:22] The first one that I wanna highlight is asking better clarifying questions. Anytime you're presented with a problem, whether it's somebody stating a problem to you, or it's just there's an issue filed, or there's a feature that you don't know how to implement, or whatever. Anytime there's a problem present to you, your first job is to understand that problem completely.
[00:00:44] Your first job is not to write code. That's the last thing you do and that's optional. The first thing you have to do is understand the problem. And we cannot get that with one single question. That is a progressive thing, it's a cyclical thing we have to come back to.
[00:01:02] We have reapproach a problem and realize later, I should have asked this before. If you can get better at having that almost uncanny ability to ask the right questions up front, that really is probably the best approximation of seniority and maturity and experience as an engineer, is just the instinct to ask the right questions earlier.
[00:01:42] That's it, so just, if I have a superpower, it's asking questions, and so I wanna encourage you to adopt that mindset. It does not show weakness, it does not show that we're not good enough or anything like that. In fact, it's a superpower. If you can be the one who asks the best questions in the room, you'll be the one who's providing value long after everybody else has left the room.
[00:02:06] So I strongly encourage that. So when you're faced with a problem, you have to ask the right questions to constrain the problem, because the answers to those questions, sometimes you won't get an answer. They'll say, I don't know, depends, right? But sometimes you'll get a concrete answer and that very much may guide you to an entirely different path for solving the problem.
[00:02:26] So don't forsake by getting those sort of clarifying questions as early as possible and then revisiting that as often as possible. Second one I already mentioned or referred to, we definitely want to balance what we do with the processing optimizations versus what we do with memory optimizations. Most of the time, people only care about performance, the speed, the CPU processing speed, and they tend to neglect the memory.
[00:03:13] Do be aware at all times of the trade-offs. There are not always trade-offs, by the way. I used to think this earlier in my career. I used to think there's no such thing as a performance and memory optimized, it's one or the other. And in a lot of cases, it feels like that.
[00:03:29] A lot of cases, the trade-offs that we make do feel like that. But there are times, and you will see in this workshop, we will come up with a solution that is both better in performance and better in memory management, and that's a win-win. So look for those, but when you can't find those, be aware of the differences.
[00:03:45] That means asking, where is this application gonna run? If it's gonna run on low-end smartphone devices in Third World countries or other parts of the world that don't have the same privileged access to high-end devices that we do. If that's what that means, then you might need to actually make a totally different choice there.
[00:04:05] Versus the only people that are ever gonna run this are high-end Mac pros or something like that. So that goes back to number 1, asking better questions, understanding the context of where this stuff is gonna run. Number 3, this is kind of a big pet peeve of mine, I don't hear enough people say this, but I think most of the people who teach this really believe it, they just don't call it out.
[00:04:30] So I'm gonna call it out, that you really actually need to get good at understanding the problem and then shaping what data structure you use or how you use it to that problem rather than the reverse. Rather than trying to say all I've got is a queue, and I've got to figure out some way to express my problem as if I can solve it with a queue.
[00:04:53] Oftentimes you can solve most problems with many different data structures, but most of those are not the best way to go. So what you want to do is develop a broader understanding of the various ways to use data structures, to combine them, to mix and match them just more broadly.
[00:05:11] I mean, there's dozens and hundreds of different data structures, some of them general, some of them very highly specialized. And none of us can keep all of that in our head, but the more of that that you have in your head, the easier it will be for you to identify this is more likely the school or the group of those problems that are gonna help me solve my problem.
[00:05:33] These data structures are more well-aligned. So literally aligning the data structure choice with the problem is one of the biggest hurdles that we have to get over. Cuz our job as an algorithmist, our job as an engineer, is to turn what we have in our heads into instructions for the computer.
[00:05:52] And if those two are misaligned, our code is going to be non-performant, buggy, hard to maintain, and ultimately, it's gonna get rewritten. That's the ultimate cycle, is that every line of code that we write suffers that same fate that somebody comes along later, doesn't understand it, and just rewrites it.
[00:06:11] And as an algorithmist, we should be trying to ask those questions and think about it more carefully, so that hopefully the code that we write is more robust, it's gonna survive those inevitable rewrite cycles. Somebody comes along and says, well, I don't know about all this other stuff, but this thing is solid, this code does what it's supposed to do and it's as good as we're gonna get it.
[00:06:31] That's sort of the ideal, if you will, that you could shoot for. Final point that I'll make, many of you have probably heard the famous quote. I did a little bit of digging, and actually, I'm not sure that it was even Knuth original idea, maybe he cribbed it from a few other people.
[00:06:53] But many of you have heard this common quote about premature optimization is the root of all evil don't prematurely optimize, right? This concept that anytime somebody sees an engineer working on an optimization of something, it seems there's almost an automatic doubt that what they're doing is even worth it.
[00:07:17] There's this presumption that if you're optimizing something, you're probably prematurely optimizing it. And what I will say is that, and we're gonna teach this as a practice. I could have put this as a fifth point up here. We're gonna teach it as a practice that when you tackle an algorithmic problem, the first solution that you do should be the dumbest and worst solution.
[00:07:39] It should be the quickest thing that you can get that is accurate, in my opinion. It should work, but you should not have to spend days or weeks trying to conceive of that solution. Even if it's horribly non-performant, even if it's completely impractical to launch to production, you actually need a reference solution, so that the optimizations that you can do, you can check to make sure that you're doing it correctly.
[00:08:04] Most people will skip over that step, they'll try to second guess things. I absolutely do this, I know for a fact that an n squared algorithm, for example, is gonna not work, so I'll just avoid even writing the code. And as a discipline, I'm gonna teach you that it's really important to have that reference implementation that was quick to write, so that you can benchmark, and so that you can check your answers, okay?
[00:08:29] Testing to make sure that you didn't create some regression because you were trying to optimize something. So what I would say is that premature optimization is not really the problem, it's immature optimization. There are things that you should be optimizing from the very first moment that you write some code, and there are things that will never matter.
[00:09:09] Cuz it knows it's never gonna get mutated or something. And I don't actually know whether that's true, but I'm just gonna go out on a limb and say it's completely irrelevant. There is never going to be a case where the choice between a var, let, and const was the difference between performance and non-performing code, that's just nonsense, it is, okay?
[00:09:29] So immature optimization, one of the things that I put under that umbrella, is trying to micro-optimize or trying to look at some implementation detail. And say I know that V8 uses hidden classes and blah, blah, blah, and then tomorrow, V8 ships a new version and all that's different.
[00:09:48] My advice is don't bet against the future. That practice of saying, I know now better than the engine, better than the compiler, better than the computer, I know these things better than they do, is you betting against the future of all of those incredibly smart folks who are working on optimizing that stuff.
[00:10:44] How do you get more mature at it? Practice, experience. But don't follow the bandwagon of, I'm not allowed to optimize now, or I'm only allowed to optimize in this specific way, because this guy, this person said this or whatever, don't follow that. Look at the problem, follow these steps, and that's the path, cyclically, experience over experience over experience, is the path to more mature optimization.
[00:11:10] And optimization is good, it's useful. You need to understand actually the full context of Knuth's quote, which was not just that all premature optimization is bad, but what he was saying is that many times, people focus on the non-critical parts of their application and they optimize stuff that won't actually matter.
[00:11:30] So that's really speaking to what I'm talking about about being more mature with it. If you can figure out what the critical path is, that's the $64 million question, what is the critical path? It turns out that's not a binary, it is or is not critical path. It's extremely context-dependent.
[00:11:48] So we have to get more mature and we have to get better at asking questions about our systems, our requirements, our problems, the contexts that our code will run in before we can ever hope to figure out where's the 3% that my attention should go.