snaggen
The core problem I see with Inheritance is that the abstractions tend to fall apart and no longer be true. Lets use the Animal example. It is easy, when you have Animal -> Cat and Animal -> Dog. But as soon as we become more specific like Animal -> Mammal -> Cat, Animal -> Fish -> Hammerhead Shark, Animal -> Bird -> Bald eagle, we risk of getting in trouble. Because now for all purposes we assume things about the Fish, Birds and Mammals, like fish is in the sea and mammals are live on land. We know that this is not strictly true, but for everything we need it works. Later we need to handle a dolphin… should that be a fish, or do we need to restructure the whole program. If we treat it like a fish, then we might be even deeper in trouble later if we would need to handle birth. And even if we restructure our program to be correct to handle birth, we might stil forget that some mammals lay eggs like the Platypus, so then things break again if we need to handle that. We tend to see Inheritance as a rigid fact based structure, but the core problem is that it is just a bunch of assumptions we dictate in a very rigid way that is hard to change.
Composition have no problem with specifying the platypus as a mammal that lays eggs and have a beak.
He is one of the key people to get all of the low level components “just work”, and a big part of why I use Fedora as my go to desktop distribution. This kind of work is a key part of providing a smooth desktop experience, sad to see RedHat stopping to support it.
If you look at Rust for example, then you specify the Traits instead. So, you could define a trait that defines the properties for birth, another to define if the animal have a beak, and another one to define the number and type of legs. The each animal implement these traits, which then properly can define a duck, cat and a platypus.
Traits are similar to an interface, but with some differences. Here is a comparison with Java interfaces https://stackoverflow.com/a/69485860
Normally during a project, I tend to restructure the code quite a bit.
First when it is small, I do it like you and have everything in one file, then as it grows I start to split out the things in to multiple files/modules. Then as it grows even further, I create subfolders. Try to define parts of the algorithms and break them out to their own modules. Like if you have a scheduling part, then you move that to scheduler.rs
. Also, move out special types to types.rs
, error types to errors.rs
to keep the area with the actual algorithms more clear.
So, that the code feels like a mess as it grows is just a normal thing. And often, it is not worth trying to plan that much ahead since it is very difficult to predict the needs.
But for a REST server I have something like this
src/main.rs
src/types.rs
src/api/v1/mod.rs
src/api/v1/errors.rs
src/api/v2/mod.rs
src/api/v2/errors.rs
src/api/v2/types.rs
src/tests/v1.rs
src/tests/v2.rs
But the before the v2 version of the api, there was just a src/api.rs, src/errors.rs . So, I think the key is to not be afrad to shuffle code around and restructure it as you need. And it will not always be good, but then you just do it again. One of the things with a very strict language like Rust is that you can shuffle it around, and rewrite it without a big risk of adding hidden bugs.
I’m happy to see that the maintainer listened to the users, so we got the best possible outcome.
I’d be happy if all movie posters looked like this from now on. They are brilliant!