Django • Rapid application development • ./manage.py startapp pol s • Define some models, forms, views and we’re in business!
Applications live and grow • More features are added: – API access – Reporting – Command Line Interface – Integration with other applications – Who knows what else…
Connected Design • Components can access al other components • When you need to access a piece of data or a piece of logic, just import and use it • Development is fast
Modular design • Access to other components goes through well-defined interfaces (API’s) using wel - defined protocols • Components have high cohesion • Components are loosely coupled
Connected vs Modular
Ports and Adapters
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
Uh oh… • Where is my application? Forms P Models Views ersist GUI en App ?? ce
Refactoring Django apps • Rules – Core domain model cannot depend on Django – Tell objects, ask values
Implications • Core model cannot depend on framework – Core model cannot derive from models.Model – Communication with Django goes through adapters • Tel , don’t ask – Views should render from immutable values – So no vote.save() in views.py!
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()
Example – Poll (2) ## Poll engine def register_vote(poll_id, choice_id): p = Pol .objects.get(pk=poll_id) Dependency on Django models selected_choice = p.choice_set.get(pk=choice_id) selected_choice.votes += 1 selected_choice.save()
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)
Example – Poll (3) ## Django model adapter def choice_exists(poll_id, choice_id): return Choice.objects.filter( pol _id=poll_id, pk=choice_id).exists() def increment_vote_count(choice_id) Choice.objects.filter(pk=choice_id).update( votes=F(‘votes’)+1)
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