воскресенье, 27 августа 2017 г.

Краткое руководство по GPG

Перевод: GPG Quickstart
Автор: Эндрю Бикхоф (Andrew Beekhof)

Оказалось кстати, что мне нужно было одновременно освежить знания о GPG и обновить ключи. Я собрал свой опыт (и источники) в тексте ниже, на случай если это окажется кому-то полезным:

Подготовка

Следующие настройки обеспечат, чтобы все ключи, создаваемые в дальнейшем, строго соответствовали стандартам 2013 года. Поместите эти настройки в файл ~/.gnupg/gpg.conf:
# Если все адресаты поддерживают несколько алгоритмов хэширования, выбирать самый надёжный из них:
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
# Предпочтения для новых ключей должны учитывать приоритет алгоритмов, в соответствии с их надёжностью:
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 BZIP2 ZLIB ZIP Uncompressed
# При создании сертификата OpenPGP использовать наиболее надёжный алгоритм хэширования,
# а не алгоритм SHA1, который используется по умолчанию:
cert-digest-algo SHA512
Следующая порция настроек не обязательна, но полезна для улучшения вывода команд gpg в различных ситуациях - в частности, для защиты от подделки. Их тоже нужно поместить в ~/.gnupg/gpg.conf:
# При выводе сертификатов показывать идентификатор пользователя, выделенный из ключей:
fixed-list-mode
# Длинные идентификаторы ключей более защищены от коллизий, чем короткие идентификаторы ключей
# (можно легко создать ключ с любым желаемым коротким идентификатором ключа):
keyid-format 0xlong
# Если вы пользуетесь графической средой (и даже если не пользуетесь ей), вам нужно использовать агента
# (похожие аргументы в пользу этого приведены по ссылке https://www.debian-administration.org/users/dkg/weblog/64):
use-agent
# Взглянув на идентификатор пользователя, вы всегда должны знать, что по мнению gpg он является доверенным,
# т.к. ключ присутствует в вашем брелоке:
verify-options show-uid-validity
list-options show-uid-validity
# Включить недвусмысленный индикатор ключа, которым сделана подпись
# (см. http://thread.gmane.org/gmane.mail.notmuch.general/3721/focus=7234):
sig-notation issuer-fpr@notations.openpgp.fifthhorseman.net=%g

Создание нового ключа

Существует несколько проверок для принятия решения о том, хорош ли ваш старый ключ (или ключи). Однако, если вы создали ключ больше чем пару лет назад, тогда возможно вам действительно нужен новый.

Я воспользовался инструкциями из статьи Анны Гереро (Ana Guerrero), которые были основой текущего руководства Debian, но выбрал тип ключа по умолчанию в соответствии со стандартами 2013 года:
  1. Запустите gpg --gen-key
  2. Выберите 1: RSA и RSA (по умолчанию).
  3. Выберите размер ключа больше 2048.
  4. Задайте срок действия ключа - 2-5 лет (обоснование).
  5. НЕ указывайте комментарий для идентификатора пользователя (объяснение).

Добавление дополнительных идентификаторов пользователя и настройки по умолчанию

С этого момента мой брелок gpg --list-keys выглядит следующим образом:
pub 4096R/0x726724204C644D83 2013-06-24
uid               [ultimate] Andrew Beekhof <andrew@beekhof.net>
sub 4096R/0xC88100891A418A6B 2013-06-24 [expires: 2015-06-24]
Как и у большинства людей, у меня есть несколько адресов электронной почты и я хочу использовать GPG и с ними тоже. Поэтому сейчас самое время добавить их к ключу. Для этого нужно воспользоваться командой gpg --edit-key. У Анны есть хороший пример добавления идентификаторов пользователей и настройки предпочтений. Просто поищите в её инструкциях текст "Add other UID" - "Добавить другой идентификатор пользователя".

Отдельные подключи для шифрования и подписи

