9 steps to better OO code
Learn how to make our code more:
"Calisthenics are exercises consisting of a variety of gross motor movements; often rhythmical and generally without equipment or apparatus."
Wikipedia
Author unknown
Art of Readable Code by Dustin Boswell, Trevor Foucher
class Board(object):
def __init__(self, data):
# Level 0
self.buf = ""
for i in range(10):
# Level 1
for j in range(10):
# Level 2
self.buf += data[i][j]
class Board(object):
def __init__(self, data):
self.buf = ""
self.collect_rows(data)
def collect_rows(self, data):
for i in range(10):
self.collect_row(data[i])
def collect_row(self, row):
for j in range(10):
self.buf += row[j]
products = self.get_products_by_user(...)
if products is None:
products = self.get_products_by_media(...)
if products is None:
products = self.get_products_by_domain(...)
if products is None:
products = self.get_any_products(...):
if products is None:
raise Exception('Access denied')
else:
...
else:
...
else:
...
else:
...
if options.get_categories() is None:
...
elif len(options.get_categories()) == 1:
...
elif SPECIAL_CATEGORY in options.get_categories():
...
elif options.get_categories() and options.get_query():
...
elif options.get_content_type():
...
def login (self, request):
if request.user.is_authenticated():
return redirect("homepage")
else:
messages.add_message(request,
messages.INFO,
'Bad credentials')
return redirect("login")
def login (self, request):
if request.user.is_authenticated():
return redirect("homepage")
messages.add_message(request,
messages.INFO,
'Bad credentials')
return redirect("login")
def function(param):
if param is not None:
value = param
else:
value = "default"
return value
def function(param):
value = "default"
if param is not None:
value = param
return value
https://github.com/gennad/Design-Patterns-in-Python
https://www.quora.com/Is-it-true-that-a-good-programmer-uses-fewer-if-conditions-than-an-amateur
class Validator(object):
def check_date(self, year, month, day):
pass
# 10th of December or 12th of October?
validator = Validator()
validator.check_date(2016, 10, 12)
class Validator(object):
def check_date(self, year: Year, month: Month, day: Day) -> bool:
pass
# Function call leaves no doubt.
validator.check_date(Year(2016), Month(10), Day(12))
class Poem(object):
def __init__(self, content):
self.content = content
def indent(self, spaces):
self.content = " " * spaces + self.content
return self
def suffix(self, content):
self.content = self.content + " - " + content
return self
Poem("Road Not Travelled").indent(4)\
.suffix("Robert Frost")\
.content
class CartService(object):
def get_token(self):
token = self.get_service('auth')\
.auth_user('user', 'password')\
.get_result()\
.get_token()
return token
# 1. What if None is returned instead of object?
# 2. How about exceptions handling?
class Field(object):
def __init__(self):
self.current = Piece()
class Piece(object):
def __init__(self):
self.representation = " "
class Board(object):
def board_representation(self, board):
buf = ''
for field in board:
buf += field.current.representation
return buf
class Field(object):
def __init__(self):
self.current = Piece()
def add_to(self, buffer):
return self.current.add_to(buffer)
class Piece(object):
def __init__(self):
self.representation = " "
def add_to(self, buffer):
return buffer + self.representation
class Board(object):
def board_representation(self, board):
buf = ''
for field in board:
buf = field.add_to(buf)
return buf
class Order(object):
def ship_order(self):
pass
order = Order()
order.ship_order()
// vs
class Order(object):
def ship(self):
pass
order = Order()
order.ship()
acc = 0
// accumulator? accuracy?
pos = 100
// position? point of sale? positive?
auth = None
// authentication? authorization? both?
class CartService(object):
def __init__(self):
self.logger = Logger()
self.cart = CartCollection()
self.translationService = TranslationService()
self.auth_service = AuthService()
self.user_service = UserService()
class Game(object):
def __init__(self):
self.score = 0
def set_score(self, score):
self.score = score
def get_score(self):
return self.score
# Usage
ENEMY_DESTROYED_SCORE = 10
game = Game()
game.set_score(game.get_score() + ENEMY_DESTROYED_SCORE)
class Game(object):
def __init__(self):
self.score = 0
def add_score(self, score):
self.score += score
# Usage
ENEMY_DESTROYED_SCORE = 10
game = Game()
game.add_score(ENEMY_DESTROYED_SCORE)
https://www.slideshare.net/PaweLewtak/object-calisthenics-pycon-sk-2017
https://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdf
https://pragprog.com/book/twa/thoughtworks-anthology
https://github.com/gennad/Design-Patterns-in-Python
https://en.wikipedia.org/wiki/Law_of_Demeter
https://www.quora.com/Is-it-true-that-a-good-programmer-uses-fewer-if-conditions-than-an-amateur