4

I am using Python's peewee ORM to map my relational database, but I'm noticing that my models are starting to get bloated and I also seem to be violating separation of concerns.

For example, my User class has self explanatory methods such as

authenticate()
push_message()
upload_image()

Even though it's useful to call user.authenticate() or user.upload_image(), these methods involve using many different packages and/or third party API's and I'm wondering if it would be better to separate them from the model.

One way I can think of fixing this is by moving all these methods into another layer( and separate that layer even further for the various domains ) and use them like so:

authenticate_user( user )
push_user_message( user )
upload_user_image( user )

But this seems contradicting to the utility of OOP. Another way maybe is to combine my original idea and use an interface of sorts?

class UserAuthentication( object )
    # authentication code goes here

# These would be in separate packages and/or modules
class User( model ):
    def authenticate( self ):
        return UserAuthentication( self ).authenticate()

But this may be introducing extraneous complexity.

2
  • OOP is sometimes useful, and sometimes not. Fortunately, Python dpes not force you to use OOP.
    – 9000
    Jul 7, 2017 at 4:22
  • I have the feeling that you have too much functionality in one class, breaking the single responsibility principle. The fact that a user triggers functionality like authentication or sending a message does not mean that it should also be part of a User class in your model. How would your model look like if you leave the initiator of actions completely out of it? Jul 7, 2017 at 6:20

1 Answer 1

6

I think you might be confusing a domain/business model with a service class. A model more or less represents a real-life object and behavior, where a service class wraps the model and performs actions against it that aren't necessarily part of the model itself.

For example, a User might have an Image property, but UploadImage is an action that's not specific to the model itself, but specific to how to implement getting an image to the model.

ORMs can wrap the model layer and provide persistence mapping (using a Fluent API, you can do so without polluting your model layer at all (at least that's what I do in .NET - not well versed in python myself)). Your service would make use of the persistence, but the core model itself (that which represents your User, or Client, or Order, etc) is ignorant of anything other than it's own properties methods and events.

The service layer, however (which might implement an AttachImage() method), would make use of both the model and the persistence layer together to perform the required task.

This way your model is clean, your ORM is clean (relying only on the model), and your service classes can be designed to do only what they need to do, and your application more or less interacts with the services.

(note that there's no small amount of ambiguation about what a "model" is - I use it here in terms of a domain model, a business-layer object representing a business entity... likewise, I've blurred the lines a bit between service and application layers, so as not to make too much of a mess of my reply...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.