Общепринято использовать отдельные ключи для подписывания и шифрования.
Коротко: бывает нужно что-то зашифровать, не подписывая, поскольку подписание может повлечь за собой юридически последствия. Также существует вероятность, что подписанные сообщения могут быть использованы для взлома зашифрованных данных.
По умолчанию gpg создаёт подключ для шифрования, но я воспользуюсь руководством Debian по субключам, чтобы создать ещё один для подписания (вместо того, чтобы использовать секретный мастер-ключ).
Это позволит сделать ваш секретный мастер-ключ ещё более защищённым, избегая его повседневного использования.
Идея заключается в том, чтобы сначала создать копию и сохранить её в ещё более безопасном месте так, что если подключ (и компьютер, где он находится) будут взломаны, мастер-ключ оставался бы в безопасности и им бы всё равно можно было бы отозвать подключи и создать новые.

Подписание нового ключа старым

Если ваш ключ старый, то им можно подписать новый ключ. Это даст знать всем, кто доверяет старому ключу, что новый ключ законный и поэтому ему можно доверять.
Вернёмся снова к советам Анны. Делается это так:
gpg --default-key СТАРЫЙ-КЛЮЧ --sign-key НОВЫЙ-КЛЮЧ
В моём случае команда будет такой:
gpg --default-key 0xEC3584EFD449E59A --sign-key 0x726724204C644D83

Отправка новых ключей на сервер

Сообщим людям, что они могут проверять вашу подпись и отправлять вам зашифрованные сообщения:
gpg --send-key 0x726724204C644D83

Отзыв старых идентификаторов пользователя

Как и в моём случае, вы можете перестать пользоваться каким-то из адресов электронной почты, указанных в старом ключе. Вы не можете удалить адреса из ваших ключей, но вы можете сообщить людям, чтобы они прекратили его использовать.

Чтобы сделать это с моим старым ключом, я воспользуюсь инструкциями из списка рассылки gnupg.

При поиске старого ключа всё выглядит по-прежнему:
pub 1024D/D449E59A 2007-07-20 Andrew Beekhof <beekhof@mac.com>
                              Andrew Beekhof <abeekhof@suse.de>
                              Andrew Beekhof <beekhof@gmail.com>
                              Andrew Beekhof <andrew@beekhof.net>
                              Andrew Beekhof <abeekhof@novell.com>
        Fingerprint=E5F5 BEFC 781F 3637 774F C1F8 EC35 84EF D449 E59A
Но если заглянуть в детали ключа, можно увидеть, что адреса в Novell/SuSE в данное время отмечены красными символами revok.
pub 1024D/D449E59A 2007-07-20
        Fingerprint=E5F5 BEFC 781F 3637 774F C1F8 EC35 84EF D449 E59A

uid Andrew Beekhof <beekhof@mac.com>
sig  sig3 D449E59A 2007-07-20 __________ __________ [selfsig]

uid Andrew Beekhof <abeekhof@suse.de>
sig  sig3 D449E59A 2007-07-20 __________ __________ [selfsig]
sig revok D449E59A 2013-06-24 __________ __________ [selfsig]
...
Таким образом другие люди, имеющие копию gpg, узнают, что больше не нужно использовать этот адрес. Вот почему важно периодически обновлять свои ключи.

Отзыв старых ключей

В реальности вы вряд ли захотите, чтобы люди, использующие старые и потенциально взломанные ключи, продолжали слать вам деликатные сообщения. Поэтому лучше отозвать весь ключ.

Поскольку ключи не могут быть удалены после того, как были загружены на сервер, на самом деле мы обновим существующую запись. Чтобы сделать это, нам понадобится исходный секретный ключ - поэтому держите его в безопасном месте!

Некоторые люди советуют заранее создать отзыв ключа, однако лично мне это кажется просто ещё одной сущностью, за которой нужно постоянно следить.

Осиротевшие ключи, которые не могут быть отозваны, продолжают оставаться действующими для любого, кто захочет отправить вам защищённое сообщение - хорошая причина задать более раннюю дату окончания действия ключа!

Вот как выглядит один из моих старых отозванных ключей:
pub 1024D/DABA170E 2004-10-11 *** KEY REVOKED *** [not verified]
                              Andrew Beekhof (SuSE VPN Access) <andrew@beekhof.net>
        Fingerprint=9A53 9DBB CF73 AB8F B57B 730A 3279 4AE9 DABA 170E

