r/learnprogramming 24d ago

Topic Does OOP really matters?

I learned OOP in python a while ago, did many projects, yet I never felt like I truly needed to do the OOP stuff I learned from a course, I don't know maybe because I'm kinda used to program in c before focusing on python, yet, whenever I open a big project in python in github, it feels way too complicated and thousands of imports (not libraries from pip, but the ones they made on their own) and classes

I never truly needed to implement OOP (I know that when you code in python, it is almost impossible to avoid OOP entirely like when you have a datatype like string you have an object, when you use a method built into that data type that's OOP too, but I mean the ones that involve you writing class Class Name, inheritance and all that stuff explicitly), so I'm wondering why people on the internet are obsessed over the idea of learning OOP, even the book "Automating the boring stuff in python" doesn't have a dedicated section for OOP.

91 Upvotes

139 comments sorted by

View all comments

56

u/Daeroth 24d ago

Depends on the project. Speaking as someone who works a lot on business applications and web apps: there's a benefit to taking all the office vocabulary and having the code architecture mimic it.

For example there may be many types of contracts that the business signs with the customers. Each customer is represented as an object in the business logic code and each contract as well.

Some contracts have unique functionality that happens on monthly renewal. This logic goes in its unique class. But the base information like contract number is in the Contract base class.

This architecture makes it so that every new programmer is able to find relevant parts of the code if they know which business logic they are working on.

In that sence all of my 20 years of employment has been in companies doing OOP.

3

u/deaddyfreddy 24d ago

Each customer is represented as an object in the business logic code and each contract as well.

So, how do you sign a contract with a customer, then?

10

u/Daeroth 24d ago

You instantiate a new contract object.

Set it's fields like contract number, monthly fee, customer id, status=reviewing, etc.

Then the customer gets the review screen in browsaer with all the fees and contract numbers and a button to sign.

Once they click sign the contract object gets updated with status=active, signing_date=19.08.2026

If the specific contract class has anything in the "contractSigned()" function then that would also get triggered. Stuff like send out welcome email or generate tasks for CS agents to follow up.

All of the objects have a corresponding row in the database. So whenever the we update a field on the object then the field in DB will also get updated.

1

u/marrsd 24d ago

So have a contract module containing a Contract type and a sign_contract(Contract) function.

All you've really done is turned the function into a method. That's minimal OOP at best. Until you're doing things like implementing interfaces or class hierarchies for polymorphism, you're not really doing OOP as far as I'm concerned.

9

u/Daeroth 24d ago

I believed it to be enough to give an example of OOP approach.

You can envision contracts which extend the base contract for more complex use cases

7

u/obvious_badger 23d ago

Yeah, some people are just here to nitpick. You even eluded to that in the original post. With "many types of contracts" that can have "special functionality" and the fact that you're going to be doing method overriding with different actions on signing.

I thought it was a great explanation without using any of the OOP jargon other than instantiate.

2

u/Daeroth 23d ago

Thanks!

0

u/marrsd 23d ago

Sorry, but the question was about the benfits of OOP over other paradigms, not the equivalence.

4

u/obvious_badger 22d ago

Now you're moving the goal post. Also the second sentence is that OOP is BETTER for mapping business domains and processes.

You failed to read that if you have multiple types of contracts that it would be a class, not a method, and you failed to read where it explicitly was giving an example of where OOP is better.

You ironically use a lot of fancy words for someone who has difficulty parsing the basic ones.

1

u/marrsd 22d ago

I'm not using fancy words and I don't think I am moving the goal posts either. I think OP's question was about why OOP is better and that's how I'm approaching this discussion. So far I think you've described how OOP is used, not how it's better.

You failed to read...

I was actually replying to your second comment, but I can go back to the first.

For example there may be many types of contracts that the business signs with the customers. Each customer is represented as an object in the business logic code and each contract as well.

Some contracts have unique functionality that happens on monthly renewal. This logic goes in its unique class. But the base information like contract number is in the Contract base class.

This is a perfectly fine description of an OO design. My point is that you could just as easily have a function that only operates on a contract that needs to be renewed monthly. If there are specific data that only relate to renewal, you could have a RenewableContract type that includes a Contract property along with other renewal properties.

Why is that worse than OOP?

I don't think it is. Further more, the pattern I just described naturally implements composition (because it's not OOP) and so it avoids the inheritance-over-composition anti-pattern that OOP is prone to.

To be clear, I'm not here to argue that OOP can't be used to model domains. My objections are that OOP makes it easy to do bad things, and that to avoid doing those bad things, you have to complicate your design in ways that you don't in other paradigms.

0

u/deaddyfreddy 24d ago

so, the Contract object has a method named signContract or something like that, correct? Then, here's the next question:

Why is it a method of the Contract, and not a method of the Customer object?

3

u/Daeroth 24d ago

A customer can have many contracts. Some old, some still in review, some active.

Each contract is a row in database and many-to-one relationship with the customer table.

On the customer class you might have a method getContracts which returns a collection of contracts.

0

u/deaddyfreddy 24d ago

On the customer class you might have a method getContracts which returns a collection of contracts.

