Why Can't We Make Simple Software? - Peter van Hardenberg - https://www.youtube.com/watch?v=czzAVuVz7u4 You are many things and I can't explain it properly, so you should introduce yourself. But yeah, your microphone's right here. Yep. Press hard for the next slide backwards and a pointer if you need it. Great, thanks. Thank you so much. Hi, everyone, I'm Peter. I'm going to kind of take things in a bit more of a philosophical kind of direction. You know, I work for a research lab these days, so that's kind of my tendency. The lab is called Ink and Switch. We are interested in carrying on kind of the work of Engelbart and Lick Leiter and Alan Kay and these people. We're interested in how computers can augment human intelligence. And that's very highfalutin. It's a lot of fun. We get to dig into all kinds of weird corners of software and experimental interfaces and so on. But before that, I have written a lot of production software. So I'm not just speaking to you from kind of an ivory tower perspective. I was one of the early employees at a platform as a service company called Heroku. I've run a lot of postgres databases. I've worked in game development as well. I've built titles for DS and gba. I worked on this one, Teenage Invasion of the Alien Brain thingies for a Victoria, B.C. game company. And I've worked on desktop software like Songbird, which was a cross platform media player that lost fairly decisively. And besides that, I've also worked in research, spending some time on, for example, this ship here, the Sir Wilfrid Laurier. It's a Canadian Arctic research icebreaker. So I spent some time in the Arctic and that actually helps inform my perspective on things too. But we'll come back to that. So I want to start by kind of saying, hold on a sec. Before we get into talking about why we can't make simple software, we should probably define our terms a little bit and talk about what complexity actually is. So the first thing I want to clarify is that complexity is not difficulty. Just because something is hard doesn't mean it's complicated. The ideas of calculus might be very difficult to internalize, but they're actually very simple and elegant. And I also want to draw a distinction between something being complex or just being kind of big. A box of Lego is not necessarily a complicated thing, though you can make a lot of things with it. Complexity occurs when your systems interact with each other and when it takes a lot to get things done because of that. More specifically, I think the problem with complexity is that your systems can become unreasonable. When I Say unreasonable. I don't mean in a colloquial sense. What I mean is that you literally cannot reason about them. You don't have the ability to predict what's going to happen. A lot of the time that's a problem because you got work to do and the thing is crashing and you don't know why. But a complex system can also be generative and surprising if you harness that complexity in positive ways. Last, before we get into it, I want to make just a very small detail point for the more pedantic in the audience. Some people draw a very specific difference between complex systems from sort of chaos math and like emergent complexity. We'll talk a little bit about that. As distinguished from complicated systems where you have a lot of just kind of mess. I'm kind of going to float back and forth across both of these without a lot of distinction because I think in this context either one can cause similar effects. Okay, so we're going to begin with a non comprehensive look at complexity. More specifically, we're going to cherry pick some examples from fake industrial scenarios where you can begin with something simple and end up with something complicated. So I'm going to start with the most basic of all reasons why your software gets complicated. And that's the first version of your code. You just write the happy path, everything's glorious. And. And software can be really simple when it lives in an idealized world and everything is fine. And so, you know, here's like a really simple imaginary pseudocode web thing. Great, we got a get request to our application. We're going to go fetch something from the database and say, hello there. This is a hello World app of web apps. Server apps. Great. And it works fine if user 12 is me and user 10 is my friend Keiko and user Fu is. Wait, what? Right, we got to validate the input. Okay, so we'll validate the request now. Okay, so we're validating the request and that's good. And geez, I'm not really handling it if we don't validate the request. And wait, do I have to do this on every request? I guess I have to do this on every request. And am I doing it the same way on every request? In fact, this exact pattern of validating user input and checking your arguments can lead to something that Bradis and Patterson call shotgun parsing. Shotgun parsing is kind of the idea that you're parsing your input, but it's like someone's taken a shotgun to your code base because it's just blown through the whole code base. It can lead to very serious security vulnerabilities because you might carefully check an input in one place but not in another. And there's a Great talk from Brewcon 2012 about this. So of course now we're going to be a little more careful. So we're going to also, if the database is down, we don't want to send a 500. We're going to fail elegantly as you go. The more of these cases that you have to handle and the better the quality of your code is, the more conservative, defensive, thorough that you are at this point. Now the actual logic of this method is beginning to disappear into all the edge case handling. We're well off the happy path now. You can clean this up a little bit. Imagine here in this case that we have a slightly better set of libraries, more thoroughly written set of libraries. We've moved the complexity down out of this method and we're saying, well, the database won't throw an exception because exceptions are ugly and subtle to handle well. It'll return null if it can't do the job for whatever reason. And we're going to say, well, there's a good type system that's handling parsing the input args before they get to us, so we don't have to worry about that anymore. And the value of well written libraries and languages, type systems and so on is that they can really simplify your code, make it less complex by preventing you from have to carry around all, all of this mental state everywhere that you go. My observation of this world is that vigilance is not a strategy. We talked earlier about how if a system fails, it's not oh blameless postmortemist. It's not that the developer failed, it's that the system failed. If you have security vulnerabilities in your code because you didn't handle input, the answer isn't to berate yourself for not handling the input. It's to step back, to level up and say, well, hold on, why do I have to do this manually every time? Strategically you want to minimize the scope of failures and design them out of your system. One way to do that is to have a type system so you don't forget to check your nulls. There are other approaches. I don't think this is universally true, but it's one way. Let's talk about scale. We all know as an array gets bigger, you can have an O of n log n kind of sort algorithm. Great. Well, scale's easy. Let's Just imagine an admin panel for a web application. You list your users. Looks kind of like this. Go to your database, select all the users, and then in your front end, just show them all. Perfect. Easy. It's fine. You've only got 10 users. Who cares? Okay, well, now we're at 10 to the 4. Okay, you've got a thousand users or so. Okay, well, okay, we can't just render all that on screen. Okay, well, we're going to use one of those offset SQL things, right? We know about this. And then we're going to need pagination, I guess. And you got to click through. Okay, yeah, sure. We can still do this. This is fine. You don't want to request all that. It's a pain to scroll through. Okay, well, now we're 10 to the six users. We got a million. Actually, that offset thing, that's a problem if you have a lot of users, because in order to generate page 850, it actually selects all of those rows and scrolls through them and just takes all of those results and just chucks them on the floor until it gets to the ones that you asked about. And actually now, even though nothing has changed about our problem statement, like, not only are the performance characteristics of the system starting to change and the user interface is starting to change, but the way that we interact with the problem is changing too. Because if you've got a million users, the way to find a user is not to just like, keep clicking next until you find them one page after page 350. I'm on the J's. Okay, click forward to change the query. ARG to force. We've all done these kinds of things when the tools didn't keep up with our admin system systems. But the point I'm trying to make here is that once you start to reach 100 million users, it's not even the same kind of problem anymore. The complexity that's snuck in here is now that we have different responsibilities. There are ethical, there are legal, there are policy responsibilities. You probably have a team of people at your organization who are responsible for dealing with abuse. Some of these people are terrible, and you want them off your platform and you can't find them. Right? Like, it's a different thing. And it's complicated because the environment has changed as much as anything else. So everything changes when your scale changes. It's not just like an algorithmic thing, it's also the kinds of things that you're doing change. And, like, in general, my advice to someone who's built a lot of high scale production systems through many orders of magnitude is that it's as harmful to build for the system of the future as it is to build an insufficient system for the present. If you build the tools for 100 million users, when you have 100 users, they're going to be completely unusable too. And you're going to waste so much time trying to solve problems you don't have yet that you're going to miss out on all the benefits of being able to just look at all your users and see who they are and talk to them. So you need to be scale appropriate and kind of be looking ahead. Another way software can get complicated is with leaky abstractions. Here we have a platform that's a little bit skewed and so complexity can kind of bubble up from under the waterline through these imperfect abstractions. This is how you copy a string. It's a nice handmade low level. This is an excerpt from Kernighan & Ritchie 1988 2nd edition C programming Language. This book was such a revelation for me how it showed me the way kernel functions were really implemented. No, I'm just kidding. They're not really implemented like this. They say here that this is how a C programmer would prefer to write string copy. The C programmer in question has never forgotten to null terminate a string. I see. But this is how string copy is actually implemented as of 2022 for Alpha in Linux. And actually this isn't how string copy is implemented. This is like one page of assembler. There's like 300 lines of assembly. And really importantly and intriguingly, although the interface remains the same, modern CPU architectures have so many more constraints around memory, alignment and everything else that although the interface is preserved, you can pass any pointers in and get values back. The kind of performance characteristics of doing an unaligned versus an aligned string copy will be dramatically different. And so complexity here I think we can kind of call this a win. We've got this super powered computer under the hood now, but it's still kind of feels like that old jalopy they were running in 1988. And that's cool that it works. But in a sense this API that's so simple is actually undermining the value of the system. And there's a lot of magic happening to kind of hide this. And so I feel very mixed about this because on the one hand it's sort of like SQL databases where you can add an index and change nothing else and things get faster. But there's like A really important subtle lie that's being told here. But maybe this is good and maybe it's bad. This is like a value judgment kind of question. And whether you understand this is happening could be completely irrelevant, or it could be the difference between the success and failure of a project. Okay, so these are kind of like technical complexities that come in. I want to talk about other sources of complexity, different kinds of complexity, and one really big source of complexity in my projects. Maybe you're smarter than me, and that's cool, but it's when you have a gap between the problem you think you have or the problem you used to have and the problem you have right now. And again, we're going to use a toy example to illustrate this. So you've got a users table, just same app as before. And you know your users. There's a bunch of fields. We got a first name and a last name. And how do you get the first name and the last name? It's easy, guys. You just split on a space. As a Van Hardenberg, you can see how this might get you in trouble. And in fact, on my California driver's license, it said that my middle name was Van for many years. And the problem here is that the model that you have for the problem doesn't actually map the problem domain successfully. So what do you do? And there are lots of things you can do. You can rewrite from scratch, you can patch around it. And actually, just as an aside for everybody in the room, the W3C has a wonderful essay about personal names around the world. And just if you take one little thing from this talk, don't use first name and last name. Don't use family name. People's family names aren't accurate. Some people have them and others don't. What you do is you have one field that is what is the full name? And then the other one is, if you need it, what should we call you? It's like a much better model. Also, Unicode, I know that's its own set of complexity, but. And so there's only so many things you can do when you have this problem. And I had a really specific, concrete example of this in a distributed system recently where, like, I had a mental model of how the system behaved, and my tests demonstrated that it behaved that way. And then in my production environment, it behaved completely differently because of behaviors that were not modeled by my understanding of the problem. And this is part of why distributed systems are so prone to this is because there's so many new free variables. And like Articulation points where things can be fast or slow or where they can fail or arrive out of order and all these kinds of things. And so when you have these kinds of model reality gaps, you have to bridge them somehow. And so what can you do? Well, you can fix the problem, you can improve your understanding and rewrite everything. And when you can do that, it's probably best. You can't really always do that, though. And more to the point, you may still not actually, you could see the problem, but you may still not actually understand the solution. And so what can you. Well, you can hack around it. I've put Van Hardenberg into a lot of text boxes without a space in it where the first letter is capitalized and the H is lowercase, and that's not how I spell my name, but it is how a lot of systems spell my name. Or you can ignore the problem, maybe it's fine, and genuinely, it could be fine for your use case. You're just like, well, I guess that Peter guy can suck it. He'll deal with having his name spelled wrong. And I do. These are options that you have. And there's like a great meme series out there on the Internet lies programmers believe about pretty much anything. Like all time zones are one hour apart, half an hour later in Newfoundland. And so I think this is a very fundamental source of complexity. But where things get really bad is when your problems start to multiply off each other. And this of course, is where you have kind of like compound interest on complexity. So what happens if your problems dimensionalize against each other? So again, imagine this web application. You've got a bunch of different browsers to support. You've got a bunch of different runtime environments to support, different screen sizes, network speeds, different OS or browser versions. And so if you want to actually understand what's happening, all of these things multiply against each other. So you don't just have one runtime environment, you might have one code base, but you have lots of different contexts. So how can you know that you actually have correct functioning code? Because the old joke about Docker like, well, it worked on my computer. Well, I guess we'll ship your computer. Well, even that doesn't really work because once you get out into the real world, there's different memory context, so you're up against different loads or whatever else, right? You don't actually configure control the whole environment. And so this is what really starts to kill you with complexity. And it's where all of those smaller inconsistencies play off each other to create an unknowably complicated environment. And this is why you see so much popularity and amberjan were kind of hinting at this, like, you don't use the native APIs, because God help you if you're trying to figure out how to map all of these totally different environments down to one consistent thing. And one solution here is just to only have one thing as best you can and to minimize the difference between those environments. And that's why you see sort of like ostensibly lazy electron apps from big companies. Because even worse than having to support all these different things is having to coordinate all the different people and teams to try and build features, right? And we've all, many of us have been there, right? Like, if you have an iOS and an Android team, like, how do you get them to ship the same feature in the same quarter? Right? That's tough. It's tough. Okay, so I hope I've convinced you now that complexity is like a complex problem itself and that it manifests in a lot of different ways. So we're going to change gears a little bit and talk about seat belts and more specifically, why seat belts don't save lives. I have an asterisk here because this is a little bit of a controversial research topic. But the upshot of this is that in at least some studies, they found that after seatbelts became mandatory in cars, people still died on the roads at similar rates. That was really surprising because seatbelts are a good idea. They keep you safer in the car. Somebody proposed this idea called risk homeostasis. The idea behind risk homeostasis is that actually we die at a rate on the road related to how much risk we're willing to take. And so if you now have a seatbelt and you're driving a car that's safer, you're going to go a little faster and you're going to take the corners a little tighter because you feel better. The issue with making people safer was that they then took on more risky behavior, conserving their total risk tolerance. And so I think we see a similar thing in software, right? I call this complexity homeostasis, which is to say that if you have kind of a system that's evolving over time, you know, everything's fine, we're going along, life is good, and then we add some more things and, you know, we're still happy. And then, oh, yeah, now it's. I don't like it anymore. It's not good. It feels bad. Now it's time for that rewrite that we were hearing about. Right. It's time to bring things back. Ah, okay. Now we can go back to making things complicated again. And so this is kind of like a set point. So homeostasis is the process where our. Or it's any process where you sort of maintain a set point. And it's commonly used to talk also about how our bodies regulate temperature, but I think our organizations regulate complexity. And so all of us have different intuitions. And when people talk about wanting things to be simple, there's like an aesthetic preference here. And different people perceive that and pursue that differently. And like Duveen's quest for just the right number of opcodes that we heard about yesterday is a great example where, like, in a certain sense, the correct number of opcodes is one, and you could do that if you really wanted to, but then you've got kind of like the CISC op code model where actually the correct number is hundreds because you're maintaining backwards compatibility. And anything that can squeeze you either better numbers out of a benchmark or more CPU sales is acceptable. How you perceive what constitutes complexity or how much complexity you're willing to tolerate is an individual or an organizational decision. Some things can actually move that up. Like, I have abandoned projects because they got complicated and annoying to work on. But, like, some people might just tolerate that and not perceive it. I've worked with some brilliant people who write the most complicated, insane, convoluted code from my perspective. But when I sort of go to them and I'm like, this is so complicated and weird. Why did you do it this way? They don't see it because they're just much smarter than me. They're able to hold that complexity in their head comfortably. And so for them, it doesn't feel that way. Another way, a system can become more complicated if it's worth a lot of money, right? Because, like, you can just hire another poor schmo to sling Java into the code base. I mean, has anybody here worked on an EA Sports title? Yeah, I'm so sorry. I have heard some things, man. And it ships every year on deadline, without fail, right? Like, that's not an environment that leads to healthy refactoring or reduction of complexity. But you know what? It makes a boatload of money. And so they'll hire people to work on it because they can afford to. And you'll work on it because they'll pay you enough, because they know. They know, right? And so part of this as well is that also if you just have more people working on things you can tolerate more complexity. I can hold part of it in my head and you can hold part of it in your head. And I kind of want to distinguish like there's sort of the breadth of complexity and if you have a well factored system, you can decompose the complexity either into layers or modules. Right. Like each individual LEGO brick is simple, but you can build very complicated things from it. Right. And so that's sort of the system complexity versus the component complexity. CSS is incredibly complicated. And by that what I mean it's complex. You can't tell from looking at one rule what it will manifest as in a final document. Okay, well we can just solve this problem with better tools, right? Well, no, because as we've talked about, we have this homeostasis point that we fall towards over time. We can choose where to set it, but we do move towards it. The research on this actually goes all the way back to the 1860s. This is Jeffons paradox, which was like, why did coal consumption not decrease when engines became more efficient? The answer is people did more work. I feel very much that this is the inevitable conclusion we have to draw from looking at the problem, which is that the degree of complexity of a system is tied to who we are and what we're doing over time. When we buy back some complexity by using better tools or by picking a simpler environment, we're going to spend that out again eventually. Okay, so let's talk a little bit about some theories of complexity, because I'm from a research lab and I like to read papers. So this is not a new problem. Have people heard of cyclometric complexity before? Yeah, we're not going to do this. You're welcome. But I do think that although you, you know, sort of the naive pursuit of like software metrics as a way of measuring what we're doing is not wise. I think that the conceptual understanding that like when you couple things together that that can have a cost and be problematic is worth thinking about. In fact, people have been looking at this and thinking about it since the 1980s. This is Mayor Lehman in 1980's IEEE Volume 68. So like, this is not a new domain. And so even back then this edition was from 1980. The first paper published was in 1974 on these laws of software engineering. We're not going to read these super close. It's more that I want you to realize that this kind of recognition that systems grow to meet growing needs if they're successful is not a new idea. It's a common problem. And whether you're working in building tools or languages, you might start with an elegant and simple thing. But as a system has more demands on it, it responds by adding, that's a very common, and it's a reasonable consequence. And if you don't do those things, the thing will often starve and die. One great paper, if you haven't read it yet on this topic, is out of the Tar Pit by Moseley. This is from 06. This paper differentiates between what is accidentally complex versus essentially complex. Essential complexity is the irreducible, non eliminable part of your system. If you are trying to model certain physical processes, like smoke or fire, like the physics part, where you're actually doing the work, you can't get rid of that. You don't want to get rid of that. That's what you're here for. But the accidental complexity is all that other stuff, like, oh God, we got to compile this so it works Like, Windows 11 has changed the ABI for this DLL. Like all that stuff where, you know, we heard about Davine hoisting the phone up the mast to download 11 gigs of something, right? That's mostly accidental complexity for our purposes. And so it helps as you're working and thinking about complexity to. To think about where you're spending that budget and whether you're being deliberate in terms of how you're adopting complexity. The other thing I want to refer to is this great essay from the Berkeley DB team in the Architecture of Open Source. And honestly, I highly recommend reading this if you just like software engineering, the architecture of Open Source software is a cool series. Basically what they do is interview open source communities about their software and have them write essays about what they've done, and then they publish and share those. But I think this BerkeleyDB chapter in particular is exceptional, and I think about this all the time, which is that software architecture degrades with changes made to software. So you might have the most elegant, brilliant, carefully planned system in the world, but it does not exist at a single point in time in a vacuum. And as new demands come along, this architecture will decay, and so it requires a constant shoring up. And when you have big interfaces that you've invested heavily in and they're straining, it can be extremely expensive to change them. I also just love this because it's a little more handmade specific kind of vibe. The Excel team motto, at least according to Joel Spolsky, is find your dependencies and eliminate them. I have been told on reasonably good authority that Excel actually is built with its own C compiler, that they didn't even want to rely on other teams within Microsoft and to the degree where they've built their own compilers. I'm not saying you necessarily should do that. I'm not saying you necessarily shouldn't. You got to think about how you're spending your budget. The last point I want to make on this theme is again, that complexity isn't necessarily bad. Complexity can lead to all kinds of wonderful emergent properties. The Legend of Zelda, Breath of the Wild. It has had such a wonderful community grow up around it precisely because they managed to tame complexity with their chemistry engine. So there's a lot of emergent gameplay properties and experiences that come out of interactions, complex interactions between systems. But the systems are factored in a way that enables and empowers us. And of course, if you're a roguelike fan, people have been doing this forever there. Okay, so now what? We have now looked at complexity. I've told you, you can't get rid of it. So we're just going to have to live with it. And better tools won't save us. So how are we going to spend this complexity budget that we have? I mean, one approach is you just put your head down and you work away and pretend it's not a problem. And that's a pretty common solution to all of our problems in life. So we could do that. But I'm going to maybe try and propose a few ways we can cut the Gordian knot here. And so the story of the Gordian knot was that there was this sort of this ox cart with a really complicated knot on the handle. And people were like, oh, whoever unties this knot will rule all of Asia. And many people had come. And then Alexander the Great came along and depending on the version of the story you hear, he just like, okay, cool. And he cut it with a knife, right? And so instead of solving the problem by like trying to be really smart or work really hard, like can we just cheat and change the rules? I think that's a better approach. So one approach is to do what folks here like to do, just start over. You can't actually get rid of this problem, but you can reset the clock on it. Just build a new one. Start from the beginning. Everything's easy in the beginning. It's only when you have users and features that you have complexity. So make a new programming language, start a new vm. It's good. You can't really change this long run pressure. But like Genuinely, you can reset the clock. And I think that's part of why things like Excel are popular and successful is they don't have package managers. Right? Like every time you make a new Excel document, it's a brand new universe, you know, with none of the misery or mistakes that you made before. It's like the forgiveness of the blank page, you know, that's. Then there's something to that. I went to a talk by John Romero at Strangeloop not that long ago, and he talked about how ID Software had been making these shovelware games as contractors, or that the ID software team, him and Romero and Carmack, had been making these sort of shovelware games. And their attitude was like, well, you should just always start from scratch. You get really good at it, you can be really fast, and each time you do a little bit better than the one before. And we do, I think, do better. I'm not. I love learning new languages and building new ecosystems. And I think a big part of the reason why they're successful is because when you have a new language, you do have the opportunity to clear away the standard library and also just the ecosystem of ideas and people and sort of start from a fresh starting point. Now, this won't cure complexity in the long run, but it can get better, at least in the midterm and we can get further. So I think, you know, that's pretty cool and it's also pretty fun. So, like, I'm all for that. Please, please do more of that. And to some extent, it's sort of like, you know, it feels like we live in these unbreakable regimes where, like, Unity, you know, rules or where, like, the big companies, Google and Microsoft and everybody rules. But that's the kind of thing that's true until it isn't. And there's this lovely quote from Ursula Le Guin about capitalism, which is sort of the generalization of these problems. Capitalism was itself an invention, and I'll just read it. We live in capitalism. Its power seems inescapable. So did the divine right of kings. And any human power can be resisted and changed by human beings. We should not doubt that the environment can be changed. The environment was created, it will be changed. We don't know how or when, but it is inevitable. Okay, so you can start over, revolution, burn it down, or, you know, just do less. Do less with less. Do I have my play date? Do people have these? Does anybody got a playdate? Yeah, this is great. It's black and white. There's only one platform. It's small. It comes in one color. It only has one color, black or white, depending on how you think about it. Doesn't have a lot of buttons, doesn't have much ram, doesn't really have any. There's a little bit of networking and there's only one hardware platform, so you don't have to worry about compatibility problems. Ish. There is the emulator, which behaves differently, and due to sourcing problems, they had to get a different microcontroller, but it transpiles natively. They're doing a really good job. Anyway, it's a heck of a lot simpler than building for PS5, you know, Xbox, PC, Switch, 3Ds, all on one code base. Like, it is genuinely awesome. And because it's so small, it's like, you know, kind of appealing. And when you have less scope, you can choose to spend that energy, that complexity budget. You can put it into polish, right? And like on a small platform, a small idea can shine. So, okay, well, we can't solve complexity, but we can make things worse. This is actually from Augmenting Human Intellect by Engelbart in 1962. And it's demonstrating that you can in fact change people's experience with design interventions. I said change, not improve. So, yeah, you can. We've made things pretty bad in terms of software development. This is my favorite slide always to show. This is the cloud, native cloud, Cloud foundation, Cloud, native landscape. I always get this wrong. This is ostensibly, I think, $20 trillion worth of companies. Anyway, please memorize all of this. There'll be a quiz at the end if you want to make a Web application in 2022. I had to zoom out the browser just to fit it all on screen for this one. So I'm going to talk a little bit now about our research, which kind of ties back into this because I think it might be interesting. Our approach is less the kind of like reboot model and more of the maybe do a little less with less model. And one of our research interests kind of builds on these sort of tools for thought. A big part of what we're interested in as a research group is not simplicity versus complexity or decentralization or anything like that. But we do find that we have to work in that space because what we want are tools that we have agency over, that we have ownership of, that are ours and can't be taken. And so we call our research there local first software. And the idea is basically that instead of having to go learn that whole chart of technologies that you can't actually do any of that stuff if you just run it on your computer, because that stuff's all in the cloud. So if you want to build software that works on your computer, not only do you not get to use all that stuff, you don't have to use all that stuff. And so this, you know, it's sort of like simplification, like via amputation. So we just cut off most of the cloud and then we build things locally. And so we've dabbled in a bunch of different platforms over the years. Right now we're building things in the browser, but storing everything in IndexEDDB. But one of our core beliefs is that collaboration is such an important part of thinking and making and doing that it should be like a really fundamental part of our platforms. And so we've been exploring technology that allows you to build software that runs on your computer, but then collaborates with other people, even allowing online offline kind of cuts. And the model underpinning that is a data structure called automerge. It's sort of like a portable versioned JSON, like data structure. You could think of it as like, get for your data. I'm happy to talk at length about this stuff, but I don't really want to harangue you too much on our particular kind of development interests. But it's really incredible just how it feels to build software that's fast and simple and runs on your computer. If you, like me, have spent the last chunk of your career building cloud services and running things in the sky. I had this really memorable outage where Amazon turned off US east one dirty because the generators didn't come on in a hurricane. And we were sort of like three days into some godforsaken system rebuild from backups of everybody's databases. And my coworker turns to me and he goes, I'm fixing computers that don't exist in a data center I've never been to for people I've never met. And he just had the like thousand yard stare in his eyes and I was like, yeah, do you need some more coffee? Yeah. And so, you know, like, in a sense working on this stuff is almost like penance for me because I created all these single points of failure. Anyway, so let's recap a little bit of all of this. How do we live our lives in this complicated world? Right? So complexity occurs when our systems have internal interactions, right? Complexity doesn't mean, oh, there's a lot of stuff. It's when all that stuff starts to bump against each other and cause unpredictable Outcomes. And complexity is also a natural consequence of system incentives. If you have a lot of people using a thing and you're listening to what they need and you're evolving as you learn more, you're going to end up with something complex. Better tools won't change this. The complexity is a consequence of who we are and the choices we make. Sure, you can. You can burn through your budget faster. But ultimately, where your project ends up on the complexity scale is more about how much time and how many ideas are invested into it than anything else. So we can't beat complexity, but we can get beaten by it. And so what are our coping strategies? Well, we can start over. We can eradicate dependencies. We can cut scope, do less. Right. We can simplify our architecture. And a really big one is being conscious of and learning to kind of identify when you're getting into these multiplicatory environments, right? Like once you start porting things to multiple platforms and having to build those, like, per platform abstractions, how do you manage that complexity back down? How do you isolate complexity? And a big part of success is isolating complexity. But I also want to, you know, give a shout out to gazing into the abyss. And, you know, you can, you can go, go for it, right? Like, embrace complexity, harness it. Yeah. It's a deal with. With an elder God. And you may accomplish great and terrible things, but at a great and terrible price. You know, that's fine, but when you do this, you got to be real careful, right? And you want to be really deliberate about how and when you take on that complexity. So I guess in closing, we can't solve complexity, but we can build better software. Or to put it in the words of cyclist Greg LeMond, it never gets easier. You just go faster there. And that's all.
Why Can't We Make Simple Software? - Peter van Hardenberg - https://www.youtube.com/watch?v=czzAVuVz7u4 당신은 많은 것들이고 제가 제대로 설명할 수 없어서, 자기소개를 해주셔야 할 것 같습니다. 네, 마이크는 여기 있습니다. 그래요. 세게 누르세요 이전 슬라이드로 가려면, 필요하시면 포인터도 있습니다. 좋습니다, 감사합니다. 정말 감사합니다. 안녕하세요, 여러분. 저는 피터입니다. 저는 좀 더 철학적인 방향으로 이야기를 해보려고 합니다. 요즘 저는 연구소에서 일하고 있어서 그런 경향이 있습니다. 그래서 그런 경향이 있죠. 연구소 이름은 Ink and Switch입니다. 우리는 관심이 있습니다 엥겔바트와 릭라이더, 앨런 케이 같은 분들의 작업을 이어가는 데 우리는 컴퓨터가 어떻게 인간 지능을 증강시킬 수 있는지에 관심이 있습니다. 그건 매우 고상한 얘기죠. 아주 재미있습니다. 우리는 소프트웨어의 온갖 이상한 구석들과 실험적인 인터페이스 등을 파고들 수 있습니다. 하지만 그 전에, 저는 많은 실제 소프트웨어를 작성했습니다. 그래서 단순히 상아탑 관점에서 말씀드리는 게 아닙니다. 저는 초기 직원 중 한 명이었습니다 Heroku라는 플랫폼 서비스 회사의 초기 직원 중 한 명이었습니다. 저는 많은 postgres 데이터베이스를 운영해봤습니다. 게임 개발 분야에서도 일했습니다. DS와 GBA용 타이틀을 만들었죠. 빅토리아 B.C.의 게임 회사에서 이런 게임을 만들었습니다. '십대의 외계 두뇌 물체 침공'이라는 게임을 만들었습니다. 그리고 저는데스크톱 소프트웨어인 Songbird 같은 것을 만들었는데, 이는 크로스 플랫폼 미디어 플레이어로 결국 실패했습니다. 그 외에도 저는 연구 분야에서 일했는데, 예를 들어 이 배, Sir Wilfrid Laurier호에서 시간을 보냈습니다. 이는 캐나다 북극 연구용 쇄빙선입니다. 북극에서 시간을 보냈고, 이는 제 관점에 영향을 주었습니다. 하지만 나중에 다시 얘기하죠. 먼저 잠깐만요, 라고 말하고 싶습니다. 단순한 소프트웨어를 만들 수 없는 이유에 대해 이야기하기 전에, 우리는 용어를 정의하고 복잡성이 실제로 무엇인지 이야기해야 합니다. 먼저 명확히 하고 싶은 것은 복잡성이 어려움과 같은 것은 아니라는 점입니다. 무언가가 어렵다고 해서 반드시 복잡한 것은 아닙니다. 미적분학의 개념은 이해하기 어려울 수 있지만, 실제로는 매우 단순하고 우아합니다. 또한 복잡한 것과 단순히 크기가 큰 것 사이의 차이를 구분하고 싶습니다. 레고 상자는 반드시 복잡한 것은 아니지만, 많은 것을 만들 수 있습니다. 복잡성은 시스템들이 서로 상호작용하고 그로 인해 일을 처리하는 데 많은 노력이 필요할 때 발생합니다. 더 구체적으로, 복잡성의 문제는 시스템이 너무 복잡해져서불합리하다고 할 때, 일상적인 의미가 아닙니다. 말 그대로 이해할 수 없다는 뜻입니다. 무슨 일이 일어날지 예측할 능력이 없는 겁니다. 대부분의 경우 이는 문제가 됩니다. 일해야 하는데 시스템이 충돌하고 이유를 모르니까요. 하지만 복잡한 시스템은 생성적이고 놀라울 수 있습니다. 그 복잡성을 긍정적으로 활용한다면 말이죠. 마지막으로, 본론으로 들어가기 전에 꼼꼼한 청중들을 위해 아주 작은 세부사항을 짚고 싶습니다. 일부 사람들은 카오스 수학의 복잡계와 창발적 복잡성 사이에 매우 구체적인 차이를 둡니다. 이에 대해 조금 이야기하겠습니다. 이는 복잡한 시스템과는 구분됩니다. 복잡한 시스템은 단순히 많은 혼란이 있는 경우입니다. 저는 이 둘을 크게 구분하지 않고 오갈 것입니다. 이 맥락에서는 둘 다 비슷한 영향을 줄 수 있다고 생각하기 때문입니다. 자, 이제 시작하겠습니다. 우리는 복잡성에 대해 포괄적이지 않은 관점으로 시작할 것입니다. 더 구체적으로, 우리는 가상의 산업 시나리오에서 단순한 것에서 시작해 복잡한 것으로 끝나는 몇 가지 예를 선별적으로 살펴볼 것입니다.가장 기본적인 이유부터 시작하겠습니다 소프트웨어가 복잡해지는 이유에 대해. 그것은 바로 코드의 첫 번째 버전입니다. 행복 경로만 작성하면 모든 게 훌륭해 보입니다. 소프트웨어는 이상적인 세상에서 살아있고 모든 것이 괜찮을 때 정말 단순할 수 있습니다. 여기 아주 간단한 가상의 의사 코드 웹이 있습니다. 좋아요, 우리 애플리케이션에 GET 요청이 왔습니다. 데이터베이스에서 뭔가를 가져와서 "안녕하세요"라고 말할 겁니다. 이것은 웹 앱의 헬로 월드 앱입니다. 서버 앱의. 좋습니다. 사용자 12가 나고 사용자 10이 내 친구 케이코고 사용자 Fu가... 잠깐, 뭐라고요? 맞아요, 입력값을 검증해야 합니다. 좋아요, 이제 요청을 검증하겠습니다. 요청을 검증하는 것은 좋습니다. 그런데 이런, 요청이 유효하지 않을 때 처리하지 않고 있네요. 잠깐, 모든 요청마다 이걸 해야 하나요? 아마도 모든 요청마다 해야 할 것 같습니다. 그리고 모든 요청에서 같은 방식으로 하고 있나요? 사실, 사용자 입력을 검증하고 인수를 확인하는 이 정확한 패턴은 Bradis와 Patterson이 말하는 산탄총 파싱으로 이어질 수 있습니다. 산탄총 파싱은 입력을 파싱하지만 마치 누군가가 산탄총으로 코드베이스를 쏜 것 같은 아이디어입니다. 전체에 퍼져있기 때문이죠코드베이스에 있을 수 있습니다. 이는 매우 심각한 보안 취약점으로 이어질 수 있는데, 한 곳에서는 입력을 주의 깊게 확인하지만 다른 곳에서는 그렇지 않기 때문입니다. 2012년 Brewcon에서 이에 대한 훌륭한 강연이 있었습니다. 따라서 이제 우리는 더 주의를 기울일 것입니다. 데이터베이스가 다운되었을 때 500 에러를 보내지 않고 우아하게 실패하도록 할 것입니다. 처리해야 할 이러한 경우가 많아질수록, 그리고 코드의 품질이 높아질수록, 이 시점에서 더욱 보수적이고 방어적이며 철저해집니다. 이제 이 메서드의 실제 로직이 모든 엣지 케이스 처리에 묻혀 사라지기 시작합니다. 우리는 이제 행복 경로에서 벗어났습니다. 이를 조금 정리할 수 있습니다. 이 경우에 더 나은 라이브러리 세트가 있다고 상상해 보세요. 더 철저히 작성된 라이브러리 세트가 있다고 합시다. 복잡성을 이 메서드에서 아래로 옮겼고, 데이터베이스는 예외를 던지지 않을 것입니다. 예외는 처리하기 어렵고 미묘하기 때문입니다. 어떤 이유로든 작업을 수행할 수 없으면 null을 반환할 것입니다. 그리고 입력 인수를 파싱하는 좋은 타입 시스템이 있어서 우리에게 도달하기 전에 처리한다고 가정합니다. 그래서 더 이상 그것에 대해 걱정할 필요가 없습니다. 잘 작성된 라이브러리와 언어, 타입 시스템 등의 가치는 정말로코드를 단순화하고, 모든 상태를 계속 기억할 필요가 없도록 복잡성을 줄이세요. 어디를 가든지 말이죠. 제가 보기에 경계심은 전략이 될 수 없습니다. 앞서 말했듯이 시스템이 실패하면, 비난 없는 사후 분석을 해야 합니다. 개발자가 실패한 게 아니라 시스템이 실패한 겁니다. 입력을 처리하지 않아 보안 취약점이 생겼다면, 입력을 처리하지 않은 자신을 꾸짖을 게 아니라 한 발 물러서서 수준을 높여야 합니다. '잠깐, 왜 매번 수동으로 이걸 해야 하지?' 라고 말이죠. 전략적으로 실패의 범위를 최소화하고 시스템에서 그런 실패를 설계적으로 제거해야 합니다. 한 가지 방법은 타입 시스템을 사용해 null 체크를 잊지 않도록 하는 것입니다. 다른 접근법도 있습니다. 이게 항상 옳다고는 할 수 없지만, 하나의 방법입니다. 규모에 대해 이야기해 봅시다. 우리 모두 알다시피 배열이 커지면 O(n log n) 정도의 정렬 알고리즘을 사용할 수 있죠. 좋습니다. 규모는 쉽습니다. 웹 애플리케이션의 관리자 패널을 상상해 봅시다. 사용자 목록이 있죠. 이렇게 생겼습니다. 데이터베이스에서 모든 사용자를 선택하고, 프론트엔드에서 그걸 모두 보여주면 됩니다. 완벽하죠. 쉽습니다. 사용자가 10명뿐이니 상관없죠. 좋습니다. 이제 10의 4제곱이 됐습니다. 천 명 정도의 사용자가 생겼네요. 음, 이제 모두를 한 번에 렌더링할 순 없화면에 표시된 그것을 보세요. 좋습니다. 우리는 오프셋 SQL 중 하나를 사용할 겁니다. 맞죠? 우리는 이것에 대해 알고 있습니다. 그리고 페이지네이션이 필요할 것 같습니다. 클릭해서 넘겨야 할 겁니다. 네, 물론이죠. 우리는 여전히 이걸 할 수 있습니다. 문제 없습니다. 모든 걸 요청하고 싶지 않죠. 스크롤하기 너무 귀찮습니다. 좋습니다. 이제 우리는 백만 명의 사용자를 가지고 있습니다. 사실, 그 오프셋 방식은 사용자가 많으면 문제가 됩니다. 850번째 페이지를 생성하기 위해서는, 실제로 모든 행을 선택하고 스크롤하면서 그 결과들을 버리다가 요청한 것들에 도달할 때까지 계속합니다. 그리고 이제, 우리의 문제 설명이 변한 것은 없지만, 시스템의 성능 특성이 변하기 시작하고 사용자 인터페이스도 변하고 있습니다. 게다가 우리가 문제와 상호작용하는 방식도 바뀌고 있습니다. 백만 명의 사용자가 있다면, 사용자를 찾는 방법은 단순히 다음을 계속 클릭하며 한 페이지씩 찾는 게 아닙니다. 350페이지까지 가서 "J"에 도달했군요. 계속 앞으로 가서 쿼리를 변경해야 합니다. ARG를 강제로 바꿔야 합니다. 우리 모두 도구가 관리 시스템을 따라오지 못할 때 이런 식으로 해본 적이 있습니다. 하지만 제가 말하려는 요점은 1억 명의 사용자에 도달하기 시작하면, 더 이상 같은 종류의 문제가 아니라는 것입니다. 복잡성이 완전히 다른 여기에 숨어든 것은 이제 우리에게 다른 책임들이 생겼다는 점입니다. 윤리적, 법적, 정책적 책임들이 있습니다. 아마도 여러분의 조직에는 남용을 다루는 책임을 맡은 팀이 있을 겁니다. 이 사람들 중 일부는 끔찍하고, 여러분은 그들을 플랫폼에서 내보내고 싶지만 찾을 수 없습니다. 맞죠? 이건 다른 문제입니다. 그리고 환경이 다른 무엇보다 많이 변했기 때문에 복잡합니다. 그래서 모든 것이 변합니다 규모가 변하면. 이는 단순히 알고리즘적인 문제가 아니라, 여러분이 하는 일의 종류도 바뀝니다. 그리고 일반적으로, 여러 규모의 대규모 프로덕션 시스템을 많이 구축해본 사람으로서 제 조언은 미래의 시스템을 위해 구축하는 것이 현재에 부족한 시스템을 구축하는 것만큼 해롭다는 것입니다. 1억 명의 사용자를 위한 도구를 만들었는데 사용자가 100명뿐이라면, 그것들은 완전히 쓸모없을 겁니다. 그리고 아직 없는 문제들을 해결하려고 너무 많은 시간을 낭비해서 모든 사용자를 살펴보고 그들이 누구인지 알아보고 대화할 수 있는 혜택을 놓치게 될 겁니다. 그래서 규모에 적합하고 앞을 내다보는 게 필요합니다. 소프트웨어가 복잡해질 수 있는 또 다른 방법은 누출되는 추상화입니다. 여기 약간 기울어진 플랫폼이 있는데, 복잡성이 이 불완전한 수면 아래에서 위로 올라올 수 있습니다.추상화입니다. 이것이 문자열을 복사하는 방법입니다. 좋은 수작업 저수준 방식입니다. 이는 1988년 2판 Kernighan & Ritchie의 C 프로그래밍 언어에서 발췌한 내용입니다. 이 책은 커널 함수가 실제로 어떻게 구현되었는지 보여줘서 저에게 큰 깨달음을 주었습니다. 아니요, 농담입니다. 실제로 이렇게 구현되지는 않습니다. 여기서는 C 프로그래머가 문자열 복사를 이렇게 작성하길 선호한다고 합니다. 해당 C 프로그래머는 문자열 끝에 null을 추가하는 것을 절대 잊지 않습니다. 알겠습니다. 하지만 이것이 2022년 기준 Alpha 리눅스에서 문자열 복사가 실제로 구현된 방식입니다. 사실 이것도 정확한 구현은 아닙니다. 이건 어셈블리 코드 한 페이지 정도고, 실제로는 300줄 정도의 어셈블리 코드가 있습니다. 매우 중요하고 흥미로운 점은, 인터페이스는 동일하게 유지되지만, 현대 CPU 아키텍처는 메모리, 정렬 등에 대해 더 많은 제약이 있어 인터페이스는 보존되고 어떤 포인터든 전달하여 값을 반환받을 수 있지만, 정렬되지 않은 문자열 복사와 정렬된 문자열 복사의 성능 특성은 크게 다릅니다. 그래서 복잡성 측면에서 이것을 성공이라고 볼 수 있습니다. 이제 초강력 컴퓨터를 가지게 되었지만, 여전히 단순한 인터페이스를 유지하고 있습니다.마치 1988년에 운행하던 고물차 같은 느낌이 듭니다. 그게 작동한다는 건 멋집니다. 하지만 어떤 면에서 이렇게 단순한 API는 실제로 시스템의 가치를 훼손하고 있습니다. 그리고 이를 숨기기 위해 많은 마법이 일어나고 있죠. 그래서 저는 이에 대해 복잡한 감정을 느낍니다. 한편으로는 SQL 데이터베이스와 비슷한데, 거기서는 인덱스만 추가하고 다른 것은 변경하지 않아도 속도가 빨라집니다. 하지만 여기에는 매우 중요하고 미묘한 거짓말이 숨어 있습니다. 이것이 좋을 수도 있고 나쁠 수도 있습니다. 이는 가치 판단의 문제입니다. 그리고 이것이 일어나고 있다는 걸 이해하는 것이 완전히 무관할 수도 있고, 프로젝트의 성공과 실패를 가르는 차이가 될 수도 있습니다. 좋습니다, 이런 것들이 발생하는 기술적 복잡성입니다. 다른 종류의 복잡성에 대해 이야기하고 싶습니다. 제 프로젝트에서 정말 큰 복잡성의 원천 중 하나는, 여러분이 저보다 더 똑똑할 수도 있겠지만, 여러분이 생각하는 문제 또는 과거에 가졌던 문제와 지금 직면한 문제 사이의 간극입니다. 다시 한 번 예시를 들어 설명하겠습니다. 사용자 테이블이 있고, 이전과 같은 앱입니다. 사용자에 대해 알고 있죠. 여러 필드가 있습니다. 이름과 성이 있습니다. 이름과 성을 어떻게 얻을까요?이름이요? 간단해요. 그냥 공백으로 나누면 돼요. Van Hardenberg처럼 말이죠. 이게 어떤 문제를 일으킬 수 있는지 아시겠죠. 실제로 제 캘리포니아 운전면허증에는 수년간 제 중간 이름이 Van이라고 적혀 있었어요. 여기서 문제는 여러분이 이 문제에 대해 가지고 있는 모델이 실제 문제 영역을 성공적으로 매핑하지 못한다는 거예요. 그럼 어떻게 해야 할까요? 할 수 있는 일이 많죠. 처음부터 다시 작성하거나, 임시방편을 쓸 수도 있어요. 그리고 잠깐 얘기하자면, W3C에는 전 세계의 개인 이름에 대한 훌륭한 에세이가 있어요. 이 강연에서 한 가지만 기억하신다면, 이름과 성을 따로 쓰지 마세요. 가족 이름도 쓰지 마세요. 사람들의 가족 이름은 정확하지 않아요. 어떤 사람들은 있고 어떤 사람들은 없죠. 대신 전체 이름을 쓰는 필드 하나와, 필요하다면, 뭐라고 불러야 할지 쓰는 필드를 하나 더 만드세요. 이게 훨씬 더 나은 모델이에요. 이런 식으로 하는 게 훨씬 나은 모델이죠. 그리고 유니코드도요. 복잡성이 있다는 건 알지만 말이죠. 이런 문제가 있을 때 할 수 있는 일은 한정되어 있어요. 제가 아주 구체적인 예를 들어드리죠.최근 분산 시스템에서 이런 경험을 했는데, 시스템 동작에 대한 내 멘탈 모델이 있었고 테스트에서는 그렇게 동작했습니다. 하지만 실제 프로덕션 환경에서는 완전히 다르게 동작했는데, 이는 내가 이해한 문제 모델에 포함되지 않은 동작들 때문이었습니다. 이것이 바로 분산 시스템이 이런 문제에 취약한 이유 중 하나입니다. 너무나 많은 새로운 자유 변수들이 있고, 많은 연결점들이 있어서 빠르거나 느리거나, 실패하거나 순서가 뒤바뀌는 등의 일들이 일어날 수 있기 때문입니다. 그래서 이런 모델과 현실 사이의 간극이 있을 때, 어떻게든 이를 해결해야 합니다. 그럼 어떻게 할 수 있을까요? 문제를 해결하고, 이해를 높이고 모든 것을 다시 작성할 수 있습니다. 그렇게 할 수 있다면 아마 그게 최선일 겁니다. 하지만 항상 그렇게 할 수는 없죠. 더 중요한 점은, 문제는 보이지만 해결책을 이해하지 못할 수도 있다는 겁니다. 그럼 뭘 할 수 있을까요? 임시방편으로 해결할 수 있습니다. 저는 많은 텍스트 상자에 Van Hardenberg를 공백 없이 넣었는데, 첫 글자만 대문자고 H는 소문자였습니다. 제 이름 철자는 그렇지 않지만, 많은 시스템에서 제 이름을 그렇게 쓰더라고요. 아니면 문제를 무시할 수도 있습니다. 실제로 괜찮을 수도 있고, 여러분의 사용 사례에서는 정말 문제없을 수도 있습니다. 그냥 "Peter가 그렇게 철자가 쓰이나 보다"라고 생각하는 거죠. 또는 문제를그 녀석은 꺼져버려. 이름 철자가 틀린 걸로 만족해야지. 그래서 난 이런 선택지들이 있어요. 그리고 인터넷에는 아주 좋은 밈 시리즈가 있죠 프로그래머들이 거의 모든 것에 대해 믿는 거짓말들에 관한 거예요 예를 들어 모든 시간대는 1시간 차이라든지, 뉴펀들랜드는 30분 늦다든지 하는 것들이요. 그래서 이것이 복잡성의 매우 근본적인 원인이라고 생각해요 하지만 정말 나쁜 상황은 문제들이 서로 곱해지기 시작할 때죠. 이건 물론 복잡성에 대한 일종의 복리 이자 같은 거예요. 그래서 무슨 일이 일어나냐면 문제들이 서로 차원화되는 거죠? 다시 말해, 이 웹 애플리케이션을 상상해보세요. 지원해야 할 여러 브라우저가 있고 지원해야 할 여러 런타임 환경이 있고, 다양한 화면 크기, 네트워크 속도, 다른 OS나 브라우저 버전들이 있어요. 그래서 실제로 무슨 일이 일어나는지 이해하려면, 이 모든 것들이 서로 곱해져요 그래서 하나의 런타임 환경만 있는 게 아니라, 하나의 코드베이스는 있지만 수많은 다른 컨텍스트가 있는 거죠. 그럼 실제로 제대로 작동하는 코드가 있다는 걸 어떻게 알 수 있을까요? Docker에 대한 옛날 농담처럼 "내 컴퓨터에서는 잘 돌아가는데"라고 하면 "그럼 당신 컴퓨터를 배포하죠"라고 하잖아요. 하지만 그것조차 실제로는 통하지 않아요. 왜냐하면 실제 세계에 나가면 메모리 컨텍스트도 서로 다른 부하나 기타 요인들과 맞서야 하죠. 실제로 전체 환경을 제어할 수는 없습니다. 이것이 바로 복잡성으로 인해 큰 문제가 되는 지점입니다. 작은 불일치들이 서로 상호작용하면서 예측할 수 없을 정도로 복잡한 환경을 만들어내는 것이죠. 이것이 바로 엠버가 암시했던 것처럼 네이티브 API를 사용하지 않는 이유입니다. 완전히 다른 환경들을 하나의 일관된 것으로 매핑하려고 한다면 큰 고생을 하게 될 겁니다. 이에 대한 한 가지 해결책은 가능한 한 하나의 환경만 사용하고 환경 간의 차이를 최소화하는 것입니다. 이것이 바로 대기업들이 겉보기에 게으른 일렉트론 앱을 사용하는 이유입니다. 여러 환경을 지원하는 것보다 더 나쁜 것은 기능을 구현하기 위해 여러 팀과 사람들을 조율해야 하는 것이기 때문이죠. 우리 중 많은 사람들이 경험해 봤을 겁니다. iOS와 안드로이드 팀이 있다면, 어떻게 같은 분기에 같은 기능을 출시하게 할 수 있을까요? 쉽지 않죠. 정말 어려운 일입니다. 자, 이제 복잡성이 그 자체로 복잡한 문제이며 다양한 방식으로 나타난다는 점을 설득했기를 바랍니다. 이제 주제를 바꿔 안전벨트와 그와 관련된 이야기를 해보겠습니다.구체적으로, 왜 안전벨트가 생명을 구하지 않는지에 대해서입니다. 이것은 약간 논란의 여지가 있는 연구 주제라 별표를 붙였습니다. 하지만 요점은 이렇습니다. 일부 연구에서 자동차에 안전벨트가 의무화된 후에도 도로에서 사람들이 비슷한 비율로 사망했다는 것입니다. 이는 매우 놀라웠습니다. 안전벨트는 좋은 아이디어이고 차 안에서 더 안전하게 해주기 때문입니다. 누군가가 위험 항상성이라는 개념을 제안했습니다. 위험 항상성의 개념은 실제로 우리가 도로에서 사망하는 비율이 우리가 감수하려는 위험과 관련이 있다는 것입니다. 그래서 이제 안전벨트가 있고 더 안전한 차를 운전한다면, 기분이 더 좋아져서 조금 더 빨리 달리고 코너를 조금 더 타이트하게 돌 것입니다. 사람들을 더 안전하게 만드는 것의 문제점은 그들이 더 위험한 행동을 하게 되어 전체적인 위험 감수 수준을 유지한다는 것입니다. 소프트웨어에서도 비슷한 현상을 볼 수 있습니다. 저는 이것을 복잡성 항상성이라고 부릅니다. 즉, 시간이 지나면서 진화하는 시스템이 있다고 할 때, 모든 것이 괜찮고, 잘 진행되고 있으며, 삶이 좋습니다. 그리고 우리는 더 많은 것들을 추가하고, 여전히 만족스럽습니다. 그리고 나서, 네, 이제...더 이상 좋아하지 않아요. 좋지 않아요. 기분이 나빠요. 이제 우리가 들었던 재작성을 할 시간입니다. 맞아요. 이제 다시 돌아갈 시간이에요. 아, 좋아요. 이제 다시 일을 복잡하게 만들 수 있어요. 이것은 일종의 기준점과 같습니다. 항상성은 과정입니다 우리의... 또는 기준점을 유지하는 모든 과정이죠. 그리고 보통 우리 몸이 온도를 조절하는 방식에 대해 이야기할 때 사용되지만, 우리 조직이 복잡성을 조절한다고 생각합니다. 우리 모두는 다른 직관을 가지고 있습니다. 사람들이 단순함을 원한다고 말할 때, 여기에는 미적 선호가 있습니다. 그리고 다른 사람들은 그것을 다르게 인식하고 추구합니다. 그리고 어제 들었던 Duveen의 적절한 수의 명령어 코드를 찾는 탐구는 좋은 예입니다. 어떤 의미에서 정확한 명령어 코드의 수는 1이고, 정말 원한다면 그렇게 할 수 있지만, 그렇게 되면 CISC 명령어 코드 모델처럼 되어 실제로 정확한 수는 수백 개가 됩니다. 왜냐하면 하위 호환성을 유지해야 하기 때문입니다. 그리고 벤치마크에서 더 나은 수치를 얻거나 더 많은 CPU 판매를 할 수 있는 것은 모두 허용됩니다. 복잡성을 어떻게 인식하고 얼마나 많은 복잡성을 감당할 수 있는지는 개인 또는 조직의 결정입니다. 어떤 것들은 실제로 그것을 높일 수 있습니다. 일부 요소들은 실제로 그 수준을 높일 수 있습니다.저는 프로젝트가 복잡해지고 짜증나면 포기한 적이 있습니다. 하지만 어떤 사람들은 그걸 견디고 인식하지 못할 수도 있죠. 제가 본 brilliant한 사람들 중에는 제 관점에서 볼 때 가장 복잡하고 미친 듯하고 얽힌 코드를 작성하는 사람들이 있습니다. 제가 그들에게 가서 "이건 너무 복잡하고 이상해요. 왜 이렇게 했어요?"라고 물으면 그들은 그렇게 보지 않아요. 그들은 저보다 훨씬 똑똑해서 그 복잡성을 머릿속에 편하게 담을 수 있기 때문이죠. 그래서 그들에겐 그렇게 느껴지지 않는 겁니다. 시스템이 더 복잡해질 수 있는 또 다른 방법은 돈을 많이 벌 때입니다. 왜냐하면 그냥 다른 불쌍한 사람을 고용해서 자바 코드를 던져 넣으면 되니까요. 여기 EA 스포츠 타이틀 작업해 보신 분 계신가요? 네, 정말 안타깝네요. 저도 몇 가지 들은 게 있어요. 매년 마감 기한에 맞춰 어김없이 출시되잖아요? 그런 환경은 건강한 리팩토링이나 복잡성 감소로 이어지지 않죠. 하지만 엄청난 돈을 벌잖아요. 그래서 그들은 사람들을 고용해 일하게 할 여유가 있죠. 그리고 당신은 그들이 충분히 지불할 테니 일하게 될 겁니다. 그들도 알거든요. 그들은 알아요, 맞죠? 그래서 이것의 일부는 더 많은 사람들이 일하면 더 많은 복잡성을 견딜 수 있다는 것입니다. 제가 일부를 머릿속에 담고 당신이 다른 부분을 담을 수 일부를 머릿속에 담을 수 있습니다. 그리고 저는 구분하고 싶습니다. 복잡성의 폭이 있고, 잘 구성된 시스템이 있다면 복잡성을 계층이나 모듈로 분해할 수 있습니다. 맞죠. 각각의 레고 블록은 단순하지만 매우 복잡한 것을 만들 수 있습니다. 그렇죠. 그래서 그것이 시스템 복잡성 대 컴포넌트 복잡성입니다. CSS는 믿을 수 없을 정도로 복잡합니다. 복잡하다는 말은 하나의 규칙을 보고 최종 문서에서 어떻게 나타날지 알 수 없다는 뜻입니다. 좋아요, 더 나은 도구로 이 문제를 해결할 수 있겠죠? 하지만 아니요, 우리가 얘기했듯이 시간이 지나면서 향하는 항상성 지점이 있습니다. 우리는 그 지점을 설정할 수 있지만 결국 그쪽으로 움직입니다. 이에 대한 연구는 실제로 1860년대까지 거슬러 올라갑니다. 이것이 제본스의 역설인데, 엔진이 더 효율적이 되었을 때 왜 석탄 소비가 줄지 않았는가? 하는 것이었죠. 답은 사람들이 더 많은 일을 했기 때문입니다. 저는 이것이 문제를 살펴볼 때 우리가 내려야 할 불가피한 결론이라고 매우 강하게 느낍니다. 즉, 시스템의 복잡성 정도는 우리가 누구이고 시간이 지남에 따라 무엇을 하는지와 연결되어 있다는 것입니다. 더 나은 도구나 방법을 사용해 복잡성을 줄일 때더 단순한 환경을 선택함으로써, 우리는 결국 그것을 다시 확장하게 될 것입니다. 자, 복잡성에 대한 몇 가지 이론에 대해 이야기해 봅시다. 저는 연구소 출신이라 논문 읽는 걸 좋아하거든요. 이것은 새로운 문제가 아닙니다. 순환 복잡도에 대해 들어보신 적 있나요? 네, 우리는 이걸 하지 않을 겁니다. 다행이죠. 하지만 소프트웨어 메트릭스를 단순히 추구하는 것이 우리가 하는 일을 측정하는 방법으로는 현명하지 않다고 생각합니다. 그러나 개념적으로 이해하는 것은 중요합니다. 요소들을 결합할 때 비용이 발생하고 문제가 될 수 있다는 점을 생각해볼 가치가 있습니다. 사실, 사람들은 1980년대부터 이를 연구하고 고민해왔습니다. 이는 1980년 IEEE 68권의 Meyer Lehman입니다. 이는 새로운 분야가 아닙니다. 1980년 판이지만, 소프트웨어 공학의 법칙에 대한 첫 논문은 1974년에 발표되었습니다. 우리는 이것들을 자세히 읽지는 않을 겁니다. 제가 여러분에게 알려드리고 싶은 것은 성공적인 시스템이 성장하는 요구를 충족하기 위해 성장한다는 인식이 새로운 아이디어가 아니라는 점입니다. 이는 흔한 문제입니다. 도구나 언어를 만드는 일을 하든, 여러분은 간단한 것으로 시작할 수 있지만 결국 복잡해질 수 있습니다. 우아하고 간단한 것이죠. 하지만 시스템에 더 많은 요구사항이 생기면 그에 대응해 추가하게 됩니다. 이는 매우 흔하고 합리적인 결과입니다. 그렇게 하지 않으면 시스템이 종종 고갈되고 사라집니다. 이 주제에 대한 훌륭한 논문이 있는데, 아직 읽지 않으셨다면 2006년에 나온 Moseley의 'Out of the Tar Pit'입니다. 이 논문은 우연히 발생한 복잡성과 본질적인 복잡성을 구분합니다. 본질적 복잡성은 줄일 수 없는, 제거할 수 없는 시스템의 일부입니다. 연기나 불과 같은 특정 물리적 과정을 모델링하려 할 때, 실제 작업을 수행하는 물리 부분은 제거할 수 없습니다. 제거하고 싶지도 않죠. 그것이 바로 목적이니까요. 하지만 우연한 복잡성은 그 외의 모든 것입니다. 예를 들어, "이런, 이걸 컴파일해야 작동하네", "Windows 11이 이 DLL의 ABI를 변경했어" 같은 것들이죠. 이런 것들은 우리가 들은 바로는, Davine이 11기가의 무언가를 다운로드하기 위해 전화기를 돛대에 매달았다는 이야기와 같은 것입니다. 우리 목적에서 이는 대부분 우연한 복잡성입니다. 따라서 복잡성에 대해 작업하고 생각할 때 이를 구분하는 것이 도움이 됩니다.예산을 어디에 쓰고 있는지, 복잡성을 도입할 때 신중한지 생각해보세요 어떻게 복잡성을 도입하고 있는지 고려해야 합니다. 또 다른 중요한 점은 Berkeley DB 팀이 쓴 오픈소스 아키텍처에 관한 훌륭한 에세이입니다. 솔직히 소프트웨어 엔지니어링에 관심 있다면 이 글을 꼭 읽어보세요. 오픈소스 소프트웨어 아키텍처는 아주 흥미로운 시리즈입니다. 기본적으로 오픈소스 커뮤니티와 인터뷰하고 그들의 소프트웨어에 대해 에세이를 쓰게 한 뒤 그것을 출판하고 공유합니다. 특히 BerkeleyDB 챕터는 뛰어나다고 생각하며, 저는 이것을 자주 떠올립니다. 소프트웨어 아키텍처는 변경이 이루어질 때마다 저하된다는 점입니다. 세상에서 가장 우아하고 훌륭하며 신중하게 계획된 시스템이 있다 해도, 그것은 진공 상태의 한 시점에만 존재하는 것이 아닙니다. 새로운 요구사항이 생기면 이 아키텍처는 퇴화하게 되고, 따라서 지속적인 보강이 필요합니다. 많은 투자를 한 큰 인터페이스가 한계에 도달하면, 그것을 변경하는 데 엄청난 비용이 들 수 있습니다. 저는 이 점이 좋습니다. 좀 더 수제작 특유의 느낌이 있거든요. 엑셀 팀의 모토는, 적어도 Joel Spolsky에 따르면, "의존성을 찾아 제거하라"입니다. 엑셀 팀의 모토는 Joel Spolsky에 따르면 "의존성을 찾아 제거하라"입니다.Excel이 자체 C 컴파일러로 만들어졌다는 꽤 신뢰할 만한 얘기를 들었습니다 심지어 마이크로소프트 내 다른 팀에도 의존하지 않고 자체 컴파일러를 만들 정도로 말이죠. 이게 꼭 필요하다는 건 아닙니다 그렇다고 불필요하다는 것도 아닙니다. 예산을 어떻게 쓸지 잘 생각해봐야 합니다. 이 주제에 대해 마지막으로 하고 싶은 말은 복잡성이 반드시 나쁜 것은 아니라는 겁니다. 복잡성은 다양한 놀라운 창발적 특성을 낳을 수 있습니다. 젤다의 전설, 브레스 오브 더 와일드를 보세요. 정말 훌륭한 커뮤니티가 형성되었는데, 이는 화학 엔진으로 복잡성을 잘 다루었기 때문입니다 그래서 시스템 간 복잡한 상호작용에서 많은 창발적 게임플레이 요소와 경험이 나옵니다. 하지만 시스템들은 우리를 가능케 하고 힘을 실어주는 방식으로 구성되어 있죠. 물론 로그라이크 팬이라면 이런 걸 오래전부터 해왔다는 걸 아실 겁니다. 자, 이제 어떻게 할까요? 그럼 지금까지 복잡성에 대해 살펴봤습니다. 제가 말씀드렸듯이, 복잡성을 없앨 순 없습니다. 그래서 우린 그냥 받아들여야 합니다. 더 나은 도구가 우리를 구원하진 않을 겁니다.그럼 우리가 가진 이 복잡성 예산을 어떻게 써야 할까요? 한 가지 접근법은 그냥 고개를 숙이고 일하면서 문제가 없는 척하는 겁니다. 이건 우리 삶의 모든 문제에 대한 꽤 흔한 해결책이죠. 그렇게 할 수도 있겠지만, 저는 여기서 고르디우스의 매듭을 끊는 몇 가지 방법을 제안해보겠습니다. 고르디우스의 매듭 이야기는 손잡이에 매우 복잡한 매듭이 있는 소 수레에 대한 것이었습니다. 사람들은 "이 매듭을 푸는 사람이 아시아 전체를 통치할 것"이라고 말했죠. 많은 사람들이 도전했습니다. 그러다 알렉산더 대왕이 왔고, 이야기 버전에 따라 다르지만 그는 그냥 "좋아"라고 하고 칼로 잘라버렸습니다. 즉, 정말 똑똑하거나 열심히 노력해서 문제를 해결하는 대신 그냥 속이고 규칙을 바꿀 순 없을까요? 그게 더 나은 접근법이라고 생각합니다. 더 나은 접근법이라고 봅니다. 한 가지 방법은 여기 있는 사람들이 좋아하는 걸 하는 겁니다. 그냥 처음부터 다시 시작하는 거죠. 문제를 완전히 없앨 순 없지만, 시계를 리셋할 수는 있습니다. 새로 만들어보세요. 처음엔 모든 게 쉽습니다. 복잡성은 사용자와 기능이 생길 때만 나타나죠. 새로운 프로그래밍 언어를 만들고, 새로운 VM을 시작하세요. 좋습니다. 장기적으로 이걸 바꿀 순 없지만압박이죠. 하지만 진심으로, 당신은 시계를 리셋할 수 있습니다. 그리고 이것이 Excel 같은 것들이 인기 있고 성공적인 이유 중 하나라고 생각합니다. 패키지 매니저가 없거든요. 매번 새로운 Excel 문서를 만들 때마다, 그것은 완전히 새로운 우주입니다. 이전에 했던 고통이나 실수가 전혀 없죠. 빈 페이지의 용서와 같은 거예요, 아시겠죠. 거기엔 뭔가가 있습니다. 저는 얼마 전 Strangeloop에서 John Romero의 강연을 들었는데, 그는 ID Software가 어떻게 이 저급 게임들을 계약자로서 만들었는지 이야기했습니다. ID Software 팀, 그와 Romero와 Carmack이 이런 종류의 저급 게임들을 만들었죠. 그들의 태도는 항상 처음부터 시작해야 한다는 것이었습니다. 그렇게 하면 정말 능숙해지고, 매우 빨라질 수 있으며, 매번 이전보다 조금씩 더 나아집니다. 그리고 우리는 실제로 더 나아진다고 생각합니다. 저는 새로운 언어를 배우고 새로운 생태계를 구축하는 것을 좋아합니다. 그것들이 성공적인 큰 이유 중 하나는 새로운 언어를 가질 때, 표준 라이브러리를 정리하고 아이디어와 사람들의 생태계도 정리할 기회가 있기 때문이라고 생각합니다. 새로운 출발점에서 시작할 수 있죠. 이것이 장기적으로 복잡성을 해결하지는 않겠지만, 적어도 중기적으로는 개선될 수 있고 더 나아갈 수 있습니다. 그래서 저는, 적어도 중기적으로는 개선될 수 있고 우리는 더 나아갈 수 있습니다. 그래서 저는, 알다시꽤 멋지고 재미있네요. 저는 그게 좋습니다. 제발 그런 것들을 더 많이 해주세요. 어느 정도는 마치 우리가 깨지지 않는 체제 속에 사는 것 같아요. Unity가 지배하거나 Google, Microsoft 같은 대기업들이 지배하는 것처럼 보이죠. 하지만 그건 그렇게 될 때까지만 사실이에요. Ursula Le Guin의 자본주의에 대한 멋진 인용구가 있는데, 이런 문제들의 일반화라고 할 수 있죠. 자본주의 자체가 발명품이었다는 거예요. 자본주의도 하나의 발명품이었습니다. 인용구를 읽어드리죠. 우리는 자본주의 속에 살고 있습니다. 그 힘은 피할 수 없어 보입니다. 왕권신수설도 그랬죠. 하지만 어떤 인간의 힘도 인간에 의해 저항받고 변화될 수 있습니다. 인간에 의해서 말이죠. 우리는 환경이 변할 수 있다는 것을 의심해선 안 됩니다. 환경은 만들어졌고, 변화할 것입니다. 우리는 어떻게 또는 언제 변할지 모르지만, 그건 불가피합니다. 자, 새로 시작할 수도 있고, 혁명을 일으키거나, 모든 걸 무너뜨릴 수도 있죠. 아니면 그저 덜 하면 됩니다. 더 적게 하세요. 제 플레이데이트가 있나요? 여러분도 있나요? 누구 플레이데이트 가지고 계신 분? 네, 이거 정말 좋아요. 흑백이고 플랫폼도 하나뿐이죠. 작고요. 심플합니다.한 가지 색상으로만 나옵니다. 검정색 또는 흰색 단 한 가지 색상만 있죠, 어떻게 생각하느냐에 따라 다르겠지만요. 버튼도 많지 않고, RAM도 많지 않고, 사실 거의 없습니다. 약간의 네트워킹 기능이 있고 하드웨어 플랫폼도 하나뿐이라 호환성 문제에 대해 걱정할 필요가 없습니다. 음... 에뮬레이터가 있긴 한데, 이건 좀 다르게 작동하고, 부품 조달 문제로 인해 다른 마이크로컨트롤러를 사용해야 했지만 네이티브로 트랜스파일됩니다. 그들은 정말 잘 하고 있어요. 어쨌든, PS5나 Xbox, PC, 스위치, 3DS 등을 위해 개발하는 것보다 훨씬 간단합니다. 하나의 코드베이스로요. 정말 멋진 일이죠. 그리고 규모가 작기 때문에 매력적이에요. 그리고 범위가 좁을 때, 그 에너지와 복잡성 예산을 다듬는 데 쓸 수 있습니다. 작은 플랫폼에서는 작은 아이디어도 빛날 수 있죠. 자, 복잡성을 해결할 순 없지만, 상황을 더 악화시킬 순 있습니다. 이는 실제로 1962년 엥겔바트의 '인간 지성 증강'에서 나온 내용입니다. 이는 디자인 개입을 통해 실제로 사람들의 경험을 바꿀 수 있다는 것을 보여줍니다. 바꿀 수 있다고 했지, 개선할 수 있다고는 하지 않았습니다.네, 그렇죠. 우리는 소프트웨어 개발 측면에서 상황을 꽤 나쁘게 만들었습니다. 이것은 제가 항상 보여주는 가장 좋아하는 슬라이드입니다. 이것은 클라우드, 네이티브 클라우드, 클라우드 파운데이션, 클라우드 네이티브 생태계입니다. 저는 항상 이름을 잘못 말합니다. 이는 표면적으로 약 20조 달러 규모의 회사들을 보여줍니다. 어쨌든, 이 모든 것을 외워주세요. 2022년에 웹 애플리케이션을 만들고 싶다면 끝에 퀴즈가 있을 겁니다. 이것을 화면에 다 담으려고 브라우저를 축소해야 했습니다. 이제 우리의 연구에 대해 조금 말씀드리겠습니다. 이는 흥미로울 수 있기 때문에 이 주제와 연관됩니다. 우리의 접근 방식은 완전히 새로 시작하는 모델이 아닙니다. 오히려 더 적은 것으로 조금 덜 하는 모델에 가깝습니다. 그리고 우리 연구 관심사 중 하나는 이런 사고를 위한 도구들을 기반으로 합니다. 연구 그룹으로서 우리가 관심 있는 큰 부분은 단순성 대 복잡성이나 탈중앙화가 아닙니다. 하지만 우리는 그 영역에서 일해야 합니다. 왜냐하면 우리가 원하는 것은 우리가 통제하고, 소유하고, 우리 것이며 빼앗길 수 없는 도구들이기 때문입니다. 그래서 우리는 이 연구를 로컬 퍼스트 소프트웨어라고 부릅니다. 기본 아이디어는 저 전체 기술 차트를 배우는 대신에실제로 컴퓨터에서 그런 것들을 할 수 없다는 것입니다 컴퓨터에서 실행하면 안 되고, 그것들은 모두 클라우드에 있기 때문입니다. 그래서 컴퓨터에서 작동하는 소프트웨어를 만들고 싶다면, 그런 것들을 사용할 수 없을 뿐만 아니라 사용할 필요도 없습니다. 이것은 일종의 단순화라고 할 수 있죠, 절단을 통한 단순화입니다. 우리는 그냥 클라우드의 대부분을 잘라내고 로컬에서 개발합니다. 우리는 수년간 여러 플랫폼을 다뤄왔습니다. 현재는 브라우저에서 개발하고 있지만, 모든 것을 IndexedDB에 저장합니다. 우리의 핵심 믿음 중 하나는 협업이 생각하고 만들고 실행하는 데 매우 중요한 부분이어서 우리 플랫폼의 근본적인 부분이 되어야 한다는 것입니다. 그래서 우리는 컴퓨터에서 실행되는 소프트웨어를 만들면서도 다른 사람들과 협업할 수 있게 하는 기술을 탐구해왔습니다. 온라인과 오프라인 상태를 오갈 수 있게 하면서 말이죠. 이를 뒷받침하는 모델은 automerge라는 데이터 구조입니다. 일종의 휴대가능한 버전 관리 JSON 같은 데이터 구조죠. 데이터를 위한 git이라고 생각하시면 됩니다. 휴대 가능한 버전 관리 JSON 데이터 구조라고 볼 수 있습니다. 이에 대해 길게 이야기할 수 있지만, 너무 자세히 설명하고 싶지는 않습니다.우리의 특정한 종류의 개발 관심사입니다. 하지만 정말 놀라운 것은 빠르고 단순하며 자신의 컴퓨터에서 실행되는 소프트웨어를 만드는 느낌입니다. 만약 여러분이 저처럼 지난 시간 동안 클라우드 서비스를 구축하고 하늘에서 실행하는 일을 했다면. 저는 기억에 남는 정전 사태가 있었는데 아마존이 US east one을 꺼버렸습니다 허리케인 때 발전기가 작동하지 않아서요. 우리는 3일 동안 모든 사람의 데이터베이스 백업에서 시스템을 재구축하느라 힘들었습니다. 그때 동료가 저를 보며 이렇게 말했죠, "난 존재하지 않는 컴퓨터를 고치고 있어, 한 번도 가본 적 없는 데이터 센터에서, 한 번도 만난 적 없는 사람들을 위해." 그의 눈에는 멍한 표정이 있었고 저는 "그래, 커피 더 필요해?" 라고 말했죠. 이런 면에서 이 일을 하는 것은 저에게 일종의 속죄 같은 거예요. 제가 이런 단일 장애점들을 만들었으니까요. 자, 이제 이 모든 것을 좀 정리해 봅시다. 이 복잡한 세상에서 우리는 어떻게 살아가야 할까요? 복잡성은 우리 시스템이 내부적 상호작용을 가질 때 발생합니다. 복잡성은 우리 시스템이 내부적 상호작용을 가질 때 발생합니다.맞죠? 복잡성은 단순히 '많은 것들이 있다'는 의미가 아닙니다. 그것은 모든 것들이 서로 부딪히기 시작하고 예측할 수 없는 결과를 초래할 때입니다. 그리고 복잡성은 시스템 인센티브의 자연스러운 결과이기도 합니다. 많은 사람들이 어떤 것을 사용하고 있고 그들의 필요를 듣고 있으며 더 많이 배우면서 진화하고 있다면, 결국 복잡한 것으로 끝나게 될 것입니다. 더 나은 도구가 이를 바꾸지는 못할 것입니다. 복잡성은 우리가 누구인지와 우리가 내리는 선택의 결과입니다. 물론, 예산을 더 빨리 소진할 수는 있습니다. 하지만 결국, 프로젝트가 복잡성 척도에서 어디에 위치하게 될지는 얼마나 많은 시간과 아이디어가 투자되었는지에 더 많이 좌우됩니다. 그래서 우리는 복잡성을 이길 수 없지만, 그것에 패배할 수는 있습니다. 그렇다면 우리의 대응 전략은 무엇일까요? 우리는 처음부터 다시 시작할 수 있습니다. 의존성을 제거할 수 있습니다. 범위를 줄이고, 덜 할 수 있습니다. 맞죠. 우리의 아키텍처를 단순화할 수 있습니다. 그리고 매우 중요한 것은 이러한 곱셈적 환경에 들어가고 있다는 것을 의식하고 식별하는 법을 배우는 것입니다. 맞죠? 일단 여러 플랫폼으로 포팅을 시작하고 플랫폼별 추상화를 구축해야 할 때, 그 복잡성을 어떻게 관리하나요? 어떻게 복잡성을 격리시키나요? 그리고 성공의 큰 부분은 복잡성을 격리시키는 것입니다. 하지만 저또한 심연을 응시하는 것에 대해 언급하고 싶습니다. 당신은 그걸 할 수 있어요, 맞죠? 복잡성을 받아들이고 활용하세요. 그래요. 그건 고대신과의 거래와 같습니다. 위대하고 끔찍한 일을 이룰 수 있지만, 위대하고 끔찍한 대가를 치르게 될 거예요. 그래도 괜찮지만, 이렇게 할 때는 정말 조심해야 해요. 그리고 그 복잡성을 어떻게, 언제 받아들일지 신중히 결정해야 합니다. 마지막으로 말씀드리면, 우리는 복잡성을 해결할 순 없지만, 더 나은 소프트웨어를 만들 수는 있습니다. 또는 사이클리스트 그렉 르몽의 말을 빌리자면, "절대 쉬워지지 않아요. 단지 더 빨라질 뿐이죠." 이상입니다.