Конечный результат

Мой новый ключ:
pub 4096R/4C644D83 2013-06-24 Andrew Beekhof <andrew@beekhof.net>
                              Andrew Beekhof <beekhof@mac.com>
                              Andrew Beekhof <abeekhof@redhat.com>
Fingerprint=C503 7BA2 D013 6342 44C0 122C 7267 2420 4C64 4D83

Заключение

Я не специалист по этой теме, поэтому буду очень признателен, если вы сообщите мне о любых возможных ошибках в этой статье.

воскресенье, 20 августа 2017 г.

Заметки о Dockerfile

Перевод: Dockerfile Notes
Автор: Соня Гамильтон (Sonia Hamilton)

Примечания переводчика:
Искал однажды что-то в интернете и вышел на блог этой авторши. Сейчас уже не помню почему, добавил этот материал в список того, что было бы неплохо перевести. Сейчас смотрю и недоумеваю - зачем мне это понадобилось? Ничего лучше фразы "чтоб было" в голову не пришло. Ну пусть будет.
Несколько заметок о Dockerfile'ах Docker.

Команды

  • MAINTAINER - автор, адрес электронной почты и т.п.
  • FROM - базовый образ, например Ubuntu.
  • CMD и ENTRYPOINT. Любая из них по отдельности может быть использована для указания исполняемого файла по умолчанию. Если используются обе, то CMD добавляется к ENTRYPOINT для получения командной строки контейнера. Любая из них может быть заменена при запуске docker. Однако CMD легче - она просто берёт остаток команды запуска docker (как "$*" в сценариях оболочки) - разрешая образу docker почувствовать себя в роли выполняемого файла, запущенного через "обёртку".
  • RUN - установочные команды. В режиме разработки разделите команды RUN, так что слои кэшировались и собирались быстрее. В рабочем режиме лучше воспользоваться цепочкой команд RUN, разделённых знаками && или точкой с запятой, поскольку несколько отдельных команд RUN создают несколько слоёв.
  • COPY и ADD. COPY копирует файлы в образ. ADD делает то же самое, но также может разархивировать файл или скачать его по ссылке. Избегайте использования команды ADD, поскольку она обладает излишне сложным поведением.
  • VOLUME - постоянный каталог на родительской файловой системе внутри /var/lib/docker/volumes. Для получения ожидаемого поведения (общий каталог для родительской системы и контейнера) воспользуйтесь командой docker run -v /var/tmp/foo:/var/tmp/foo.
  • ENV, WORKDIR и USER - переменные окружения, текущий каталог и идентификатор пользователя для команд CMD/ENTRYPOINT.
  • EXPOSE - открыть сетевой порт. Воспользуйтесь форматом nn, а не nn:mm, который позволяет пользователю указать публичный порт при помощи опции -p. Порт, открытый при помощи команды EXPOSE может быть автоматически отображён при помощи опции -P.

Сборка, запуск, выполнение

# Собрать образ и пометить его, использовать текущий каталог в качестве контекста
docker build -t="soniah/foo:1.0" .
# Запустить, автоматически отобразить порты. В режиме разработки опустите -D - стандартный поток
# вывода будет выводиться на экран, а контейнер автоматически остановится при нажатии Ctrl-C.
docker run -P sonia/foo
# Получить интерактивную оболочку
docker exec -it random_name bash
# Удалить все старые образы, за исключением базовых образов Ubuntu
docker rmi -f `docker images | tail -n +2 | grep -v 'ubuntu' | awk {'print $3'}`
# Удалить все контейнеры, включая остановленные контейнеры
docker rm -f `docker ps --no-trunc -aq`

Смотрите также

воскресенье, 13 августа 2017 г.

Карго-культ микросервисов

Перевод: The microservices cargo cult
Автор: Ставрос Корокитакис (Stavros Korokithakis)

"Всё сделано правильно. Форма совершенна. Он выглядит точно так же, как и раньше. Но он не работает."