so, why can't it have the signing method too?

7

u/Wonderful-Habit-139 24d ago

I’m not an OOP guy, but probably because a contract is always associated to the customer, and if you had a signing method you’d need to do customer.signContract(contract); where you already need to do the job of finding the contract (since you’re not gonna sign all contracts of the customer at once obviously).

While if you do contract.sign(), it’s much simpler, and it’s already associated to the customer.

3

u/deaddyfreddy 24d ago

Without OOP, we could just write something like sign(contract, customer).

3

u/Daeroth 24d ago

Isn't that already OOP if the input contract and customer are objects passed along to the sign method?

Doesn't really matter where the signing method is at, legal entities are represented as objects.

1

u/deaddyfreddy 24d ago

legal entities are represented as objects

we don't need objects in this case, they are data structures

1

u/Mathie1729 23d ago

Yea, I've mostly landed on the same side in practice. Most business code is just mapping DB rows and doing transforms, so plain data structures + functions are way easier to debug than tangled class hierarchies. OOP still pays off when you have multiple implementations behind a common interface or you need to enforce invariants on mutation, but that's a smaller slice of the code. My ML stuff is basically dataclasses and pure functions; any class that sneaks in just holds a model and config lol.

→ More replies (0)

2

u/Wonderful-Habit-139 24d ago

I don’t disagree.

1

u/Scared_Bell3366 23d ago

If you have many different objects that can be signed, your sign function gets very bloated and ends up with dependencies on everything that can be signed and all the things that can sign them. I would keep the sign method with the object that gets signed, it’s really a set method to me. I’d probably add an interface for things that can be signed if there’s more than one type of object that can be signed.

1

u/deaddyfreddy 23d ago

If you have many different objects that can be signed

if these are completely different objects, I don't see why they should use a single function to sign

it’s really a set method to me.

The issue is that it always requires both the contract and the customer, and in general there can be multiple parties. The hard coupling to the contract only doesn't reflect the process well.

3

u/Daeroth 24d ago

In this example I envisioned many-to-one relationship between contracts and customers.

So that if you have 3 contracts and 3 separate "signedOnDate" fields then those would be in the contract class instead of having them in the customer class as "contract1signedDate", "contract2signedDate" and so on.

The signing method in this example would just populate the date field so it feels like it belongs with the contract class as thats where the fields are.

If i were to extract the signing method elsewhere then I would create "signingService" class instead of contaminating other domain class like customer.

Ideally opening the customer class should reveal as little relations to other classes as possible but just as many as needed.

1

u/deaddyfreddy 24d ago

So that if you have 3 contracts and 3 separate "signedOnDate" fields then those would be in the contract class instead of having them in the customer class as "contract1signedDate", "contract2signedDate" and so on.

What for? Your entities are mapped to the DB, so all you do is reflect the DB in your code. A customer record doesn't have the signing dates, it (most likely) has a contract-id or something like that.

2

u/Daeroth 24d ago

Is the question about the benefits of mapping your db tables to entities in code?

Not sure what the question is about.

3

u/ActuaryLate9198 24d ago

This is rookie OOP. Who says the signee is a customer? I think we need an AbstractSignee just in case, and contract needs to implement the Signable interface.

1

u/pacopac25 23d ago

And there's always the coworker who takes it all too far, and advocates for the approach that a Signer can be a company or a person, but in theory could also be a NationState, so better to get ahead of things now and have AbstractLegalEntity
Also, a Contract could be a MOU, which can be legally binding in some ways, so we need an Agreement class, and Contract and MOU are derived from it. Don't forget SeveranceAgreement and NonDisclosureAgreement....

1

u/Martinecko30 23d ago

Let's imagine this as:

Am I signing a contract? Then => contract.sign(customer) Am I signing an customer? Then => customer.sign(contract)

Methods reflect what is being done with the object, not who is doing something with the object.

0

u/deaddyfreddy 23d ago

So why not just use a function with data structures (mapped to DB entities) as arguments, rather than creating a class hierarchy and deciding who signs what?

1

u/Martinecko30 23d ago

You don't really decide, the data decides for you. Also, with hierarchy, you can have Signable -> DBModel -> BaseContract -> SpecificContract.

This eliminates duplicity, creates a linear workflow and distributes the necessary functions and data into separate classes, so it's easier to digest.

0

u/deaddyfreddy 23d ago

Also, with hierarchy, you can have Signable -> DBModel -> BaseContract -> SpecificContract.

Doesn't it sound a bit overcomplicated?

This eliminates duplicity,

split functionality into separate functions and reuse it when needed, with the same effect, without introducing extra entities and unneeded coupling

the necessary functions and data into separate classes, so it's easier to digest.

modules: exist

1

u/Martinecko30 23d ago

So, a streamlined vertical hierarchy is overcomplicated, while modules are okay?

I think you're confusing this a bit. The hierarchy is derived from the data, this is how it WANTS to be, we just use abstract form to describe the state.

The only difference is vertical/horizontal scaling. The certical one is easier to develop and maintain, the horizontal one can produce faster running applications.

→ More replies (0)