Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pragmantic SaaS Architecture

Pragmantic SaaS Architecture

A presentation I gave at wearedevelopers about pragmatic SaaS architectures.

Armin Ronacher

May 11, 2017
Tweet

More Decks by Armin Ronacher

Other Decks in Programming

Transcript

  1. Pragmatic SaaS
    Architecture
    Armin @mitsuhiko Ronacher

    View full-size slide

  2. )J *N"SNJO
    BOE*EP0QFO4PVSDF
    MPUTPG1ZUIPOBOE4BB4

    View full-size slide

  3. lucumr.pocoo.org
    github.com/mitsuhiko
    twitter.com/mitsuhiko
    read
    discover
    follow

    View full-size slide

  4. 800°C
    36° 2' 0.4662" N
    118° 15' 38.7792" W
    795°C
    789°C
    797°C
    793°C
    805°C
    782°C

    View full-size slide

  5. Multi Tenant

    View full-size slide

  6. Managed Cloud?
    single tenant

    View full-size slide

  7. But also …
    On Premises?

    View full-size slide

  8. patterns are
    universal
    (examples are Python)

    View full-size slide

  9. Building Blocks

    View full-size slide

  10. boring is better
    than fancy

    View full-size slide

  11. Postgres & Redis & AMQP
    (for example)

    View full-size slide

  12. Security First

    View full-size slide

  13. If you only take one thing
    away from this talk …

    View full-size slide

  14. context
    awareness

    View full-size slide

  15. Tenant Isolation
    from framework import get_request
    def get_tenant_from_request():
    request = get_request()
    auth = validate_auth(request.headers.get('Authorization'))
    return Tenant.query.get(auth.tenant_id)
    def get_current_tenant():
    rv = tls.current_tenant
    if rv is None:
    rv = get_tenant_from_request()
    tls.current_tenant = rv
    return rv

    View full-size slide

  16. Automatic Tenant Scoping
    def batch_update_projects(ids, changes):
    projects = Project.query.filter(
    Project.id.in_(ids) &
    Project.status != ProjectStatus.INVISIBLE
    )
    for project in projects:
    update_project(project, changes)
    DANGER!

    View full-size slide

  17. Automatic Tenant Scoping
    class Project(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    status = db.Column(db.Integer)
    tenant_id = db.Column(db.Integer, db.ForeignKey('tenants.id'))
    tenant = db.relationship(Tenant)
    @classproperty
    def query(cls):
    return db.Query(self).filter(
    Project.tenant == get_current_tenant()
    )

    View full-size slide

  18. User Access Scope
    Restrictions

    View full-size slide

  19. User Scope & Request Scope
    def get_current_scopes():
    current_user = get_current_user()
    if current_user is None:
    all_scopes = set(['anonymous'])
    else:
    all_scopes = current_user.get_roles()
    return all_scopes & scopes_from_request_authorization()

    View full-size slide

  20. Log Security Related Actions
    def log(action, message=None):
    data = {
    'action': action,
    'timestamp': datetime.utcnow()
    }
    if message is not None:
    data['message'] = message
    if request:
    data['ip'] = get_request().remote_addr
    user = get_current_user()
    if user is not None:
    data['user'] = User
    db.session.add(LogMessage(**data))

    View full-size slide

  21. Language from User or Request
    def get_current_language():
    user = get_current_user()
    if user is not None:
    return user.language
    request = get_current_request()
    if request and request.accept_languages:
    return request.accept_languages[0]
    return 'en_US'

    View full-size slide

  22. Monolith → SOA

    View full-size slide

  23. SOA is complex

    View full-size slide

  24. Start Simple Evolve

    View full-size slide

  25. Design as you go

    View full-size slide

  26. Developer Happiness

    View full-size slide

  27. custom linters
    on commit
    mitsuhiko at herzog in ~/Development/sentry on git:master+? workon sentry
    $ git ci -am 'Performance improvements to the data scrubber.'
    src/sentry/utils/data_scrubber.py:147:1: F401 'unused' imported but unused

    View full-size slide

  28. master is stable

    View full-size slide

  29. institutionalize
    bidirectional
    compatibility

    View full-size slide

  30. fast iteration
    trumps
    scalability

    View full-size slide

  31. Quick Release Cycles

    View full-size slide

  32. make dev and
    prod look alike

    View full-size slide

  33. short and small
    pull requests

    View full-size slide

  34. feature flag
    new functionality

    View full-size slide