Микросервисы - это чудо. Мы знаем это, потому что об этом говорят все последние истории успеха. Новости наполнены историями о том, как люди берут огромную монолитную систему, разбивают её, добавляют веб-API и наслаждаются всеми выгодами.

Как и со всеми модными практиками, всё начинается довольно невинно. Кто-то пробует её, она хорошо себя показывает. Затем он в красках расписывает все преимущества новой практики. Все воодушевлены и хотят её попробовать. Вскоре появляется бурный поток статей, рассказывающий о том, как хорошо работает новая практика, как много людей попробовали её и убедились в её достоинствах. Однако, никто не рассказывает о тех случаях, когда она не сработала, просто потому что люди не любят рассказывать о собственных неудачах.

Прежде чем продолжить, я хочу разъяснить, что я не заявляю о том, что микросервисы не работают. Как и везде, есть достоинства и недостатки, поэтому я хочу рассказать о недостатках, потому что достоинства уже достаточно освещены.

Карго-культы

Возможно раньше вы слышали фразу "карго-культ". Эта метафора означает попытки достичь успеха, повторяя действия других успешных людей, даже если эти действия никак не ведут к успеху или недостаточны для его достижения.

В данном контексте это означает реализацию микросервисов лишь потому, что все крутые ребята делают так, независимо от того, было ли это уместно и независимо от того, действительно ли успех дела зависел в первую очередь от микросервисов. Как и в случае с другими инструментами, неплохо знать сильные и слабые стороны микросервисов, прежде чем пытаться их использовать.

Достоинства

Давайте начнём с рассмотрения достоинств.
  • Масштабируемость: Это главное. Поскольку микросервисы малы и самодостаточны, их можно разместить на выделенном сервере, если это будет необходимо. Можно поделить данные между экземплярами, распределять между ними нагрузку и настраивать любым способом, который имеет значение для вашего приложения.
    Вы также можете принять решение хранить данные в каждом из сервисов, воспользовавшись таким хранилищем данных (и даже языком программирования или технологией), которое лучше подходит в данном конкретном случае.
  • Более понятная архитектура: Каждый сервис имеет чётко определённые границы, которые обычно неприкосновенны. Больше нельзя обращаться к приватным данным лишь потому, что это удобно. Каждый сервис теперь скрывается за собственным API и не доступен иным образом.
  • Независимое развёртывание: Поскольку каждый сервис отделён, при необходимости его легко можно развернуть даже несколько раз за день. Это может способствовать увеличению времени бесперебойной работы.
  • Меньшая кодовая база: Поскольку код небольшой, в нём проще разобраться. Назначение каждого сервиса и его интерфейс чётко определены, что позволяет кому-нибудь быстрее прочитать код и разобраться в нём, а стало быть - быстрее изменять, расширять и поддерживать его.

Недостатки

  • Сложность: Сразу на порядок увеличивается количество работы, выполняемой серверами. Между ними появляются промежуточные прослойки, работающие через сеть, что на порядок увеличивает общее количество развёртываний и нагрузку на администраторов, а количество сервисов, требующих мониторинга, увеличивается во много десятков раз.
    Также появляется масса дополнительного кода, выполняющего сериализацию и десериализацию данных, передаваемых между сервисами. И хотя обычно его суммарный объём не велик, ничего хорошего в этом нет.
  • Накладные расходы: Все эти разнообразные хранилища данных, преобразования данных и сетевые вызовы не обходятся даром. Лично мне встречалось замедление порядка 1000% из-за перехода на микросервисы (да, в десять раз медленнее).
  • Сегрегация данных: Поскольку все данные теперь хранятся в разрозненных хранилищах данных, нужно следить за их согласованностью. Если в монолитной системе можно было обойтись простым каскадным удалением, то теперь нужна сложная симфония зависимостей, вызовов и перепроверок. Это очень похоже на использование не реляционного хранилища данных. Если у вас есть опыт работы не реляционными хранилищами и вы успешно с ними справлялись, то проблем возникнуть не должно.

Критическая оценка

