diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f9f141b --- /dev/null +++ b/flake.lock @@ -0,0 +1,58 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "id": "flake-utils", + "type": "indirect" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1718089647, + "narHash": "sha256-COO4Xk2EzlZ3x9KCiJildlAA6cYDSPlnY8ms7pKl2Iw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f7207adcc68d9cafa29e3cd252a18743ae512c6a", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/src/content/posts/2023-09-02-coping-with-refactoring/index.md b/src/content/posts/2023-09-02-coping-with-refactoring/index.md deleted file mode 100644 index eeffcbe..0000000 --- a/src/content/posts/2023-09-02-coping-with-refactoring/index.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Coping with refactoring -date: 2023-09-02T02:17:23.405Z -tags: - - software-engineering - -heroImage: ./ruinsHero.png -heroAlt: ruins -draft: true ---- - -It is the inevitable nature of code to be refactored. How do we make it a less -painful process? - -It pains me to start a stream-of-consciousness type of article with a -definition, but to set things straight let's be sure we're talking about the -same thing. When I say **refactoring** I mean changing potentially large parts -of the codebase purely for the sake of making it more "organized". For some -definition of organized. - -As software developers, we usually think of refactoring as something we do in -order to make something easier. A common example would be something like a few -lines of code that people on your team have just been copy and pasting -mindlessly everywhere, because to make it generic would mean that they would -have to touch code outside of their little bubble and then reviewers get -hesitant at the diffs and yadda yadda all kinds of problems supposedly. - -Now it's your turn, and you have to change something tiny in those few lines of -code ...everywhere. Before you go in and start abstracting all of it into -something more generic, take a breather and think for a second: is it worth it -to refactor? - -If your refactor involves adding some extra helper classes or you're pulling out -your toolbelt of design patterns, **you are creating complexity**. And in the -software world, complexity is the real devil. - -Many people try to code in an "extensible" way in order to avoid refactors, with -extravagant interfaces and inheritance patterns. But all they've created is just -a larger mess that's harder to clean up later down the line when it eventually -needs to be rewritten. And it _will_ eventually need to be rewritten. - -Let's talk about object-oriented programming. There's this bizarre -[open-to-extension but closed-to-modification][1] principle I've observed where -people are so resistant to changing their source code that they'd implement -heaps of useless design patterns on top of it in order to keep their little -classes from ever being touched. - -[1]: https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle - -If that doesn't sound insane to you, let's take a look at a case study. Suppose -you're writing some code that takes in a request type, diff --git a/src/content/posts/2024-06-21-coping-with-refactoring/index.md b/src/content/posts/2024-06-21-coping-with-refactoring/index.md new file mode 100644 index 0000000..1a5d486 --- /dev/null +++ b/src/content/posts/2024-06-21-coping-with-refactoring/index.md @@ -0,0 +1,61 @@ +--- +title: Coping with refactoring +date: 2024-06-21T05:56:50.594Z +tags: + - software-engineering + +heroImage: ./ruinsHero.png +heroAlt: ruins +--- + +It is the inevitable nature of code to be refactored. How do we make it a less +painful process? + +A not-horrible approach to creating a piece of software by first developing the +happy path, and then adding extra code to handle other cases. When we do this, +we may find that patterns emerge and some parts may be abstracted out to make +the code cleaner to read. This makes sense. + +It seems that many engineers decided that this process of abstracting is too +painful and started using other people's abstractions pre-emptively in order to +avoid having to make a lot of code changes. They may introduce patterns like the +ones described in the GoF Design Patterns book. + +Some abstractions may be simple to understand. But more often, they almost +always make the code longer and more complex. And sometimes, as a part of this +crystal ball future-proofing of the code, you may make a mistake :scream:. At +some point, you will have to change a lot more code than you would've had to if +you didn't start trying to make a complex design to begin with. It's the exact +same concept as the adage about [premature optimization][2]. + +[2]: https://en.wikipedia.org/wiki/Program_optimization + +As an example, as a part of one of my previous jobs, I was reviewing code that +created _10+ classes_ that included strategy patterns and interfaces. The code +was meant to be generic over something that could be 1 of 4 possibilities. But +the 4 possibilities would basically never change. The entire setup could've been +replaced with a single file with a 4-part if/else statement. + +I'm not saying that design patterns aren't useful. If we had more possibilities, +or needed to make it so that programmers outside our team had to be able to +introduce their own options, then we would have to rethink the design. But +changing an if statement in a single file is trivial. Changing 10+ files and all +the places that might've accidentally referenced them is not. + +Some people think they can dodge the need to refactor by just piling more +abstractions on top, in a philosophy known as ["Open to extension, closed to +modification."][1] I think this is just a different, more expensive form of +refactoring. Increasing the number of objects just increases the amount of code +you need to change in the future should requirements or assumptions change. + +[1]: https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle + +So the next time you're thinking of introducing design patterns and creating a +boat load of files to hide your potential complexity into, consider whether the +cost of adding that abstraction is worth the pain it will take to change it +later. + +> [!NOTE] +> As a bonus, if your language has a good enough type system, you probably don't +> need the strategy pattern at all. Just create a function signature and pass +functions as values! diff --git a/src/content/posts/2023-09-02-coping-with-refactoring/ruinsHero.png b/src/content/posts/2024-06-21-coping-with-refactoring/ruinsHero.png similarity index 100% rename from src/content/posts/2023-09-02-coping-with-refactoring/ruinsHero.png rename to src/content/posts/2024-06-21-coping-with-refactoring/ruinsHero.png