8. Dragon ADR Position Change¶
ADR - Architecture Design Records
8.1. Problem¶
Move dragon left by 10 and down by 20
Move dragon left by 10 and right by 15
Move dragon right by 15 and up by 5
Move dragon down by 5
8.2. Option 1¶
>>> dragon.shift(left=10, down=20)
>>> dragon.fly(left=10, down=20)
Pros and Cons:
Good: extensible to 3D
Good: move by relative shifting (left, right, up, down)
Good: encapsulation, object knows current position, state and does the move
Bad: method names are too use-case specific
Decision: rejected, method names too use-case specific
Problem:
>>> dragon.fly(left=10, down=20) # does the same, but different name
>>> hero.walk(left=10, down=20) # does the same, but different name
>>> snake.slide(left=10, down=20) # does the same, but different name
Use Cases:
>>> locmem.store(key='...', value='..')
>>> locmem.retrieve(key='...')
>>> database.insert(column='...', value='...')
>>> database.select(column='...')
>>> filesystem.write(filename='...', content='...')
>>> filesystem.read(filename='...')
8.3. Option 2¶
>>> dragon.change_position(left=10, down=20)
>>> dragon.position_change(left=10, down=20)
Pros and Cons:
Good: extensible to 3D
Good: move by relative shifting (left, right, up, down)
Good: encapsulation, object knows current position and moves
Bad: the method names are a bit too complex for
Decision: candidate, method names are a bit too complex for now
8.4. Option 3¶
>>> dragon.move(left=10, down=20)
>>> dragon.move(right=10, up=20)
>>> dragon.move(right=10, left=20)
Pros and Cons:
Good: extensible to 3D
Good: move by relative shifting (left, right, up, down)
Good: encapsulation, object knows current position, state and does the move
Good: hides business logic (inverted y-axis)
Good: easy
.move()
Good: you can prevent negative shifting (i.e.:
left=-10
)Decision: candidate
8.5. Option 4¶
>>> dragon.move(x=10, y=-20)
Pros and Cons:
Good: extensible to 3D
Good: move by relative shifting (left, right, up, down)
Good: encapsulation, object knows current position, state and does the move
Good: easy
.move()
Bad: you have to know, which axis is
left
and with isright
Bad: requires knowledge of business logic (inverted y-axis)
Bad: controller must know other variables, such as speed factor (snail is slower than a dragon), surface on which the dragon is moving (solid is faster than water or ice), injuries (if dragon is not injured with his for example left foot)
Bad: you cannot prevent negative shifting (i.e.:
x=-10
)Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected, it requires to much inside knowledge of API from user
8.6. Option 5¶
>>> dragon.move_to(x=10, y=20)
Pros and Cons:
Good: extensible to 3D
Bad: Move by setting absolute position which is similar to
.set_position()
, but it differs from it where inmove()
you can make an animation of movement, and withset_position()
it happens instantlyBad: controller must know other variables, such as speed factor (snail is slower than a dragon), surface on which the dragon is moving (solid is faster than water or ice), injuries (if dragon is not injured with his for example left foot)
Bad: requires knowledge of business logic (inverted y-axis)
Bad: violates abstraction (OOP Principle)
Decision: rejected, violates Model-View-Controller (MVC)