Как было показано выше, микросервисы имеют несколько крупных достоинств, но у них так же есть и большие недостатки. С точки зрения размера проекта, достоинством окажется более чёткая архитектура и малая кодовая база каждого из сервисов, но расплатой за это будут сегрегация данных и сложность.

Небольшие проекты сильно пострадают от накладных расходов. Крупные проекты получат выгоду от увеличения масштабируемости и независимости развёртывания, что позволит более гибко и свободно добавлять вычислительные мощности для обслуживания растущей нагрузки.

Стоит ли вам использовать микросервисы?

Из описанного выше следует, что небольшие проекты не смогут извлечь пользы из микросервисной архитектуры. Однако, они всё же могут извлечь пользу из более чёткой архитектуры и меньшей кодовой базы, верно?

Не спешите. Ничто не мешает монолитным системам получить эти преимущества, пользуясь достоинствами монолитности. И правда, всё зависит от того, насколько хорошо структурирована архитектура монолитной системы, насколько чётко определены интерфейсы как бы независимых модулей и библиотек. Проблема в том, что для этого нужно соблюдать дисциплину, а с микросервисной архитектурой это получается само собой.

Поэтому разумно будет задать вопрос себе и своей команде - доверяете ли вы себе настолько мало, что готовы взять на себя бремя развёртывания, аппаратного оснащения и снижения скорости лишь для того, чтобы поделить проект? В большинстве случаев можно поступить по-другому: реализовывать чёткие и строгие интерфейсы для взаимодействия между модулями, создать правила - что разрешено и что и как запрещено вызывать извне модулей, а также использовать инструментарий, который поможет вам в этом.

Простой способ принятия решения

Чтобы помочь вам сориентироваться в лабиринте вопросов и доводов при принятии решения - нужны ли вам микросервисы, я создал соответствующую диаграмму. Вот она:

Диаграмма для принятия решений, нужны ли вам микросервисы

Эта диаграмма ответит на все ваши вопросы о микросервисах.

Это немного щекотно.

Заключение

Не начинайте с микросервисов, это сложный способ, который вначале не требуется.

Подведём итоги. Крупнейшее достоинство микросервисной архитектуры, которое трудно получить при других подходах, - это масштабируемость. Все остальные достоинства могут быть достигнуты при соблюдении дисциплины и хорошей организации процесса разработки. К тому же, выбирая монолитный подход, вы получаете надёжность, простоту развёртывания и мониторинга, а также более высокую скорость. Если ваш монолит хорошо спроектирован, его узкие места позднее можно будет выделить в отдельные сервисы, возможно даже переписав их на другой язык, если это потребуется.

Истинно глаголю вам: не начинайте с микросервисов лишь потому что так делают крутые парни. Это сложный подход, который поначалу не нужен. Наслаждайтесь простотой разработки и гибкостью развёртывания, которые даёт одно приложение. Когда ваш бизнес окрепнет и вырастет, и вы не сможете найти достаточно мощный сервер для приложения, только тогда выделяйте части из общей инфраструктуры в отдельные сервисы, соединяя их через HTTP или через очередь сообщений.

Принять участие в последующей священной войне можно найдя меня в Twitter. Чтобы избежать невинных жертв, можете просто оставить комментарий на этой странице.

Примечания переводчика
Сам довольно скептически отношусь к идее микросервисов, по многим причинам.

Во-первых, идея микросервисов основывается на веб-технологиях, но программирование не ограничивается одним только вебом, а за пределами веба имеется более общий подход, который можно назвать "распределённые системы".

Во-вторых, микросервисный подход уместен в больших компаниях, где работает много программистов, разрабатывающих большие публичные веб-сервисы. Но большинство компаний - не большие и не разрабатывают публичные веб-сервисы. Микросервисные системы в небольших компаниях окажутся не уместными - в таких компаниях нет высоких или непредсказуемо быстро растущих нагрузок, они не могут тратить много денег на оборудование и разработчиков.

