Moving from Django Apps to Services

1,745 views
1,612 views

Published on

Slides from a talk on moving from Django applications to using services which enable better maintainability and scaling.

Moving from Django Apps to Services

  1. 1. Django Apps to Services
  2. 2. Craig Kerstiens @craigkerstiens work at @heroku
  3. 3. DjangoProject A collection of configuration and apps for a particular Website. (per Django Project)
  4. 4. DjangoProject A collection of configuration and apps for a particular Website.App A web application that does something. I.e. Weblog, Poll, Ticket system (per Django Project)
  5. 5. TableTable Table Table Table Table Table Table Table TableTable Table Table TableTable Table Table Table Table Table Table
  6. 6. TableTable Table Table Table Table Table Table Table TableTable Table Table TableTable Table Table Table Table Table Table
  7. 7. TableTable Table Table p Table Table Table p Table A Table TableTable Table Table TableTable Table Table Table Table Table Table
  8. 8. Monolithic Monster
  9. 9. Monolithic Monster$ ls mysitemodels.pyviews.pyforms.pyadmin.py
  10. 10. Monolithic Monster$ ls mysite $ wc -l models.pymodels.py 2557 models.pyviews.py $ wc -l view.spyforms.py 14241 views.pyadmin.py
  11. 11. Monolithic Monster $ ls mysite $ wc -l models.py models.py 2557 models.py views.py $ wc -l view.spy forms.py 14241 views.py admin.pyhttp://www.slideshare.net/jacobian/the-best-and-worst-of-django
  12. 12. Within Django
  13. 13. Within DjangoProject
  14. 14. Within DjangoProject App App App
  15. 15. Within DjangoProject Tickets App FAQ App FaqCreator App
  16. 16. Within Django cd myproject && find . manage.pyProject requirements.txt settings.py urls.py ./faq/admin.py ./faq/forms.py Tickets App ./faq/models.py ./faq/urls.py ./faq/views.py ./faqcreator/admin.py FAQ App ./faqcreator/forms.py ./faqcreator/models.py ./faqcreator/urls.py ./faqcreator/views.py ./tickets/admin.py FaqCreator App ./tickets/forms.py ./tickets/models.py ./tickets/urls.py ./tickets/views.py
  17. 17. Reusability
  18. 18. cd myproject && find . Reusability
  19. 19. cd myproject && find . Reusability manage.py requirements.txt settings.py urls.py ./faq/admin.py ./faq/forms.py ./faq/models.py ./faq/urls.py ./faq/views.py ./faqcreator/admin.py ./faqcreator/forms.py ./faqcreator/models.py ./faqcreator/urls.py ./faqcreator/views.py ./tickets/admin.py ./tickets/forms.py ./tickets/models.py ./tickets/urls.py ./tickets/views.py
  20. 20. cd myproject && find . Reusability cd myproject && find . manage.py requirements.txt manage.py settings.py requirements.txt urls.py settings.py ./faq/admin.py urls.py --> ./faq/forms.py ./faq/models.py cat myproject/requirements.txt ./faq/urls.py ./faq/views.py faq==0.1 ./faqcreator/admin.py faqcreator==0.1 ./faqcreator/forms.py tickets==0.1 ./faqcreator/models.py ./faqcreator/urls.py ./faqcreator/views.py ./tickets/admin.py ./tickets/forms.py ./tickets/models.py ./tickets/urls.py ./tickets/views.py
  21. 21. REUSABILITY means faster features due to DRY(Don’t Repeat Yourself )
  22. 22. REUSABILITY means faster features due to DRY(Don’t Repeat Yourself )REUSABILITY does not always mean SCALABILITYor MAINTAINABILITY
  23. 23. DjangoProject A collection of configuration and apps for a particular Website.App A web application that does something. I.e. Weblog, Poll, Ticket system (per Django Project)
  24. 24. DjangoProject A collection of configuration and apps for a particular Website.App A web application that does something. I.e. Weblog, Poll, Ticket systemService Method of communication over the web. Web APIs allow combination of multiple services
  25. 25. Tech imitate TeamsProject Company Tickets App Support FAQ App Knowledge Base FaqCreator App
  26. 26. Teams SupportKnowledge Base
  27. 27. Teams Grow App Support AppKnowledge Base
  28. 28. Teams Grow App Support AppKnowledge Base Billing
  29. 29. Teams Grow App Support Marketing AppKnowledge Base Billing
  30. 30. Teams Grow App Support Marketing API AppKnowledge Base Analytics Front End Billing Mobile Social
  31. 31. Apps Grow App Support Marketing API p s App A pKnowledge Base Analytics Front End3 App Billing Mobile Social
  32. 32. Apps Grow App Support p App s Marketing App API A p 9 AppKnowledge Base App Analytics App Front End App Billing App Mobile App Social
  33. 33. Apps Grow Support p s Marketing API Ap seKnowledge Base 9 deb a Analytics Front End Billing C o Mobile Social 1
  34. 34. SOA To the Rescue
  35. 35. SOA To the Rescue
  36. 36. SOA To the Rescue Photo by Paul Downey (psd on flickr)
  37. 37. ServiceDefined contract for communicating
  38. 38. ServiceDefined contract for communicating$ curl -O $FAQ_API/create/ -X “question=my question source=123”
  39. 39. In Python
  40. 40. In Pythondata = { ‘question’: “my question”, ‘source’: 123}requests.POST(os.environ[‘FAQ_API’] + ‘/create/’, data=data)
  41. 41. More than just API
  42. 42. More than just APIwww.google.com
  43. 43. More than just APIwww.google.commail.google.com
  44. 44. More than just APIwww.google.commail.google.comcalendar.google.com
  45. 45. More than just APIwww.google.commail.google.comcalendar.google.com..............google.com
  46. 46. Types of Services
  47. 47. Types of Servicessite
  48. 48. Types of Servicessitesubdomain
  49. 49. Types of ServicessitesubdomainAPI
  50. 50. Types of ServicessitesubdomainAPI - no auth required
  51. 51. Types of ServicessitesubdomainAPI - no auth required - API auth required
  52. 52. Types of ServicessitesubdomainAPI - no auth required - API auth required - user auth required
  53. 53. Where to Start App Support App Marketing App API AppKnowledge Base App Analytics App Front End App Billing App Mobile App Social
  54. 54. Where to Start App Support App Marketing API AppKnowledge Base Analytics Front End Billing Mobile App Social
  55. 55. 1 JavascriptMany pages
  56. 56. LA POSTA
  57. 57. Within Django cd myproject && find . manage.pyProject requirements.txt settings.py urls.py ./faq/admin.py ./faq/forms.py Tickets App ./faq/models.py ./faq/urls.py ./faq/views.py ./faqcreator/admin.py FAQ App ./faqcreator/forms.py ./faqcreator/models.py ./faqcreator/urls.py ./faqcreator/views.py ./tickets/admin.py FaqCreator App ./tickets/forms.py ./tickets/models.py ./tickets/urls.py ./tickets/views.py
  58. 58. Apps Depend on Other Apps
  59. 59. Apps Depend on Other Appsfaq creator
  60. 60. Apps Depend on Other Appsfaq creator faq app
  61. 61. Apps Depend on Other Appsfaq creator faq appticket
  62. 62. Apps Depend on Other Appsfaq creator faq appticket faq app
  63. 63. Apps Depend on Other Appsfaq creator faq app version == 0.1ticket faq app version == 0.2
  64. 64. Apps Depend on Other Appspip install faq==0.1pip install faq==0.2pip freezefaq==0.2
  65. 65. Apps Depend on Other Appsfaq creator faq app version == 0.1ticket faq app version == 0.2
  66. 66. Back to APIs
  67. 67. What’s a serviceProvider API_HOST= http://127.0.0.1
  68. 68. What’s a serviceProvider API_HOST= http://127.0.0.1Endpoint /v1/create/
  69. 69. What’s a serviceProvider API_HOST= http://127.0.0.1Endpoint /v1/create/Contract { ‘question’: ‘foo bar’, ‘source’: 123 }
  70. 70. App
  71. 71. AppURLs Views Models
  72. 72. AppURLs Views Models ServiceProvider Endpoint Contract
  73. 73. A SERVICE means REUSABILITYand enables SCALABILITY andMAINTAINABILITY
  74. 74. Where to start
  75. 75. Where to start1. If you’re monolithic, break up the apps first
  76. 76. Where to start1. If you’re monolithic, break up the apps first2. Port something that doesn’t require user
  77. 77. Where to start1. If you’re monolithic, break up the apps first2. Port something that doesn’t require user3. Port where you have many dependencies
  78. 78. Porting an App models.pyclass Faq(models.Model): title = models.CharField(max_length=100) source = models.IntegerField(blank=True, null=True) description = models.TextField() solution = models.TextField() def __unicode__(self): return self.title
  79. 79. Porting an App faqcreator/views.pyfrom faq.models import faqi = Faq(title=‘foo’, description=‘bar’, solution=’la posta’)i.save()
  80. 80. Turn it into an API
  81. 81. Turn it into an API1. pip install django-tastypie
  82. 82. Turn it into an API1. pip install django-tastypie2. add tastypie to INSTALLED_APPS
  83. 83. Turn it into an API1. pip install django-tastypie2. add tastypie to INSTALLED_APPS3. define your APIs
  84. 84. Create your APIfrom faq/api.py tastypie.resources import ModelResourcefrom faq.models import Faqfrom django.contrib.auth.models import Userfrom tastypie.authentication import BasicAuthentication, DjangoAuthorizationfrom tastypie.authorization import Authorizationclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create(bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  85. 85. Create your API api.pyclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create( bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  86. 86. Create your API api.pyclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create( bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  87. 87. Create your API api.pyclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create( bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  88. 88. Create your API api.pyclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create( bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  89. 89. Create your API api.pyclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create( bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  90. 90. Create your API api.pyclass FaqResource(ModelResource): class Meta: queryset = Faq.objects.all() resource_name = faq list_allowed_methods = [get, post] authentication = BasicAuthentication() authorization = Authorization() def obj_create(self, bundle, request=None, **kwargs): return super(FaqResource, self).obj_create( bundle, request, user=request.user) def apply_authorization_limits(self, request, object_list): return object_list.filter(user=request.user)
  91. 91. Create your API urls.pyfrom faq.api import FaqResourcefrom tastypie.api import Apiv1_api = Api(api_name=v1)v1_api.register(FaqResource())urlpatterns = patterns(, url(r^api/, include(v1_api.urls)),)
  92. 92. Use your APIcurl -H "Content-Type: application/json" --user admin:testing -X POST --data {"title": "New FAQ", "source": "1", "description": "foo", "solution": "bar"} http://127.0.0.1:8000/api/v1/faq/
  93. 93. Use it in Python
  94. 94. Use it in Pythondata = { title: New FAQ, source: 1, description: foo, solution: bar}r = requests.post(os.environ[‘FAQ_API’] + "api/v1/faq/", data=data, auth=(admin, testing))
  95. 95. Version Bump
  96. 96. Version Bumpdata = { title: New FAQ, source: 1, description: foo, solution: bar, related: [123, 456]}r = requests.post(os.environ[‘FAQ_API’] + "api/v2/faq/", data=data, auth=(admin, testing))
  97. 97. Version Bump
  98. 98. Version Bumpdata = { title: New FAQ, source: 1, description: foo, solution: bar, related: [123, 456]}r = requests.post(os.environ[‘FAQ_API’] + "api/v2/faq/", data=data, auth=(admin, testing))
  99. 99. In our Applicationfaq_creator/views.py ticket/views.py
  100. 100. In our Application faq_creator/views.pyr = requests.post(os.environ[‘FAQ_API’] + "api/v2/faq/", data=data, auth=(admin, testing)) ticket/views.pyr = requests.post(os.environ[‘FAQ_API’] + "api/v1/faq/", data=data, auth=(admin, testing))
  101. 101. cd myproject && find . Reusability cd myproject && find . manage.py requirements.txt manage.py settings.py requirements.txt urls.py settings.py ./faq/admin.py urls.py --> ./faq/forms.py ./faq/models.py cat myproject/requirements.txt ./faq/urls.py ./faq/views.py faq==0.1 ./faqcreator/admin.py faqcreator==0.1 ./faqcreator/forms.py tickets==0.1 ./faqcreator/models.py ./faqcreator/urls.py ./faqcreator/views.py ./tickets/admin.py ./tickets/forms.py ./tickets/models.py ./tickets/urls.py ./tickets/views.py
  102. 102. Maintainability/Scalability/Agilitycd myproject && find . ls projects manage.py faq-service requirements.txt myproject settings.py cd faq-service && find . urls.py manage.py requirements.txtcat myproject/requirements.txt faq==0.1 --> settings.py urls.py cd myproject && find . faqcreator==0.1 tickets==0.1 manage.py requirements.txt settings.py urls.py cat myproject/requirements.txt faqcreator==0.1 tickets==0.1
  103. 103. Maintainability/Scalability/Agility
  104. 104. Maintainability/Scalability/Agility Faq Project - Its own Django project - 1 Django app - Own database - Own deployment
  105. 105. Maintainability/Scalability/AgilityMy Project Faq Project - Contained Django Project - Its own Django project - 2 Django apps - 1 Django app - Own database - Own database - Own deployment - Own deployment
  106. 106. Take aways
  107. 107. Take aways1. Start non-critical (Cheat)2. Create services where theres app reuse3. Create services where theres pain4. Start small
  108. 108. Others
  109. 109. Others1. Expect APIs to fail2. Flask is great for APIs3. Make it easy to setup/test
  110. 110. Fin. Resourceshttp://www.craigkerstiens.comhttp://bit.ly/djangoappstoservices/http://www.12factor.nethttp://github.com/craigkerstiens/

×