More Related Content Similar to Moving from Django Apps to Services (20) Moving from Django Apps to Services3. Django
Project A collection of configuration and apps for a particular Website.
(per Django Project)
4. Django
Project 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. Table
Table Table
Table
Table Table
Table
Table
Table
Table
Table
Table Table
Table
Table
Table
Table Table
Table Table
Table
6. Table
Table Table
Table
Table Table
Table
Table
Table
Table
Table
Table Table
Table
Table
Table
Table Table
Table Table
Table
7. Table
Table Table
Table
p
Table Table
Table
p
Table
A
Table
Table
Table
Table Table
Table
Table
Table
Table Table
Table Table
Table
10. 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.py
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.py
http://www.slideshare.net/jacobian/the-best-and-worst-of-django
16. Within Django
cd myproject && find .
manage.py
Project 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
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. 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
23. REUSABILITY means faster features due to DRY
(Don’t Repeat Yourself )
REUSABILITY does not always mean SCALABILITY
or MAINTAINABILITY
24. Django
Project 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)
25. Django
Project A collection of configuration and apps for a particular Website.
App A web application that does something. I.e. Weblog, Poll, Ticket
system
Service Method of communication over the web.
Web APIs allow combination of multiple services
28. Teams
Support
Knowledge Base
30. Teams Grow
App
Support
App
Knowledge Base
Billing
31. Teams Grow
App
Support Marketing
App
Knowledge Base
Billing
32. Teams Grow
App
Support Marketing API
App
Knowledge Base Analytics Front End
Billing Mobile Social
33. Apps Grow
App
Support Marketing API
p s
App
A p
Knowledge Base Analytics Front End
3 App
Billing Mobile Social
34. Apps Grow
App
Support
p
App
s
Marketing App
API
A p
9
App
Knowledge Base App
Analytics App
Front End
App
Billing App
Mobile App
Social
35. Apps Grow
Support
p s
Marketing API
Ap se
Knowledge Base
9 deb a
Analytics Front End
Billing
C o Mobile Social
1
38. SOA To the Rescue
Photo by Paul Downey (psd on flickr)
42. In Python
data = {
‘question’: “my question”,
‘source’: 123
}
requests.POST(os.environ[‘FAQ_API’] + ‘/
create/’, data=data)
46. More than just API
www.google.com
mail.google.com
calendar.google.com
47. More than just API
www.google.com
mail.google.com
calendar.google.com
..............google.com
55. Where to Start
App
Support App
Marketing App
API
App
Knowledge Base App
Analytics App
Front End
App
Billing App
Mobile App
Social
56. Where to Start
App
Support App
Marketing API
App
Knowledge Base Analytics Front End
Billing Mobile App
Social
65. Within Django
cd myproject && find .
manage.py
Project 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
71. Apps Depend on Other Apps
faq creator
faq app version == 0.1
ticket
faq app version == 0.2
72. Apps Depend on Other Apps
pip install faq==0.1
pip install faq==0.2
pip freeze
faq==0.2
73. Apps Depend on Other Apps
faq creator
faq app version == 0.1
ticket
faq app version == 0.2
77. What’s a service
Provider API_HOST= http://127.0.0.1
Endpoint /v1/create/
Contract {
‘question’: ‘foo bar’,
‘source’: 123
}
80. App
URLs Views Models
Service
Provider Endpoint Contract
81. A SERVICE means REUSABILITY
and enables SCALABILITY and
MAINTAINABILITY
84. Where to start
1. If you’re monolithic, break up the apps first
2. Port something that doesn’t require user
85. Where to start
1. If you’re monolithic, break up the apps first
2. Port something that doesn’t require user
3. Port where you have many dependencies
86. Porting an App
models.py
class 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
87. Porting an App
faqcreator/views.py
from faq.models import faq
i = Faq(title=‘foo’, description=‘bar’, solution=’la posta’)
i.save()
90. Turn it into an API
1. pip install django-tastypie
2. add tastypie to INSTALLED_APPS
91. Turn it into an API
1. pip install django-tastypie
2. add tastypie to INSTALLED_APPS
3. define your APIs
92. Create your API
from
faq/api.py
tastypie.resources import ModelResource
from faq.models import Faq
from django.contrib.auth.models import User
from tastypie.authentication import BasicAuthentication, DjangoAuthorization
from tastypie.authorization import Authorization
class 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)
93. Create your API
api.py
class 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)
94. Create your API
api.py
class 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)
95. Create your API
api.py
class 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)
96. Create your API
api.py
class 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)
97. Create your API
api.py
class 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)
98. Create your API
api.py
class 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)
99. Create your API
urls.py
from faq.api import FaqResource
from tastypie.api import Api
v1_api = Api(api_name='v1')
v1_api.register(FaqResource())
urlpatterns = patterns('',
url(r'^api/', include(v1_api.urls)),
)
100. Use your API
curl -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/
102. Use it in Python
data = {
'title': 'New FAQ',
'source': '1',
'description': 'foo',
'solution': 'bar'
}
r = requests.post(os.environ[‘FAQ_API’] + "api/v1/faq/",
data=data,
auth=('admin', 'testing'))
104. Version Bump
data = {
'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'))
106. Version Bump
data = {
'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'))
108. In our Application
faq_creator/views.py
r = requests.post(os.environ[‘FAQ_API’] + "api/v2/faq/",
data=data,
auth=('admin', 'testing'))
ticket/views.py
r = requests.post(os.environ[‘FAQ_API’] + "api/v1/faq/",
data=data,
auth=('admin', 'testing'))
109. 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
110. Maintainability/Scalability/Agility
cd myproject && find . ls projects
manage.py faq-service
requirements.txt myproject
settings.py cd faq-service && find .
urls.py manage.py
requirements.txt
cat 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
115. Take aways
1. Start non-critical (Cheat)
2. Create services where theres app reuse
3. Create services where theres pain
4. Start small