3 ms·
That is the dream of the Open–closed principle in SOLID and Postal's law like in RFC 1122. While these ideas are good defaults, unfortunately they lead to unma
by nyrikki 2y ago
That is the dream of the Open–closed principle in SOLID and Postal's law like in RFC 1122.
While these ideas are good defaults, unfortunately they lead to unmaintainable, monolithic, insecure code. One needs to make decisions on tradeoffs based on current needs and balance on how to move forward.
Remember how Tor anonymity was broken due to Postal's law? Or how many encryption downgrade attacks have resulted in breaches?
IMHO the better option, but a hard sell, is to focus on externalization and methods like ports and adapters and DDD to help you write interfaces that are more likely to be stable, while still having polices in place to help you move forward when needed.
The chaos report from the 90's and many many more studies since have showed that trying to get software projects perfect from the beginning is impossible.
There are just to many unknowns and trying to plan for them all is impossible.
In some situations like REST it is easier so that breaking changes can be released in a new API version, with a deprecation schedule.
With other things like graphql, ffi etc... it becomes far harder.
If changing the language results in API breakage, you weren't following the inversion principle.
Even with language features, what you call a 'stack' is an abstract data type, not a concrete implementation. While there may be very strong disintegration drivers like performance or language limitations that drive you leaking implementation details or limit your ability to confirm to the ADT while maintaining the other properties you want, that is not specifically the concrete implementation that results in that breaking.
ADT's like lists, stacks, or queues are defined by their semantics from the user's perspective.
Obviously Rust's design decisions may make duplicating the semantics while gaining the advantage of the switch challenging or possibly impossible.
While not really the target audience for either language, I would prefer zig's crashing behavior to hyper using unsafe evaluations of macros as an example.
https://github.com/hyperium/hyper/blob/30f2961e89eb306780d856e6e2c1ee10ffbbafd2/src/ffi/macros.rs#L39 https://github.com/hyperium/hyper/blob/30f2961e89eb306780d85...
Both are better than c's problems like `x[4]` actually being `*x` though. (IMHO)
The point being is, do target a forever API as a default ideal, but don't stick to that ideal too strongly or it will result in an outcome that is far worse for anything more complicated than say UNIX file operations which are simple enough to do so.
We are in a industry where the 'best' option rarely if ever exists and we almost always have to choose the least worst options.
If some external party can figure out how to refactor without breaking the ADT/API semantics, you shouldn't care except be impressed that they avoided leaking their implementation details to you.
- aw1621107 2y ago> While not really the target audience for either language, I would prefer zig's crashing behavior to hyper using unsafe evaluations of macros as an example. > https://github.com/hyperium/hyper/blob/30f2961e89eb306780d856e6e2c1ee10ffbbafd2/src/ffi/macros.rs#L39 https://github.com/hyperium/hyper/blob/30f2961e89eb306780d85... This looks basically like a port of something like Kotlin or C#'s ?. operator - the macro checks whether the pointer is null, returns err if it is, and dereferences the pointer otherwise. The part highlighted in the link looks like it's part of the macro implementation - there don't seem to be any "direct" uses of that particular rule in calling code and it's only invoked via the other rules in that macro definition. I think that should make that bit null-safe at least. Lifetime safety might be a bit trickier, especially since that bit is part of hyper's C API so idk if there's anything Rust (or Zig, for that matter) could do to ensure the pointer is still valid when dereferenced.