Wanting to incorporate an http server into a C project of mine, the only battle-tested or feature-complete options either allocated dynamic memory UTH without an option to override the allocators, or are too opinionated with the core API, like mandating callbacks for everything. Suprisingly there's no decent (single header) C library that don't have these 2 issues, at least that I could find.
I disagree. Technology is inherently political, and it’s valuable and important to get informed and reminded about the many horrible people that are directly or indirectly tied to any mentioned organizations and projects.
The OpenGOAL project is a project to reverse engineer the Jak and Daxter video games and the custom programming language they were developed in: GOAL.
The long-term objective of the project is to make Jak and Daxter run natively on a PC by decompiling and recompiling it with OpenGOAL, our reverse engineered version of GOAL for x86-64 PCs. We do not host any game assets or copyrighted material from the game – we only host tools for reverse engineering and porting the game. The user must provide a copy of the game to use our tools.
When working on large applications, by far the single most important factor in performance is having simple and understandable code.
Understandable but slow code can be fixed. Incomprehensible code can't, so it either stays slow or gets worked around with caching/async processing/etc.
If you want fast software, you should write the simplest thing that isn't obviously stupidly slow, then measure and see what parts you need to change. Occasionally you need to make pieces less readable to make them faster, but it's going to be 5% of the application, not the whole thing.
This is only true up to some point of skill & complexity. Hotspot optimisation only takes you so far. Eventually you can end up with a program that is fast everywhere but which is still somehow slow at the macro level. Like LLVM.
Truly fast software is made by thinking about data flow from the start. If you use the right data structures, the code takes care of itself.
But this is far beyond Clean Code. The examples in that book are neither readable nor performant. He uses bad data structures and hidden mutation everywhere. In the large, that approach leads to a buggy, fragile mess.
Choosing the right data structure isn't in opposition to making simple, readable code; it's part of it. Nothing over-complicates code more than a bad choice of data structure. If you pick the data structure that simplifies your code the most, the vast majority of the time that is also the right choice for performance.
I disagree with much of the advice in Clean Code, but it has nothing to do with performance. Clean Code is bad because it produces overly-complex unreadable code. The reason that it produces poor performance isn't because the code is too readable; to the contrary, if the code was more readable it would be more obvious that it's using the wrong data structure.
I'm not saying that you shouldn't think about performance from the beginning. I'm saying that you shouldn't sacrifice simplicity and readability for the sake of performance until you are sure it's necessary because those things are rarely in opposition to each other on the macro scale.
Nothing is worse for performance than doing work you don't need to do and unreadable code tends to do a lot of that if it has been actively maintained for more than a year or two.
If you go with simple, straightforward data structures you often get adequate performance at the macro level. In my experience, getting really good performance often involves being clever with data structures. It depends how far you want to push performance.
I’ve done a lot of work optimising text CRDTs. There, the simple data structure is (essentially) a list which contains metadata for each character. But you’re constantly scanning and inserting into the list. You can improve it in two ways: first, make each list item store the metadata for a connected span of characters. Second, use a b-tree for fast insertion. Make the b-tree store aggregate metadata in internal nodes. That gets you orders of magnitude better performance - O(n) per keystroke to O(log n). RLE gets ~10x lower ram utilisation. It’s only the obvious data structure when you’ve thought about the problem a lot. And you have to write your own btree - there are no libraries for this. At least, none I have found.
> I'm saying that you shouldn't sacrifice simplicity and readability for the sake of performance until you are sure it's necessary
It really depends on the domain. If you’re making a note taking app, you probably get good enough performance by doing the obvious thing. If you’re making a browser, database, llm inference engine or 3d game engine, it pays to think about perf from the start. But my impression is that most people on this site aren’t doing that sort of thing.
That seems like a pretty niche problem. There are already numerous high quality browsers, databases, llm inference engines and 3d game engines and only a tiny portion of devs are working on that type of thing.
The vast majority of applications are better off using one of the many high-performance, battle-tested implementations of b-trees that already exist, which, for users of those implementations, is one of the simplest and most commonly used data structures; we just call them databases and filesystems instead of b-trees.
Every rule has exceptions but you should know the rules before you decide to break them. For anyone other than an experienced expert, writing your own b-tree implementation in a production system is an extremely foolish decision (if it's for fun or learning, do whatever you want).
There are already numerous iOS apps and numerous websites. And yet, people keep making more!
I think I broadly agree with your overall point. I’ve just spent a lot of my career working on niche problems like this. And there are a lot of people working on systems software. Windows, Linux, macOS, chrome, postgres, etc don’t write themselves. But unless you move in those circles, you can spend your whole life never interacting with any of those engineers.
> we just call them databases and filesystems instead of b-trees.
The b-trees I’m talking about are in memory. Btrees often outperform other kinds of in memory tree structures (avl, rb, binary, etc) because you get fewer dram memory stalls.
I'm not disagreeing that there are cases where it makes sense to implement a b-tree; I don't think there are any cases where it makes sense to implement a b-tree (in production) as a person who needs beginner-level advice about code organization.
This. I've spent a good chunk of my career on performance work and this idea that you can hotspot optimize stuff after the fact is utterly wrong and the reason why so much of your software sucks battery and runs like crap.
Clean code like approaches have a very real cost for users (even in languages with good optimizers) and is usually unfixable after the fact.
> You're sacrificing end user experience for developer ergonomics.
No. You may be sacrificing end user experience, but it's not guaranteed. You have to examine the system under development to determine which style is appropriate.
If you actually have to process huge numbers of these objects, then yes. But if you don't, if whatever the actual real-world object is trickles in at 10 per second, do you need to worry about performance and cache misses here? You're already going to suffer from cache misses because the processing rate is so low.
So you get to make an engineering choice based on circumstances. If you need high-throughput, use a design that satisfies that requirement but maybe forfeits flexibility and maintainability. If you don't, then you can lean towards a design that forgoes a bit of performance in favor of flexibility and maintainability.
Use your judgement, don't follow any rule blindly whether it comes from Muratori or Martin.
I had a dead screen on a phone, so I was able to enable screenreader mode, used that to navigate to enable USB debugging and allow scrcpy screensharing.
That process cost me a couple of days and a similar working phone for testing, but it worked and I could save all the data on the phone.
I work doing mobile app development and scrcpy along with iphone mirroring for iphone have made it much easier to do typing which is super helpful when testing flows that involve filling out forms.
Only gripe with scrcpy (and an extremely minor one at that) is that tab doesnt automatically advance input fields in the app, while it does in iphone mirroring
reply