Ask HN: In general, prefer your abstractions vs. runtime ones ASAP?
I’ve been working on an http server in C as a side project, and while studying the code bases of other C projects, I’ve noticed that there is a tendency to start programming in terms of the project’s own abstractions (structs, functions) at the lowest levels, or “as soon a possible”; e.g., to use a custom file descriptor structs, custom versions of read(2) and write(2) or equivalent “enhanced” functions. What I mean is that I see for example the native FILE or bind/listen/accept once, but then they are either always wrapped or remain encapsulated at a lowest implementation layer.
The way I see it, this effectively maximizes the proportion of your code that speaks in your own abstractions, which certainly makes coding easier (working in your vernacular, so to speak).
Is this intentional, and is there a principle or pattern being applied? For reference, I’ve been looking at ngnix, libuv, livevent, redis and SQLite, the latter two a while back so they may not follow my description.
2 comments
[ 2.7 ms ] story [ 18.0 ms ] threadI don't want to over engineer it, so I don't write a wrapper for file descriptor.
I studied lwan, for inspiration. I too see it has some abstraction layers. I think it is mainly for cross-compiling on different platforms, it needs to abstract the socket, event, io APIs.
My project is linux only. So I want to stay simple.
For example, let’s say you want to write a 100 byte struct to file, and write returns 0 and sets errno to EINTR, or return 67 and keep errno as is.
Why would you write the code to handle those cases in every function that writes data? How would you fix all those entry points if you discover your handling is buggy, or that some commonly used file system is buggy, and you need to implement a workaround?
Similarly, if you read those 100 bytes, your call may return 67 and update the file position. You need code to recover from that. Why duplicate that throughout your code?