Extensible Python: Robustness through Addition - PyCon 2024
pviafore
153 views
81 slides
May 20, 2024
Slide 1 of 81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
About This Presentation
A talk given at PyCon 2024 about how you can write sustainable Python by understanding dependencies, composability, open-closed principles, and extensibility. Also covers topics such as Event-Driven Programming and Plug-in based Architecture
Size: 22.4 MB
Language: en
Added: May 20, 2024
Slides: 81 pages
Slide Content
Software is both archeology and time-travel
Your job is to deliver value in a timely manner
How do you enable the future to be just as efficient ?
Extensibility
) Think about the humans
Extensibility Themes
1) Reduce Commit Complexity
2 ) Be Mindful of OCP
Open-Closed Principle
Code should be open to extension and closed for modification
When To Split Are easy things hard to do? Do you encounter pushback against similar features? Do you have consistently high estimates? Do commits contain large changesets? Are you mixing policy changes with mechanisms changes
Policies vs. Mechanisms
3 ) Separate Policies and Mechanisms
From backoff documentation
F rom Flask documentation
4 ) Data-Driven Designs
Data options Can you put your data in a collection? Configuration Files? Persistence Layers (i.e. databases, bucket storage, etc.)?
from typing import Callable @dataclass class Metadata: does_match: Callable [[ User ], bool ] if __name__ == "__main__" : run_self_test()
pip install requests
Physical Dependencies Hard-coded into source code Easy to follow from A to B Easily understandable Easy to find, hard to change Hard to substitute or mock out Understandable by static analysis tools
pipdeptree
pydeps
pyan3
What Happens If You Need Something To Change?
A B C
A B C
A B D
A B Whatever
Logical Dependencies
requests.post( "table-management/pizza-made" , { "id" : order, "pizza" : pizza.to_json() }) # meal is an abstract type meal: Meal = meal_factory.create( "pizza" )
Logical Dependencies Typically determined at run-time Readability suffers Debuggability suffers Hard to find, easy to change Easy to substitute or mock out Not understandable by static analysis tools Crucial for Abstraction
7 ) Trade-off Dependencies Judiciously
Event-Driven Architectures
def complete_order(order: Order ): package_order(order) notify_customer_that_order_is_done(order) notify_restaurant_that_order_is_done(order)
Architectural Extensibility
Producer Transport Consumer
Producer Transport Consumer
pypubsub
from pubsub import pub def notify_customer_that_meal_is_done(order: Order ): # ... snip ... pub.subscribe(notify_customer_that_meal_is_done, "meal-done" )
from pubsub import pub def complete_order(order: Order ): package_order(order) pub.publish( "meal-done" , order)
8 ) Use Event-Driven Architectures to Decouple Producers and Consumers
Pluggable Architectures
Plug-in examples pytest poetry hypothesis pylint
Plugging Into Algorithms
@dataclass class PizzaCreationFunctions: prepare_ingredients: Callable add_pre_bake_toppings: Callable add_post_bake_toppings: Callable
0) Think about the humans 1) Reduce Commit Complexity 2) Be Mindful of OCP 3) Separate Policies and Mechanisms 4) Consider Data-Driven Design 5) Develop Libraries First 6) Create Building Blocks 7) Trade-off Dependencies Judiciously 8) Use Event-Driven Architectures to Decouple Producers/Consumers 9) Use Pluggable Python for Extension Points
10 ) Don't Overextend Yourself
Who Am I? Principal Software Engineer Cloud Software Group Owner of Kudzera, LLC Author of Robust Python Organizer of HSV.py
Extensible Python: Robustness Through Addition Patrick Viafore