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 Slide

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

    View Slide

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

    View Slide

  4. View Slide

  5. 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 Slide

  6. I love SaaS

    View Slide

  7. SaaS

    View Slide

  8. Multi Tenant

    View Slide

  9. Managed Cloud?
    single tenant

    View Slide

  10. But also …
    On Premises?

    View Slide

  11. Diving In

    View Slide

  12. patterns are
    universal
    (examples are Python)

    View Slide

  13. Building Blocks

    View Slide

  14. boring is better
    than fancy

    View Slide

  15. Postgres & Redis & AMQP
    (for example)

    View Slide

  16. Foundation

    View Slide

  17. Security First

    View Slide

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

    View Slide

  19. context
    awareness

    View Slide

  20. 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 Slide

  21. 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 Slide

  22. 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 Slide

  23. User Access Scope
    Restrictions

    View Slide

  24. 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 Slide

  25. Audit Logs

    View Slide

  26. 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 Slide

  27. i18n & l10n

    View Slide

  28. 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 Slide

  29. Monolith → SOA

    View Slide

  30. SOA is complex

    View Slide

  31. Start Simple Evolve

    View Slide

  32. Design as you go

    View Slide

  33. Developer Happiness

    View Slide

  34. 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 Slide

  35. master is stable

    View Slide

  36. institutionalize
    bidirectional
    compatibility

    View Slide

  37. fast iteration
    trumps
    scalability

    View Slide

  38. Quick Release Cycles

    View Slide

  39. make dev and
    prod look alike

    View Slide

  40. short and small
    pull requests

    View Slide

  41. feature flag
    new functionality

    View Slide

  42. QA
    &

    View Slide