8.7. Option 6¶
>>> dragon.move_x(10)
>>> dragon.move_y(-20)
>>> dragon.move_horizontal(10)
>>> dragon.move_vertical(-20)
Pros and Cons:
Good: extensible to 3D, just add another method
Bad: require knowledge of an API
Bad: Move by setting absolute position
Bad: controller must know other variables, such as speed factor (snail is slower than a dragon), surface on which the dragon is moving (solid is faster than water or ice), injuries (if dragon is not injured with his for example left foot)
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
8.8. Option 7¶
>>> dragon.move_xy(10, -20)
Pros and Cons:
Bad: Move by setting absolute position
Bad: controller must know other variables, such as speed factor (snail is slower than a dragon), surface on which the dragon is moving (solid is faster than water or ice), injuries (if dragon is not injured with his for example left foot)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: requires knowledge of business logic (inverted y-axis)
Bad: name indicates that this is not extensible to 3D
Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
Problem:
>>> console.run_command('pwd', True, False, None)
8.9. Option 8¶
>>> dragon.move(10, -20)
Pros and Cons:
Good: extensible to 3D
Bad: require knowledge of an API
Bad: Move by setting absolute position
Bad: controller must know other variables, such as speed factor (snail is slower than a dragon), surface on which the dragon is moving (solid is faster than water or ice), injuries (if dragon is not injured with his for example left foot)
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
Problem:
>>> run('ls', True, False, None)
8.10. Option 9¶
>>> dragon.move((10, -20))
>>> dragon.move_xy((10, -20))
Pros and Cons:
Bad: require knowledge of an API
Bad: Move by setting absolute position
Bad: controller must know other variables, such as speed factor (snail is slower than a dragon), surface on which the dragon is moving (solid is faster than water or ice), injuries (if dragon is not injured with his for example left foot)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: requires knowledge of business logic (inverted y-axis)
Bad: not extensible to 3D
Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
Problem:
>>> run(('ls', True, False, None))
8.11. Option 10¶
>>> dragon.move(dx=10, dy=-20)
>>> dragon.move(horizontal=10, vertical=-20)
Pros and Cons:
Good: encapsulation, object knows current position and moves
Bad: controller computes final offset
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
8.12. Option 11¶
>>> dragon.move(0, 10, 0, -20)
>>> dragon.move((0, 10, 0, -20))
>>> dragon.move([
... (0, 10, 0, -20),
... (0, 10, 0, -20)])
Pros and Cons:
Good: there is only one method
move()
responsible for movingBad: Python has keyword arguments, so use it
Bad: require knowledge of an API
Bad: not extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Decision: rejected
Example:
move(left, right, up, down)
Problem:
>>> run(True, False, None)
p {
margin-top: 25px;
margin-bottom: 75px;
margin-right: 50px;
margin-left: 100px;
}
p {
margin: 25px 50px 75px 100px;
}
p {
margin: 25px 50px 75px;
}
p {
margin: 25px 50px;
}
p {
margin: 25px;
}
CSS:
4 params: top, right, bottom, left
3 params: top, right-left, bottom
2 params: top-bottom, right-left
1 params: top-right-bottom-left
8.13. Option 12¶
>>> dragon.move([
... (10, -20),
... (10, -15)])
Pros and Cons:
Good: move by relative offset
Bad: require knowledge of an API
Bad: not extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
Example:
move(horizontal, vertical)
8.14. Option 13¶
>>> dragon.move_to([
... (10, -20),
... (50, -120),
... (5)])
Pros and Cons:
Bad: move by setting absolute position
Bad: require knowledge of an API
Bad: not extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
Example:
move(x, y)
8.15. Option 14¶
>>> dragon.move_to({'x':50, 'y':-120})
>>> dragon.move_to([
... {'x':10, 'y':-20},
... {'x':10, 'y':-15}])
Pros and Cons:
Bad: require knowledge of an API
Bad: not extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
8.16. Option 15¶
>>> dragon.move({'left':50, 'down':120})
>>> dragon.move([
... {'left':50, 'down':120},
... {'left':50, 'right':120},
... {'down':50}])
Pros and Cons:
Bad: require knowledge of an API
Bad: not extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: violates abstraction (OOP Principle)
Bad: **kwargs can convert to keyword arguments
Decision: rejected
8.17. Option 16¶
>>> dragon.move({'dx': 10, 'dy': 20})
>>> dragon.move([
... {'dx': -10, 'dy': 20},
... {'dx': -10, 'dy': 0}])
Pros and Cons:
Bad: require knowledge of an API
Bad: not extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
dy=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
8.18. Option 17¶
>>> dragon.move(Point(x=10, y=20))
>>> path = [
... Point(x=10, y=20),
... Point(x=10, y=15),
... ]
>>>
>>> dragon.move(path)
Pros and Cons:
Good: Move by setting absolute position on a path
Good: This is how they do it in games
Good: extensible to 3D
Bad: requires knowledge of business logic (inverted y-axis)
Bad: require knowledge of an API
Decision: possible, common practice in game-dev
8.19. Option 18¶
>>> dragon.move([
... {'direction': 'left', 'distance': 20},
... {'direction': 'left', 'distance': 10},
... {'direction': 'right', 'distance': 20}])
Pros and Cons:
Good: extensible to 3D
Bad: require knowledge of an API
Decision: rejected
8.20. Option 19¶
>>> dragon.move([
... Left(20),
... Left(10),
... Right(20)])
Pros and Cons:
Good: extensible to 3D
Bad: require knowledge of an API
Bad: additional entities
Decision: rejected
8.21. Option 20¶
>>> dragon.move([
... Direction('left', 20),
... Direction('left', 10),
... Direction('right', 20)])
>>> dragon.move([
... Direction('left', distance=20),
... Direction('left', distance=10),
... Direction('right', distance=20)])
Pros and Cons:
Good: extensible to 3D
Bad: require knowledge of an API
Bad: additional entities
Decision: rejected
8.22. Option 21¶
>>> dragon.position_x -= 10
>>> dragon.position_y += 20
>>> x = dragon.position_x - 10
>>> y = dragon.position_y + 20
>>> dragon.set_position(x=x, y=y)
>>> x = dragon.position_x
>>> y = dragon.position_y
>>> dragon.set_position(x=x-10, y=y+20)
Pros and Cons:
Good: extensible to 3D, just add
z
attributeBad: require knowledge of an API
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
y=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates encapsulation (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
8.23. Option 22¶
>>> dragon.move(x=-10, y=+20)
>>> dragon.move(dx=-10, dy=+20)
>>> dragon.change_position(left=-10, down=20)
Pros and Cons:
Good: extensible to 3D
Bad: business login in controller
Bad: the user must know the internals, how to calculate the position, which way is up or down (positive or negative shifting), note that
dy=-20
means go up by 20 (we have invertedy
axis)Bad: violates abstraction (OOP Principle)
Bad: violates Tell, Don't Ask (OOP Principle)
Decision: rejected
8.24. Option 23¶
>>> dragon.move('left', 20)
>>> dragon.move('right', 5)
>>> dragon.move('left', distance=20)
>>> dragon.move('right', distance=5)
>>> dragon.move(direction='left', distance=20)
>>> dragon.move(direction='right', distance=5)
>>> dragon.move('l', 20)
>>> dragon.move('r', 5)
>>> dragon.move('l', distance=20)
>>> dragon.move('r', distance=5)
>>> dragon.move(direction='l', distance=20)
>>> dragon.move(direction='r', distance=5)
Pros and Cons:
Good: extensible
Good: extensible to 3D
Bad: not possible to do movement in opposite directions in the same time
Decision: rejected
Problem:
>>> plt.plot(x, y, color='cyan')
>>> plt.plot(x, y, color='c')
Usecase:
>>> df.plot(kind='line')
>>> df.interpolate('polynomial')
>>> plt.plot(x, y, color='red')
8.25. Option 24¶
>>> dragon.move_left(10)
>>> dragon.move_right(10)
>>> dragon.move_upright(10)
>>> dragon.move_downright(10)
>>> dragon.move_downleft(10)
>>> dragon.move_upleft(10)
>>> dragon.move_left_down(10, 20)
Pros and Cons:
Bad: not extensible
Bad: to complex for now
Bad: not possible to do movement in opposite directions in the same time
Decision: rejected, complex
Problem:
>>> db.execute_select(SQL)
>>> db.execute_select_where(SQL)
>>> db.execute_select_order(SQL)
>>> db.execute_select_limit(SQL)
>>> db.execute_select_offset(SQL)
>>> db.execute_select_order_limit(SQL)
>>> db.execute_select_where_order_limit(SQL)
>>> db.execute_select_where_order_limit_offset(SQL)
>>> db.execute_insert(SQL)
>>> db.execute_insert_values(SQL)
>>> db.execute_alter(SQL)
>>> db.execute_alter_table(SQL)
>>> db.execute_alter_index(SQL)
>>> db.execute_create(SQL)
>>> db.execute_create_table(SQL)
>>> db.execute_create_index(SQL)
>>> db.execute_create_database(SQL)
Example:
>>> db.execute(SQL)
Use Case:
>>> read_csv('iris.csv', ';', 'utf-8', True)
>>> read_csv('iris.csv', delimiter=';', encoding='utf-8', verbose=True)
>>> read_csv_with_encoding('iris.csv', 'utf-8')
>>> read_csv_with_delimiter('iris.csv', ';')
>>> read_csv_with_delimiter_encoding('iris.csv', ';', 'utf-8')
>>> read_csv_with_delimiter_encoding_verbose('iris.csv', ';', 'utf-8', True)
>>> file = ReadCSV('iris.csv') # encapsulation?!
>>> file.set_delimiter(';')
>>> file.set_encoding('utf-8')
>>> file.set_verbose(True)
>>> file = ReadCSV('iris.csv') \
... .withDelimiter(';') \
... .withEncoding('utf-8') \
... .withVerbose(True)
>>> file = read_csv('iris.csv',
... delimiter=';',
... encoding='utf-8',
... verbose=True)
8.26. Option 25¶
>>> LEFT = 0x61 # keyboard key code
>>> RIGHT = 0x62
>>> UP = 0x63
>>> DOWN = 0x64
>>>
>>> dragon.move(direction=LEFT, distance=20)
>>> DIRECTION_LEFT = 0x61 # keyboard key code
>>> DIRECTION_RIGHT = 0x62
>>> DIRECTION_UP = 0x63
>>> DIRECTION_DOWN = 0x64
>>>
>>> dragon.move(direction=DIRECTION_LEFT, distance=20)
Pros and Cons:
Good: explicit
Good: verbose
Good: extensible
Bad: to chaotic
Bad: to complex for now
Bad: there is no easy way to know which are possible directions
Bad: not possible to do movement in opposite directions in the same time
Decision: rejected, complex
8.27. Option 26¶
>>> KEY_BINDING = {
... 'ARROW_UP': dragon.move_up,
... 'ARROW_DOWN': dragon.move_down,
... 'ARROW_LEFT': dragon.move_left,
... 'ARROW_RIGHT': dragon.move_right}
>>>
>>>
>>> def action(key, time):
... return KEY_BINDING.get(key)(time)
>>>
>>>
>>> action('ARROW_UP', 5)
Pros and Cons:
Good: explicit
Good: verbose
Good: extensible
Good: there is a enumeration of possible choices for directions
Bad: to complex for now
Decision: rejected, complex
8.28. Option 27¶
>>> class Direction(IntEnum):
... LEFT = 0x61
... RIGHT = 0x62
... UP = 0x63
... DOWN = 0x64
>>>
>>>
>>> dragon.move(Direction.LEFT, distance=5)
>>> dragon.move(direction=Direction.LEFT, distance=5)
Pros and Cons:
Good: explicit
Good: verbose
Good: extensible
Good: ordered
Good: there is a enumeration of possible choices for directions
Bad: to complex for now
Bad: not possible to do movement in opposite directions in the same time
Decision: rejected, complex
8.29. Option 28¶
>>> class Key(IntEnum):
... LEFT = 0x61
... RIGHT = 0x62
... UP = 0x63
... DOWN = 0x64
>>>
>>>
>>> game.bind_key(Key.ARROW_LEFT, dragon.move_left) # good
>>> game.bind_key(Key.ARROW_RIGHT, dragon.move_right) # good
>>>
>>> game.bind_key(..., dragon.move_downright) # bad
>>> game.bind_key(..., dragon.move_downleft) # bad
Pros and Cons:
Bad: not extensible
Bad: to complex for now
Bad: not possible to do movement in opposite directions in the same time
Decision: rejected, complex
8.30. Decision¶
>>> class Dragon:
... def move(self, *,
... left: int = 0, right: int = 0,
... down: int = 0, up: int = 0,
... ) -> None: ...
>>>
>>> dragon.move(left=10, down=20)
Pros and Cons:
Good: easy
Good: verbose
Good: extensible (easy to convert to 3D)
Good: encapsulation
Re-evaluate in future:
>>> class Dragon:
... def change_position(self, *,
... left: int = 0, right: int = 0,
... down: int = 0, up: int = 0,
... ) -> None: ...
>>>
>>> dragon.change_position(left=10, down=20)
Pros and Cons:
Good: consistent with
set_position()
andget_position()
Good: verbose
Good: extensible
Bad: a bit too complex for now