В-третьих, микросервисная архитектура очень напоминает преждевременную оптимизацию, которая, как известно, является злом. Часто люди пытаются сделать своё приложение масштабируемым тогда, когда это ещё не нужно. Автор этой статьи совершенно верно заметил, что при правильно организованной архитектуре приложения, любой из компонентов приложения можно легко превратить в самостоятельный сервис, написав соответствующие прослойки. Поэтому, на мой взгляд, лучше осваивать приёмы из книги банды четырёх, чем поддаваться карго-культу микросервисов.

воскресенье, 6 августа 2017 г.

Bottle - полный веб-стек без Django

Перевод: Bottle, full stack without Django
Автор: Тьяго Авелино (Thiago Avelino)

Эта заметка в блоге основана на лекции, которую я прочитал здесь, в Бразилии. Посмотрите слайды!

Веб-микрофреймворк Bottle

Bottle - это веб-микрофреймворк, совместимый с WSGI, который зависит только от стандартной библиотеки Python и совместим с Python версий 2.6, 2.7, 3.2, 3.3 и 3.4. Весь исходный текст фреймворка умещается в одном файле. Он был создан Марселем Хеллкэмпом (Marcel Hellkamp - @defnull) и поддерживается сообществом, образовавшимся вокруг этого фреймворка.

Django - это прагматичный фреймворк для быстрой веб-разработки, который написан на Python, использует стандарт MTV (model-template-view - модель-шаблон-представление). Изначально он был создан как система для управления сайтом журнала в городе Лоуренс, в Канзасе. Стал проектом с открытым исходным кодом, был опубликован под лицензией BSD в 2005 году. Название Django фреймворк получил в честь джазового музыканта Джанго Рейнхардта. Django стал очень известен благодаря поставке с "батарейкам", то есть благодаря нескольким библиотекам, добавленным к основному коду фреймворка для упрощения разработки. Вместе с фреймворком эти библиотеки сформировали так называемый "полный стек".

Прагматичный - значит ориентированный на решение практических, реальных задач с чётко определённой целью. Другими словами, команда разработчиков Django приняла некоторые архитектурные решения, а пользователи Django следуют этой архитектуре, не имея возможности легко её поменять.

Хорошо ли, если вместе с веб-фреймворком поставляются "батарейки"? Если вы согласны использовать всё, что даёт вам фреймворк, то ответ - да. Однако, не все веб-проекты одинаковы.

В большинстве проектов используется не более 80% возможностей Django. В тех случаях, когда используется не более 50% возможностей, мы вынуждены платить за все, что было предусмотрено архитектурой Django. То есть теряем в производительности, потому что в Django имеется множество модулей, которые не используются, но по-прежнему продолжают работать. Когда же мы используем микрофреймворк, мы берём на себя роль архитектора приложения. Поскольку у нас нет предопределённой архитектуры, нам нужно время, чтобы определить архитектуру приложения.

Все пакеты Python, которые имеются в библиотеке Django, в микрофреймворке могут быть заменены!

SQLAlchemy

SQLAlchemy существовал до Django (да, до Django) и начиная с 2005 года появилась команда, которая стала заниматься разработкой ORM. Команда же разработчиков Django занимается одновременно и разработкой фреймворка и разработкой ORM. Я думаю, что не стоит говорить о том, что результат работы специалистов обычно бывает лучше, чем результат работы универсалов.

Структура модели:
class Entity(Base):
    __tablename__ = 'entity'
    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    name = Column(String(50))

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "<Entity('%d', '%s')>" % (self.id, self.name)

WTForms

Обходное решение для тех, кто не использует Django и кому нужно работать с формами - это WTForms, которые были созданы в 2008 году и поддержка которых продолжается до сих пор!

Структура формы:
class UserForm(Form):
    name = TextField(validators=[DataRequired(), Length(max=100)])
    email = TextField(validators=[DataRequired(), Length(max=255)])

Шаблонизатор

Jinja2 - это современный удобный для дизайнеров язык шаблонизации для Python, который был создан по образцу шаблонов Django. Он быстрый, широко используется и может быть дополнительно защищён изоляцией рабочего окружения.

Структура шаблона:
<title>{% block title %}{% endblock %}</title>
<ul>
{% for user in users %}
  <li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>

Миграция

