7 ms·
Well it's hard to argue about that tradeoff in general, but I think the existence of languages like Python, Ruby and PHP is compelling. Though I'd accept the ar
by crabmusket 3y ago
Well it's hard to argue about that tradeoff in general, but I think the existence of languages like Python, Ruby and PHP is compelling. Though I'd accept the argument that they help optimise for neither performance nor changeability!
My perspective is necessarily limited, but I often see optimisation as a case of "vertical integration" and changeability as about "horizonal integration".
To make something fast, you can dig all the way down through all the layers and do the exact piece of work that is required with the minimum of useless faffing about for the CPU[0]. But to make something robust, you might want to e.g. validate all your inputs at each layer since you don't know who's going to call your method or service.
Regarding the DOD/OOP wars, I really love this article, which argues that OOP doesn't have to be bad[1]. I also think that when performance is a requirement, you just have to get more particular about your use of OOP. For example, the difference between Mesh and InstancedMesh[2] in THREE.js. Both are OOP, but have very different performance implications.
[0] Casey Muratori's "simple code, high performance" video is an epic example of this. When the work he needed to do was "this many specific floating point operations", it was so cool to see him strip away all the useless layers and do almost exactly and only those ops.
[1] https://www.gamedev.net/blogs/entry/2265481-oop-is-dead-long-live-oop/ https://www.gamedev.net/blogs/entry/2265481-oop-is-dead-long...
[2] https://threejs.org/docs/index.html?q=instanc#api/en/objects/InstancedMesh https://threejs.org/docs/index.html?q=instanc#api/en/objects...
- GuestHNUser 3y agoThanks for the thoughtful reply. > Well it's hard to argue about that tradeoff in general, but I think the existence of languages like Python, Ruby and PHP is compelling. Though I'd accept the argument that they help optimise for neither performance nor changeability! I see the point you're making, and I don't disagree with it. But I should be a bit more clear in what I really meant in my parent comment: Given whatever language a developer is working in, whether it is fast like C++ or a slow language like Python (or perhaps even Minecraft Redstone), I think the programmer that takes a data oriented approach (meaning they write their code thinking about the kinds of data the program can receive and the kind it will likely receive, along with what operations will be the most expensive) will have better code than a programmer that makes a nice object model following all the SOLID principles. The majority of the OOP code I've worked with spends too much time caring about abstractions and encapsulation that performance is lost and the code is no better to work with. > Regarding the DOD/OOP wars, I really love this article, which argues that OOP doesn't have to be bad[1]. I also think that when performance is a requirement, you just have to get more particular about your use of OOP. For example, the difference between Mesh and InstancedMesh[2] in THREE.js. Both are OOP, but have very different performance implications. Absolutely agree here. Classic gamedev.net article. ECS != DOD and I think the next parts of the article illustrate how DOD isn't necessarily in opposition with programming paradigms like OOP and FP. With that said, I think it can be argued that common patterns within both OOP and FP circles are a hurdle at times to utilizing hardware to its fullest. Here's Casey Muratori's argument against SOLID principles[0] for instance. --------------------- I think the point still stands: performance isn't in opposition to making a maintainable/changeable program. [0] https://youtu.be/tD5NrevFtbU?si=sED7befZRnVnQIxQ https://youtu.be/tD5NrevFtbU?si=sED7befZRnVnQIxQ
- Jach 3y agoA missing element to the conversation is another interpretation of DOD, that is, domain-oriented design. My favorite writing on the matter is "Programming as if the Domain (and Performance) Mattered" (https://drive.google.com/file/d/0B59Tysg-nEQZSXRqVjJmQjZyVXc/view?resourcekey=0-TUcDaYWBXZ4WO4RtjTByBg https://drive.google.com/file/d/0B59Tysg-nEQZSXRqVjJmQjZyVXc...) When OOP has bad performance, or is otherwise another instance of ball of mud architecture, it often stems from not modeling the domain correctly. Only using or being forced to use an inferior conception of OOP (i.e. OOP as merely fancy structs + function pointers) doesn't help either, and ends up encouraging the sorts of patterns found in GOF even preemptively before they can maybe earn their keep. And what's especially insidious about Kingdom of Nouns style OOP is that just because you have named something, or created a type hierarchy, does not actually make it a particularly good model of anything. If you interview enough people, you'll find some thinking it's entirely reasonable to do the equivalent of making a Car a subclass of a Garage just because garages contain cars. When bad modeling infects production code, it's difficult to remove, especially when it's so overgrown that a bunch of other code is created not to fix the modeling but to try and wrangle a bit of sanity into localized corners (often at the further expense of performance -- frequently from a lot of data copying and revalidating). On the other hand, modeling things too close to the hardware, or (as the linked paper goes through) too close to one ideal of functional programming purity (where you want to just express everything with map and reduce on sequences of numbers if you can, in theory giving high performance too), can severely get in the way of changing things later, because again you're not actually modeling the domain very correctly, just implementing one clever and specific mapping to raw numbers. When the domain changes, if your mapping was too coupled to the hardware, or too coupled to a nice map/reduce scheme, the change throws a big wrench in things. Sometimes, of course, such direct hardware and code exploitation is necessary, but we live in a fat world of excess and most business software isn't so constrained. An interesting example from the past could be Wolfenstein 3D, where its doors and especially its secret push walls are handled as special cases by the raycaster. Carmack initially refused to add push wall functionality to his engine, it seemed like it would be too big of a hack and possibly hinder performance too much. Big special cases as ifs down in the fors usually suck. After much needling and thinking though, and realizing the game really did need such a feature, he eventually got it done, surprising everyone when at a final attempt at convincing him to add them, he revealed he already did it.
- hinkley 3y ago> But to make something robust, you might want to e.g. validate all your inputs at each layer since you don't know who's going to call your method or service. If you actually have layers, then repeated guarding is not necessary. The guards are necessary when the same function appears at multiple levels of abstraction - when calls reach across multiple layers of even back up the hierarchy. In Angular you had services. Everything was meant to talk to those to get to the data, and I think a lot of people misunderstood the value this provides. If you want user data to look a certain way to the front end, you can do cleanup at insertion time (which can be spread out over years when you didn’t know it was a problem) or at read time. Ideally you want this in the backend, but it can be a challenge because you don’t know what you need until you need it, and expecting the backend people to drop everything to tackle your latest epiphany RFN is unreasonable. But you can make the Service work the way you would like the backend to work, and make a pitch for that logic to move into the backend. It’s generally self explanatory code, without a lot of tendrils elsewhere. Airlifting it across process boundaries is far easier than surgically removing a set of assumptions and decisions smeared across the code. “Beyond this point, all foo have bar, and you don’t need to worry about it.” This takes architectural discipline but the dividends are great.