Python: Bashing Object Oriented Programming
Author profile picture

@1nj3ct0r1nj3ct0r

Hi, I’m 15 years outdated hacker and programmer that works for myself in residence! I do tasks for enjoyable!

People bash OO lots lately, I’m more and more coming to the opinion they’re proper, not less than in Python. My level right here is to not argue that OO is unhealthy per se, extra that its introduction is just pointless, AKA not helpful.

Oli’s Conjecture

All OO code may be refactored into equal non-OO code that is as straightforward or easier to know.

Let’s take an instance that ought to pan out in OO’s favor, we have all seen/written code considerably like the next:

class ApiClient:
    def __init__(self, root_url: str, session_cls: sessionmaker):
        self.root_url = root_url
        self.session_cls = session_cls

    def construct_url(self, entity: str) -> str:
        return f"{self.root_url}/v1/{entity}"

    def get_items(self, entity: str) -> List[Item]:
        resp = requests.get(self.construct_url(entity))
        resp.raise_for_status()
        return [Item(**n) for n in resp.json()["items"]]

    def save_items(self, entity: str) -> None:
        with scoped_session(self.session_cls) as session:
            session.add(self.get_items(entity))


class ClientA(ApiClient):
    def construct_url(self, entity: str) -> str:
        return f"{self.root_url}/{entity}"


class ClientB(ApiClient):
    def construct_url(self, entity: str) -> str:
        return f"{self.root_url}/a/special/place/{entity}"


client_a = ClientA("https://client-a", session_cls)
client_a.save_items("bars")

We selected OO it as a result of we needed to bind the 

root_url

 to one thing and we did not need to cross across the 

sessionmaker

.

We additionally needed to utilise inheritance to hook into a technique midway by way of the decision stack.

But what if we just do cross knowledge round, and write ‘boring’ capabilities, what occurs then?

@dataclass
class Client:
    root_url: str
    url_layout: str


client_a = Client(
    root_url="https://client-a",
    url_layout="{root_url}/{entity}",
)

client_b = Client(
    root_url="https://client-b",
    url_layout="{root_url}/a/special/place/{entity}",
)


def construct_url(consumer: Client, entity: str) -> str:
    return consumer.url_layout.format(root_url=consumer.root_url, entity=entity)


def get_items(consumer: Client, entity: str) -> List[Item]:
    resp = requests.get(construct_url(consumer, entity))
    resp.raise_for_status()
    return [Item(**n) for n in resp.json()["items"]]


def save_items(consumer: Client, session_cls: session_cls, entity: str) -> None:
    with scoped_session(session_cls) as session:
        session.add(get_items(consumer, entity))


save_items(client_a, session_cls, "bars")

We needed to cross around the 

Client

 and the 

session_cls

 round. 🤷

Who cares?

We even wrote like 10% fewer characters.

Also, the conjecture stands, the ensuing code is not less than as straightforward to know and we did not want any OO.

I’ve heard this fashion known as the bag-of-functions fashion. That is to say, all of your code simply consists of typed knowledge and module-namespaced-bags-of-functions.

What about long-lived global-y issues?

Use this sample to reuse config/db session lessons over the lifetime of an utility.

What about interfaces/summary base lessons?

Just attempt writing with out them, I promise it is going to be OK. (To be honest, it is solely the introduction of sort hints to Python that has made the bag-of-functions fashion so nice).

What about impure issues?

If you have taken the pure-FP/hexagonal-architecture tablet, you need to write pure lessons that take impure ‘adapter’ situations for getting-the-current-datetime/API-calls/talking-to-the-db/other-impure-stuff. The concept is sweet in principal – must be good for testing proper? – in follow, you may simply use freezegun / use responses / take a look at with the db (the 

other-impure-stuff

 tends to not really exist) and save your self quite a lot of trouble.

Exceptions:

I’d wish to make exceptions for the next:

I Lied.

My level right here is to not argue that OO is unhealthy per se.

OK, I lied, it is not only a case of OO being a largely futile addition to the language, it is that it typically obscures the issue at hand and encourages unhealthy behaviours:

  • It encourages you to mutate. Bag-of-functions makes it really feel icky to mutate arguments – because it ought to really feel. (Feel free to mutate throughout the confines of your perform BTW, let’s not go mad FP).
  • It’s considerably simply the return of worldwide variables. Not with the ability to share knowledge between capabilities with
    self

    forces you to write down capabilities with a smaller state-space which might be simpler to check.

  • Smooshing in capabilities in along with your knowledge makes it tougher to serialise something – in a world of REST APIs, serialisability is tremendous helpful.
  • It encourages mad inheritance hierarchies – this has been talked about at size elsewhere.
  • Most importantly although, it provides nothing, it is simply noise that distracts from the issue at hand and makes it tougher to navigate/comprehend your code.

Note

A basic video within the OO-bashing style.

Author profile picture

Read my tales

Hi, I’m 15 years outdated hacker and programmer that works for myself in residence! I do tasks for enjoyable!

Tags

Join Hacker Noon

Create your free account to unlock your customized studying expertise.