22
Hexagonal Design in Django Maarten van Schaik

Hexagonal Design - Maarten van Schaik

Embed Size (px)

DESCRIPTION

Presentatie gegeven tijdens Amsterdam Python Meetup Group

Citation preview

Page 1: Hexagonal Design - Maarten van Schaik

Hexagonal Design in Django

Maarten van Schaik

Page 2: Hexagonal Design - Maarten van Schaik

Django

• Rapid application development• ./manage.py startapp polls• Define some models, forms, views and we’re

in business!

Page 3: Hexagonal Design - Maarten van Schaik

Applications live and grow

• More features are added:– API access– Reporting– Command Line Interface– Integration with other applications– Who knows what else…

Page 4: Hexagonal Design - Maarten van Schaik

Connected Design

• Components can access all other components• When you need to access a piece of data or a

piece of logic, just import and use it• Development is fast

Page 5: Hexagonal Design - Maarten van Schaik

Modular design

• Access to other components goes through well-defined interfaces (API’s) using well-defined protocols

• Components have high cohesion• Components are loosely

coupled

Page 6: Hexagonal Design - Maarten van Schaik

Connected vs Modular

Page 7: Hexagonal Design - Maarten van Schaik

Ports and Adapters

Page 8: Hexagonal Design - Maarten van Schaik

Ports and Adapters

• Specific adapter for each use of the application, e.g. web view, command line, message queue, etc.

• Each adapter connects to a port of the application

• Mock adapters and test harnesses facilitate testing

• Testing becomes easier and faster

Page 9: Hexagonal Design - Maarten van Schaik

Typical Django app

• __init__.py• admin.py• forms.py• models.py• tests.py• urls.py• views.py

Page 10: Hexagonal Design - Maarten van Schaik

App

Uh oh…

• Where is my application?

??GU

I

ModelsViews

Forms

Persistence

Page 11: Hexagonal Design - Maarten van Schaik

Refactoring Django apps

• Rules– Core domain model cannot depend on Django– Tell objects, ask values

Page 12: Hexagonal Design - Maarten van Schaik

Implications

• Core model cannot depend on framework– Core model cannot derive from models.Model– Communication with Django goes through

adapters• Tell, don’t ask– Views should render from immutable values– So no vote.save() in views.py!

Page 13: Hexagonal Design - Maarten van Schaik

Example – Poll

def vote(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) try: selected_choice = p.choice_set.get( pk=request.POST[‘choice’]) except (KeyError, Choice.DoesNotExist): return render(request, …, {error: …}) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(…)

Page 14: Hexagonal Design - Maarten van Schaik

Example – Poll

def vote(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) try: selected_choice = p.choice_set.get( pk=request.POST[‘choice’]) except (KeyError, Choice.DoesNotExist): return render(request, …, {error: …}) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(…)

Mutating data!

Page 15: Hexagonal Design - Maarten van Schaik

Example – Poll (2)

def vote(request, poll_id): try: poll_engine.register_vote(poll_id, request.POST[‘choice’]) except Exception as e: return render(request, …, {error: …}) else: return HttpResponseRedirect(…)

Page 16: Hexagonal Design - Maarten van Schaik

Example – Poll (2)

## Poll engine

def register_vote(poll_id, choice_id): p = Poll.objects.get(pk=poll_id) selected_choice = p.choice_set.get(pk=choice_id) selected_choice.votes += 1 selected_choice.save()

Page 17: Hexagonal Design - Maarten van Schaik

Example – Poll (2)

## Poll engine

def register_vote(poll_id, choice_id): p = Poll.objects.get(pk=poll_id) selected_choice = p.choice_set.get(pk=choice_id) selected_choice.votes += 1 selected_choice.save()

Dependency on Django models

Page 18: Hexagonal Design - Maarten van Schaik

Example – Poll (3)

## Poll engine

def register_vote(poll_id, choice_id): if not poll_repository.choice_exists(poll_id, choice_id): raise PollException(…)

poll_repository.increment_vote_count(choice_id)

Page 19: Hexagonal Design - Maarten van Schaik

Example – Poll (3)

## Django model adapter

def choice_exists(poll_id, choice_id): return Choice.objects.filter( poll_id=poll_id, pk=choice_id).exists()

def increment_vote_count(choice_id) Choice.objects.filter(pk=choice_id).update( votes=F(‘votes’)+1)

Page 20: Hexagonal Design - Maarten van Schaik

Conclusions

• Hexagonal design will help keep speed of adding new features constant

• Encourages modularity and encapsulation• Encourages clean and well-organized

applications• Tests become faster when using plain objects

and data• Django models are not that useful without

coupling with them

Page 21: Hexagonal Design - Maarten van Schaik

That’s it