{"action":"created","issue":{"url":"https://api.github.com/repos/mattupstate/overholt/issues/39","labels_url":"https://api.github.com/repos/mattupstate/overholt/issues/39/labels{/name}","comments_url":"https://api.github.com/repos/mattupstate/overholt/issues/39/comments","events_url":"https://api.github.com/repos/mattupstate/overholt/issues/39/events","html_url":"https://github.com/mattupstate/overholt/issues/39","id":84812856,"number":39,"title":"Service Objects vs Service Mixins","user":{"login":"yiumingh","id":2039973,"avatar_url":"https://avatars.githubusercontent.com/u/2039973?v=3","gravatar_id":"","url":"https://api.github.com/users/yiumingh","html_url":"https://github.com/yiumingh","followers_url":"https://api.github.com/users/yiumingh/followers","following_url":"https://api.github.com/users/yiumingh/following{/other_user}","gists_url":"https://api.github.com/users/yiumingh/gists{/gist_id}","starred_url":"https://api.github.com/users/yiumingh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yiumingh/subscriptions","organizations_url":"https://api.github.com/users/yiumingh/orgs","repos_url":"https://api.github.com/users/yiumingh/repos","events_url":"https://api.github.com/users/yiumingh/events{/privacy}","received_events_url":"https://api.github.com/users/yiumingh/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-06-03T23:17:57Z","updated_at":"2015-06-04T17:38:36Z","closed_at":null,"body":"I'm wondering what are the drawbacks of using mixins vs using objects. I actually implemented services by using a mixin instead of a separate object on its own.\r\n\r\nThis helps me in a two ways:\r\n1. I don't have to define \\_\\_model\\_\\_, since I'm using classmethods to obtain the model I'm running the query on.\r\n2. I don't have to create or instantiate objects to use getters like all, find, etc.\r\n\r\n```\r\nclass ServiceMixin(object):\r\n\r\n    def save(self):\r\n        db.session.add(self)\r\n        db.session.commit()\r\n        return self\r\n\r\n    @classmethod\r\n    def all(cls):\r\n        return cls.query.all()\r\n\r\n    @classmethod\r\n    def get(cls, _id):\r\n        return cls.query.get(_id)\r\n\r\n    @classmethod\r\n    def get_all(cls, id_cl=\"id\", *ids):\r\n        id_column = cls.get(id_cl)\r\n        return cls.query.filter(id_column.in_(ids)).all()\r\n\r\n    @classmethod\r\n    def find(cls, **kwargs):\r\n        return cls.query.filter_by(**kwargs)\r\n\r\n    @classmethod\r\n    def first(cls, **kwargs):\r\n        return cls.find(**kwargs).first()\r\n\r\n    @classmethod\r\n    def get_or_404(cls, id):\r\n        return cls.query.get_or_404(id)\r\n\r\n    @classmethod\r\n    def new(cls, **kwargs):\r\n        return cls(**cls._preprocess_params(kwargs))\r\n\r\n    @staticmethod\r\n    def _preprocess_params(kwargs):\r\n        kwargs.pop('csrf_token', None)\r\n        return kwargs\r\n\r\n    @classmethod\r\n    def create(cls, **kwargs):\r\n        return cls.save(cls.new(**kwargs))\r\n\r\n    def update(self, **kwargs):\r\n        for k, v in self._preprocess_params(kwargs).items():\r\n            setattr(self, k, v)\r\n        self.save()\r\n        return self\r\n\r\n    def delete(self):\r\n        db.session.delete(self)\r\n        db.session.commit()\r\n```\r\n\r\nTo use it, simply inherit it when creating your models:\r\n```\r\nclass Product(db.Model, ServiceMixin):\r\n    id = db.Column(db.Integer(), primary_key=True)\r\n    name = db.Column(db.String(250))\r\n    ...\r\n \r\nProduct.all() # Gets all of the products\r\nProduct.find(name=\"tacos\") # Finds all products named \"tacos\"\r\np = Product(name=\"spegahetti\")\r\np.save() # Saves the newly created Product\r\n```\r\n\r\nAnyway, this project template is great stuff! Thanks for letting us in on this."},"comment":{"url":"https://api.github.com/repos/mattupstate/overholt/issues/comments/108986446","html_url":"https://github.com/mattupstate/overholt/issues/39#issuecomment-108986446","issue_url":"https://api.github.com/repos/mattupstate/overholt/issues/39","id":108986446,"user":{"login":"mattupstate","id":166176,"avatar_url":"https://avatars.githubusercontent.com/u/166176?v=3","gravatar_id":"","url":"https://api.github.com/users/mattupstate","html_url":"https://github.com/mattupstate","followers_url":"https://api.github.com/users/mattupstate/followers","following_url":"https://api.github.com/users/mattupstate/following{/other_user}","gists_url":"https://api.github.com/users/mattupstate/gists{/gist_id}","starred_url":"https://api.github.com/users/mattupstate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mattupstate/subscriptions","organizations_url":"https://api.github.com/users/mattupstate/orgs","repos_url":"https://api.github.com/users/mattupstate/repos","events_url":"https://api.github.com/users/mattupstate/events{/privacy}","received_events_url":"https://api.github.com/users/mattupstate/received_events","type":"User","site_admin":false},"created_at":"2015-06-04T17:38:36Z","updated_at":"2015-06-04T17:38:36Z","body":"It's a matter of design, which we can argue all day if you want :smirk:, and thats because design is a matter of opinion. If that works for you, thats fine. I, however, don't like to mix responsibilities in my objects. For example, I don't believe this mixin approach is appropriate when you begin to have more complicated business logic when instances of your models are created, updated, or deleted. A hypothetical scenario might be that, when you create a Product record you must also publish a message to a message queue. In my opinion, it would be inappropriate to encapsulate that logic in a class method on the Product model class. More appropriate would be an object that brings together separate functions that deal with both operations, making the logic easier to test."}}