Использование Alembic начинается с создания среды миграции. Это каталог сценариев, которые относятся к отдельному приложению. Среда миграции создаётся единожды, а затем поддерживается совместно с исходным кодом самого приложения.

Структура миграции:
revision = '1975ea83b712'
down_revision = None

from alembic import op
import sqlalchemy as sa

def upgrade():
    pass

def downgrade():
    pass
Как создать обновление и откат:
def upgrade():
    op.create_table(
        'account',
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('name', sa.String(50), nullable=False),
        sa.Column('description', sa.Unicode(200)),
    )

def downgrade():
    op.drop_table('account')
Структура модификации таблицы:
"""
$ alembic revision -m "Add a column"
"""

revision = 'ae1027a6acf'
down_revision = '1975ea83b712'

from alembic import op
import sqlalchemy as sa

def upgrade():
    op.add_column('account', sa.Column('last_transaction_date', sa.DateTime))

def downgrade():
    op.drop_column('account', 'last_transaction_date')

Заключение

Здесь было продемонстрировано всё, что можно найти в стеке Django. Я писал эту заметку для не для того, чтобы принизить Django. Я лишь показал, что существуют другие полностековые решения для разработки приложений. Многие люди используют Django, не понимая экосистемы Python. В наше время Django предоставляет множество готовых решений, что заставляет некоторых разработчиков лениться и не наращивать мастерство в проектировании архитектуры приложения.

Помогайте Bottle. Мы - растущее сообщество. Чтобы внести свой вклад в код Bottle, обратитесь к списку открытых задач. В случае сомнений можно обратиться в список рассылки или в IRC-канал.

ПРИСОЕДИНЯЙТЕСЬ

Примечания переводчика:
Считаю, что в статье тема не раскрыта. Не понятно, какая такая особенная архитектура приложения имелась в виду,
которая никак не сочетается с Django. Перечислено несколько средств, которые в чём-то заменяют средства, имеющиеся в Django. Без сомнений, SQLAlchemy заткнёт за пояс джанговский ORM. Безусловно, Jinja2 - очень быстрый шаблонизатор, быстрее джанговского. Но стоит иметь в виду, что в Django все эти средства глубоко интегрированы друг с другом.

Например, в Django есть модельные формы, которые позволяют не создавать подробное описание формы, а автоматически получить это описание из описания модели. При необходимости модельную форму можно даже чуть-чуть подправить, указав какие поля не нужно отображать на форме, какие дополнительные поля, которых нет в модели, нужно добавить к форме, в каком порядке должны следовать поля, можно переопределить отдельные поля формы, определить особые методы валидации и т.д. В простейшем случае описание всей формы ограничивается парой строчек, но если нужно - можно получить гибкость, которую дают обычные формы.

Другой пример - в Django миграции можно сгенерировать автоматически. Автоматическая генерация даже умеет определять переименованные поля. А если же автоматика не сработала корректно, то автоматически сгенерированный код миграции можно подправить и руками.

Наконец, в комплекте с Django имеется административный интерфейс, для которого можно определять собственные классы для редактирования таблиц. В большинстве случаев этот административный интерфейс позволяет сэкономить время на создании шаблонов и написании представлений для просмотра и редактирования таблиц. Да, его возможности ограничены, но ведь в комплекте с Bottle ничего подобного нет, а если и есть в сторонних модулях, то наверняка такие модули тоже окажутся недостаточно интегрированными с ORM или модулем форм - придётся писать дополнительный код, который предоставит необходимую информацию этому модулю.

Я сам в своих проектах использую Django, но для некоторых задач он действительно избыточен. Например, в одной из прошлых своих заметок я писал Тайловый сервер на основе Python, Mapnik и Bottle. Денис Рыков, материалами которого я воспользовался, тоже писал тайловый сервер, воспользовавшись фреймворком Bottle. Для себя я решил, что если приложение не работает с собственной базой данных, а берёт информацию из сторонних источников и занимается лишь её преобразованием, или выполняет какие-то действия по требованию, то лучше использовать Bottle, т.к. в нём нет избыточных возможностей, а сам он обладает минимумом зависимостей и работает с любой версией Python.