Skip to content

Instantly share code, notes, and snippets.

@anapaulagomes
Last active March 26, 2019 15:13
Show Gist options
  • Save anapaulagomes/55067a80f776008ce761bd704d0726d4 to your computer and use it in GitHub Desktop.
Save anapaulagomes/55067a80f776008ce761bd704d0726d4 to your computer and use it in GitHub Desktop.
Code smell Temporal coupling example
class PrivateClassesView:
def post(self):
# code omitted for readability sake
data = {
'to': ['[email protected]'],
'body': 'blablabla',
'scheduled_for': datetime(2019, 3, 30, 11, 1, 0)
}
if subject:
data['subject'] = subject
email = Email.objects.create(**data) # database object
email.send() # has important logic on email flow
class GroupClassesView:
def post(self):
# code omitted for readability sake
data = {
'to': ['[email protected]'],
'body': 'blablabla',
}
if subject:
data['subject'] = subject
email = Email.objects.create(**data)
email.send()
class IntensiveClassesView:
def post(self):
# code omitted for readability sake
data = {
'to': ['[email protected]'],
'body': 'blablabla',
}
if subject:
data['subject'] = subject
email = Email.objects.create(**data)
email.send()
"""
Only this method would know the logic behind Email.
Consumers, like our views, shouldn't think about Email implementation details.
"""
def schedule_email(to, body, subject='My default subject', scheduled_for=None):
data = {
'to': ['[email protected]'],
'body': 'blablabla',
'subject': subject,
}
if scheduled_for is None:
data['scheduled_for'] = now()
email = Email.objects.create(**data)
email.send()
class PrivateClassesView:
def post(self):
# code omitted for readability sake
schedule_email(to, body, subject, scheduled_for)
class GroupClassesView:
def post(self):
# code omitted for readability sake
schedule_email(to, body, subject)
class IntensiveClassesView:
def post(self):
# code omitted for readability sake
schedule_email(to, body)
@anneFly
Copy link

anneFly commented Mar 26, 2019

I do see your point of trying to get rid of code repetition.
However, I think there are pros and cons on both sides. As you know, I am not a fan of too many layers of abstraction. It makes the code harder to read and it's harder to notice side effects. Usually, you'll regret your abstraction by the time you need to implement special cases and suddenly you end up with a lot of optional arguments and if else blocks in your utility function.
But I'm usually also not a fan of "developing for the future", I mean like when you write code trying to think of all possible future cases and making it super complex even though you have just a simple problem to solve at the moment. So, it's also arguable to say that if the function schedule_email would need to be adapted with special behavior, then it can be refactored by then.

In the end, I know that this topic is very opinionated. Some like this, some like that. To be honest, I personally don't see the current code as a "code smell", and I don't follow the DRY principle unless it's business logic. If you're unsure, feel free to ask around what others think.
This article for example is interesting: https://programmingisterrible.com/post/176657481103/repeat-yourself-do-more-than-one-thing-and

@jpaulorio
Copy link

I don't see the main point here being about getting rid of repetition though. Instead, my understanding is that her point is about encapsulating the logic of how to send an email or, to be more generic, how to make sure we're following the Single Responsibility Principle. The way I see it is that side effects to the main action of a given class/method should belong somewhere else. In her example, sending an email is a side effect of whatever the main classes are supposed to do, thus it's not the responsibility of those classes to know the steps required to send an email.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment