AOP in Python API design

41
AOP in Python API design Douwe van der Meij Goldmund, Wyldebeast & Wunderliebe

description

Talk at PyGrunn 2012 by Douwe van der Meij.

Transcript of AOP in Python API design

Page 1: AOP in Python API design

AOP in Python API design

Douwe van der Meij

Goldmund, Wyldebeast & Wunderliebe

Page 2: AOP in Python API design

Outline

● Problem description ● Aspect Oriented Programming ● Implementation

Page 3: AOP in Python API design

Case

● BioBench:○ Application for biogas installations

● Enter measurements ● Normalize data ● Calculate plant performance

Page 4: AOP in Python API design

Problem description

● Large code-base ● A lot of calculations ● Django web-interface ● Make calculations available via an API

Page 5: AOP in Python API design

Problem description

● Is there a library/framework? ● Are the alternatives? ● What is the actual impact of the feature? ● What aspects to take into account?

Page 6: AOP in Python API design

Problem description

● Aspects:○ Security○ Statistics / Logging○ Serialization○ More?

Page 7: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs

Page 8: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs def api_add(request): return add(request.args['lhs'], request.args['rhs'])

Page 9: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs def api_add(request):

if request.args['token'] == valid: return add(request.args['lhs'], request.args['rhs']) raise Exception('Security error')

Page 10: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs def api_add(request):

if request.args['token'] == valid: database.query().alter usage counter return add(request.args['lhs'], request.args['rhs']) raise Exception('Security error')

Page 11: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs def api_add(request):

if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')

Page 12: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs def api_add(request):

if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')

Page 13: AOP in Python API design

Problem description

def add(lhs, rhs): return lhs + rhs def api_add(request):

if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')

Page 14: AOP in Python API design

Problem description

Code base

Page 15: AOP in Python API design

Problem description

Code base

● Security

Page 16: AOP in Python API design

Problem description

Code base

● Statistics / Logging

Page 17: AOP in Python API design

Problem description

Code base

● Serialization

Page 18: AOP in Python API design

Problem description

Code base

● Dispatcher

Page 19: AOP in Python API design

Problem description

Code base

● Scattered / tangled code

Page 20: AOP in Python API design

Aspect Oriented Programming

● What is AOP? ● Separation of concerns (aspects) ● Avoid scattering / tangling

Page 21: AOP in Python API design

Code base

● Scattered / tangled code

Aspect Oriented Programming

Page 22: AOP in Python API design

Code base

● Avoid scattering

Aspect Oriented Programming

Page 23: AOP in Python API design

Code base

● Avoid tangling

Aspect Oriented Programming

Page 24: AOP in Python API design

Aspect Oriented Programming

● How to implement these marvelous concepts?○ In pure python please!

Page 25: AOP in Python API design

Aspect Oriented Programming

● Decorators!

Page 26: AOP in Python API design

Aspect Oriented Programming

● Aspect:○ Pointcuts○ Join points○ Advices

■ Before advices■ After advices■ Around advices

Page 27: AOP in Python API design

Aspect Oriented Programming

● Before advice○ Must execute the function (no side-effects)

def aspect(function): def advice(*args, **kwargs):

do something here return function(*args, **kwargs) return advice

Page 28: AOP in Python API design

Aspect Oriented Programming

● After advice○ Must execute the function (no side-effects)

def aspect(function): def advice(*args, **kwargs): result = function(*args, **kwargs)

do something here return result return advice

Page 29: AOP in Python API design

Aspect Oriented Programming

● Around advice○ Allowed to bypass the function

def aspect(function): def advice(*args, **kwargs):

do something here result = function(*args, **kwargs)

do something here return result return advice

Page 30: AOP in Python API design

Implementation

● How to apply it to our case?

Page 31: AOP in Python API design

Implementation

● The decorators

Page 32: AOP in Python API design

Implementation

● Security aspect○ Around advice

def secure(function): def advice(*args, **kwargs):

if valid token in request object: return function(*args, **kwargs) raise Exception('No valid token provided') return advice

Page 33: AOP in Python API design

Implementation

● Statistics aspect○ Before advice

def statistics(function): def advice(*args, **kwargs):

increase API usage count for the user logged in return function(*args, **kwargs) return advice

Page 34: AOP in Python API design

Implementation

● Serialization aspect○ Around advice

def serialize(function): def advice(format, *args, **kwargs): if not format in ['html', 'xml', 'json']:

raise exception result = function(*args, **kwargs)

make a http response of 'result' in the right format return advice

Page 35: AOP in Python API design

Implementation

● Dispatcher aspect○ Around advice

def dispatch(function): def advice(*args, **kwargs):

proxy the API call to a call to the core system return advice

Page 36: AOP in Python API design

Implementation

mapping = { 'api_function': (core_function, ['lhs', 'rhs']), 'create_token': (create_token, ['username', 'password']),}

Page 37: AOP in Python API design

Implementation

def dispatch(function): def advice(*args, **kwargs):

if API call in proxy mapping: core_function, params = mapping[API call] kwargs.update(extract(params, request)) return function(proxy=core_function,

params=params, *args, **kwargs)

raise exception return advice

Page 38: AOP in Python API design

Implementation

● The API itself

Page 39: AOP in Python API design

Implementation

@secure@serialize@statistics@dispatchdef api_call(*args, **kwargs): proxy_function = kwargs['proxy'] params = kwargs['params']

return proxy_function(extract params from kwargs)

Page 40: AOP in Python API design

Conclusion

● AOP offers some brilliant concepts in software engineering

● Separate your concerns / aspects

○ Avoid classical scattering and tangling

Page 41: AOP in Python API design

Questions?

● Thank you!

[email protected]@douwevandermeij