[ $davids.sh ] — david shekunts blog

🧐 **You don't know what OOP is 🧐

# [ $davids.sh ] · message #129

🧐 **You don't know what OOP is 🧐

**Link to the article A bold statement, I know, but try to answer the question: "What is OOP?" – without using the words Encapsulation, Inheritance, Polymorphism, and Abstraction.

If you can't do it (and about 90% of developers can't, even those who use OOP), then you don't know what OOP is.

And I'll say even more, OOP comes in two types.

So, what is OOP and what types does it come in, let's break it down now:

https://fop.davidshekunts.ru/you-dont-know-oop

#oop #fop

  • @ 4ront · # 216

    What about Ruby?

  • @ 🦾 IT-Dressing room 💪 · # 217

    The issue is that in the languages presented, I have enough expertise to confidently say that FOP (Functional Object-Oriented Programming) would fit well with them. However, with Ruby, I’ve only written code using Rails, and that was about 5 years ago :(

    I’d be happy to add Ruby to FOP, but I need the help of a more competent Ruby developer to ensure they are compatible.

  • @ 4ront · # 218

    I apologize. I didn’t clarify.

    Regarding this statement, I asked: *"Moreover, it’s astonishing and extremely amusing that practically the only language that maximizes OOP architecture is Erlang, one of the most canonical functional programming languages…"

    *Ruby is a language with a strong emphasis on object-oriented programming. The language has many features for working with objects: creating, modifying, protecting, and performing other actions with them. All capabilities are designed to implement OOP and make working with this approach more convenient.

  • @ 🦾 IT-Dressing room 💪 · # 219

    Got it

    As I describe in the article, we have 2 OOP concepts: OOP syntax and OOP architecture

    Ruby fully supports OOP syntax

    BUT from an architecture perspective, it's Erlang that truly embodies OOP: each Erlang function acts as a mini-application that can receive messages from its internal message queue (a built-in language mechanism) and send messages to other functions (these messages also get queued)

    Each function is fully encapsulated, with functions communicating via serializable messages (this is rarely discussed, but this small aspect is actually a crucial part of OOP - no OOP language prohibits non-serializable arguments in class methods, which already violates OOP architecture; this is a big topic and I think I'll write a separate article dedicated specifically to "serializable messages in OOP"). Each function is connected to a set of others it communicates with, forming a graph

    Therefore, Erlang's internal structure fully aligns with OOP architecture, while Ruby (like Java, C#, etc.) merely provides OOP syntactic constructs and leaves it to developers to implement the architecture at the code level

  • @ 4ront · # 220

    Here we can recall SmallTalk. The language in which Alan Kay embedded his OOP ideas.

    *The main ideas of Smalltalk are:

    * Everything is objects, and all their interaction happens through message passing; * Everything is modifiable; * Dynamic typing

    *———

    Long before Smalltalk appeared, Alan Kay formulated three fundamental principles of object-oriented programming (Simula-67):

    * An object is the basic unit of an object-oriented system. * Objects can have state. * Message passing is the only way for objects to exchange information.

  • @ 🦾 IT-Dressing room 💪 · # 221

    Yes, SmallTalk is also a great example.

    The situation with Erlang amuses me precisely because it is functional in terms of syntax and it is preferable to write in a functional architecture, but the language's design itself adheres to OOP principles.)

    By the way, a question—where exactly does the phrase "everything is available for modification" come from? It sounds extremely contradictory to encapsulation, maybe I don’t quite understand it correctly.

  • @ 4ront · # 222

    No surprises here. Taken from the wiki (article in Russian).

    * Everything is available for modification. If you want to change the integrated development and execution environment itself, you can do it in a running system without stopping, recompiling, or restarting. If you need a new language control construct, you can add it. In some implementations, you can also change the language syntax or the way the garbage collector works.

  • @ 🦾 IT-Dressing room 💪 · # 223

    Ahhh, got it, it's about Live Coding, the ability to modify the application without restarting it, directly on the fly while it's running in the interpreter + the ability to change compilation rules and language constructs.

  • @ [ $davids.sh ] · # 1228

    In the previous post, I talked about an RMQ issue where it would silently delete queues without any notification.

    This behavior was so bizarre that it had to be either deeply buried within RMQ, making it hard for many to access, or so obvious that I simply missed it.

    No matter how much I dug into the deep web for solutions to my problem, I found nothing suitable. So, I decided to approach it from a different angle: rereading the "Getting Started" guide.

    Once again, I came across a paragraph stating: "you should not use auto-delete queues if you are naming them yourself" – and an example: "if you create a queue with auto-delete, disconnect from one node, and then quickly switch to another, RMQ won't know what to do, and you'll encounter client-side errors."

    And we were indeed creating auto-delete named queues (I'll explain why in the next post), which is precisely what we needed from RMQ.

    What's more, in the scenario described above, it does send an error and close the connection. However, this is perfectly normal behavior; RMQ tends to close connections for the slightest reason. That's why all our logic is designed to reconnect and restore all subscriptions.

    And then it hit me: "What if this bastard behaves the same way when one of the nodes goes down, but upon recovery, it simply doesn't send us a connection break due to a configuration race condition?" – and, damn it, I was right.

    When a node with auto-delete queues disconnects from the cluster (even for a couple of seconds), and the consumers are on a neighboring node, the cluster doesn't close their connections or throw errors. However, it does delete the queue...

    And the only damn sensible solution is to make all queues replicated (quorum). Astonishingly, this instantly transforms RMQ into a mentally challenged version of Kafka.

    But the explanation is too long, so I'll cover it in the next post.

  • @ [ $davids.sh ] · # 1230

    We had two communication patterns:

    Event Driven Architecture (we throw an event and forget about it, and a bunch of readers on the other side consume it) and RPC (we send a request and wait for a response from one reader) + obviously, all of this must work in a cluster mode with at least 3 nodes.

    EDA must guarantee us: "if we throw an event and see that it has entered the queue, then eventually it can be read from the other side in the correct sequence by the required number of instances."

    RPC must guarantee: "if the reader is not available, we must find out about it to perform a retry; if it still doesn't appear, then return a timeout; and if the reader is available, then get a response within an optimal time interval or return a timeout."

    RMQ, NATS, and Kafka walk into a bar.

    NATS is a message broker, meaning its task is to allow subscribing to and sending messages to topics in a fire-and-forget format, and it does not guarantee order.

    It's great for RPC (it even has a built-in module), but since it doesn't guarantee sequence and that a message will reach a reader that hasn't come up yet, we can't use it for EDA (I'll immediately say, we're not considering JetStreams).

    Kafka is a distributed log: we write to the end and read from a desired point (offset).

    It perfectly solves the EDA problem (the only complexity is in calculating partitions and implementing external locks on queues, but more on that below) and RPC can be implemented in general (it will just be a bit "heavy").

    RMQ is something in between the two worlds: fire-and-forget, with guaranteed sequence, and distribution and uniqueness are achieved through queue parameters (exclusive, single-active-consumer, durability, etc.) and juggling exchange + queue types.

    In theory, it solves the RPC problem well (it even has a built-in RPC plugin) and, except for long-term message storage, it will give us all the characteristics needed for EDA, even with the ability to choose between speed (no replication) and reliability (latent Kafka replication).

    In practice, however, this garbage only works normally with certain settings, which makes it a terrible alternative to both NATS and Kafka.

    A multi-tool = zero quality.

    So, RMQ really likes to break a cluster and not be able to fix it.

    Firstly, for RMQ, it's absolutely normal to show you that everything is fine, all queues and exchanges exist, but in reality, when trying to write or consume, nothing will happen, NOT EVEN ERRORS. Why? Because it incorrectly synchronized its configuration. How to fix it? Either by manually deleting queues, restarting a node, or replacing the entire cluster (I'm not kidding, we had to do all 3 options).

    Secondly, if you don't use quorum (replicated) queues or use any kind of TTL on queues, then any problems in the cluster guarantee you either complete dysfunction of these queues or complete dysfunction of the cluster.

    And if you use quorum queues, then prepare for a significant degradation in message transfer and processing speed.

    This means that for RMQ to work stably, we'll have to turn it into a slower version of Kafka without a persistent log.

    The only remaining advantage is its built-in reader management system, BUT the funny thing is that in the end, if you want not just "one reader at a time per queue," but "one reader at a time per set of queues with balancing the number of queues to readers" (and this is a common use case), you'll still have to implement locks on queues yourself, just like with Kafka...

    For me, this is another case of a "Swiss Army knife" that can do things, but poorly.

    Can RMQ be used? If you use quorum queues without frequent creation, you have enough fire-and-forget, and you don't want to deal with partitions, cursors, and distribution in Kafka, then yes, RMQ will do its job.

    In other cases, when choosing between RMQ and Kafka, it's better to choose Kafka. It has many more problems at the beginning, but later you can at least sleep at night.

  • @ [ $davids.sh ] · # 1231

    Ah yes, another interesting conclusion:

    RMQ will give you a bunch of features, but they will only work as long as it's in a single instance. The question arises: "Why give them at all?" – and it's because RMQ is primarily a technology that assumes single-instance operation, and all further enhancements with clustering are features that came later, because time and the market dictated the conditions.

    But this technology is very poor at clustering.

    Therefore, the second use case for RMQ: if a single instance is sufficient for you, then you (probably) can also use RMQ without any issues.

  • @ [ $davids.sh ] · # 1232

    And once again, summarizing, I would highlight 2 points:

    1. Instead of strictly limiting certain queue properties in the case of a cluster, they often write "recommendations" (not) to use this or that feature in a cluster.

    But if this feature completely breaks queues when clustered, then it's not "recommendations" at all, it just needs to be forbidden to use, and that's it.

    1. If RMQ has added clustering capability, then make configuration synchronization reliable, even at the expense of speed.

    Because now the system can say "everything is okay," but in reality, it might not work at all, and you won't see it until you try to send/receive a message and nothing happens.

    And if these 2 points were addressed, my complaint would remain at the level of: "In the end, RMQ is a simplified but slower alternative to Kafka" – and in this wording, I could trust the technology, but in the current situation, when it breaks the cluster and doesn't report anything about it at all, the trust is 0.