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

Пройдя все стадии от отрицания до принятия в программировании на Python, могу сказать, что он нам подошел. Но будет неправдой сказать, что нас обошли стороной трудности и проблемы, связанные с особенностями разработки. 

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

Языки и технологии в нашем DWH

Наш DWH облачный и расположен в Google Cloud. Значительную часть технологий этой платформы мы используем для решения задач:

  • BigQuery.

  • Pub/Sub + Dataflow.

  • Dataproc.

  • Google Functions.

  • Composer.

Помимо этого, есть опенсорсные технологии, которые активно используем — Livy и Presto.

Языки нашей разработки можно представить в виде небольшой таблицы: 

Scala

SQL

Python

General-purpose язык.

Быстрый.

Имеет небольшую распространенность.

Поддерживается для многих систем обработки/хранения данных.

Скорость зависит от системы.

Очень распространен (основные конструкции).

General-purpose язык.

Не очень быстрый.

Очень распространен.

Подружить такое количество технологий с доставкой данных из API и бэкенда требует много усилий. Это выросло в целый проект, позволяющий автоматизировать выгрузки и сбор витрин данных. В качестве основного языка мы используем Python, в узких местах Scala. Проект, предоставляющий простой интерфейс для работы со сложными инструментами, мы назвали de-core.

Что же могло пойти не так?

Кейс 1. Навигация в проекте

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

Проблемы:

  • Непонятно, что и где лежит.

  • common.py на 10 тысяч строк.

  • IDE не помогает найти нужные файлы.

  • Документации нет.

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

Что можно сделать:

  • Закоммититься на определенную структуру проекта.

  • Явно разделить функционал для общего использования и частного процесса.

  • Описать базовые классы того, что ожидается от фичи.

  • Начать вести документацию. 

  • Придумать нейминг.

Первым делом мы выделили «ядро» проекта. Это центральная часть, которая часто переиспользуется и должна быть написана наиболее качественно. Провели глубокий рефакторинг этой части, определили базовые структуры для того, чтобы унифицировать разрабатываемые модули. Ввели понятную структуру в проекте для поддержки ETL-процессов, завязались на нашу архитектуру DWH (raw-, ods-, dds-, cdm-слои), и поиск нужных файлов свелся к логическим единицам — источник и таблица.

Пример структуры для источника
Пример структуры для источника

Кейс 2. Помоги себе сам

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

Спор о необходимости типизации в Python
Спор о необходимости типизации в Python

Проблемы:

  • IDE не подсказывает методы класса.

  • Передал аргументы не того типа.

  • Нейминг функций/методов/переменных не всегда помогает.

Типизация помогает понять, что ожидает функция или метод, IDE может подсказать атрибуты и методы. А линтеры автоматически проверят эти ожидания. Мы также определили базовые классы как стандарт написания ETL. Поддержка интерфейса классов позволяет быстрее ориентироваться в чужом коде.

Что можно сделать:

  • Прописать типы.

  • Определить интерфейс ответа функции/метода.

  • Подготовить базовые классы.

  • Настроить линтеры и хуки.

Функция с типизацией и базовым классом
Функция с типизацией и базовым классом

Кейс 3. Сложная схема зависимостей

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

Проблемы:

  • Всегда нужно деплоить проект целиком.

  • Трудно вынести часть проекта в отдельную библиотеку. 

  • Пакеты зависят друг от друга циклически для разных файлов.

Здесь помогает регулярный рефакторинг, когда нужно пересматривать актуальность текущего кода после изменения требований. Как вариант разрыва зависимостей — определение объектов для передачи в функцию/метод/класс.

Что можно сделать:

  • Переразбить проект на пакеты.

  • Провести код-ревью и груминг.

  • Заложить время на рефакторинг.

Можете ли вы позволить себе оформить часть проекта как отдельную библиотеку?
Можете ли вы позволить себе оформить часть проекта как отдельную библиотеку?

Кейс 4. А у меня локально запускается

Одна из частых проблем — запуск в разных средах и локальное тестирование. Существует риск, что среда будет отличаться от продакшена при тесте. А это может привести к непредсказуемым ошибкам.

Проблемы:

  • Разное поведение локально и на проде.

  • Неправильные подсказки от IDE.

Здесь спасает Docker. Все тесты и проверки работы приложения нужно тестировать в виртуальной сред, соответствующей проду.

Что можно сделать:

  • Сделать отдельное виртуальное окружение для проекта;

  • Запускать тесты только в Docker.

Вам тоже выдали новый MacBook с M1?
Вам тоже выдали новый MacBook с M1?

Я пролистал текст, о чем он был?

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

Главное, что стоит держать в голове, начиная большой проект на Python:

  • Промышленная разработка на Python — это сложно.

  • IDE ваш друг, используйте возможности по максимуму.

  • Есть много рекомендаций по тому, как писать код — лучше их изучить.

  • Не поскупитесь на автоматизацию, линтеры, хуки, документацию.

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

Комментарии (8)


  1. vladimir123456
    23.12.2022 13:36
    +1

    А зачем писать большие проекты на Пайтон?
    модно? да
    скорость выполнения? нет
    время реакции? нет
    скорость разработки? нет
    легкость поддержки? нет


    1. mmMike
      23.12.2022 14:16
      +1

      Одно преимущество. Курсы питона за 2 недели "и вы программист".

      Зря спорите с этими людьми. Это не пробиваемо. Вот вам минусов накидали с ходу без аргументов.


    1. whoisking
      23.12.2022 14:31

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

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


  1. Ivan22
    23.12.2022 13:52

    ну ладно питон.. но раз уж питон, то где Airflow ??


    1. markhor
      24.12.2022 01:53
      +1

      Composer он и есть


  1. vladimir123456
    24.12.2022 00:13
    +2

    А не проще ли использовать язык с компилятором вместо линтера и аннотаций? В чем фишка? Если глянуть, например, на код использующий OpenCV, C++ и Python выглядят практически одинаково, но… на C++ код обертки можно распараллелить, а на Python? Добро пожаловать в мультизадачность с shared memory - это даже не хочется комментировать… Для написании небольших кусков кода при разработке алгоритмов, использование Python может быть удобно, но не более того. Понятность Python весьма условна, особенно большая кодовая база на Python. По моему опыту, проще разобраться в обьемном коде написанном на компилируемом языке чем на Python - при одинаковом владении 2 языками.


    1. nikolay_404ov Автор
      24.12.2022 21:06
      +2

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

      Теперь о конкретно нашем случае, стояла проблема следующего характера - была реализована аналитика на некотором clickhouse + доставка данных до него с помощью проекта на java(все inhouse). Через некоторое время количество данных увеличилось значительно, также аналитикам были поставлены задачи на довольно сложный анализ происходящего. Решение оказалось крайней сложно масштабируемым до новых запросов.

      Запрос бизнеса был такой - максимальная скорость перехода на новое решение.

      Собственно здесь было принято решение уйти в облако. Это быстрее, чем инхаус развернуть. Здесь же принято решение писать на питоне.

      Блок оправданий за питон:

      • дата инженеров было буквально несколько, а аналитиков было (относительно дата инженеров) много;

      • дата инженеры стали ботлнеком;

      • Найм новых дата инженеров шел медленно;

      Почти у всех дата инженеров, в том числе у меня, опыта разработки на питоне было мало, до этого мы писали на scala и java почти все. Мы пошли на следующий трюк - мы можем не только своими силами организовать переезд, но и максимально привлечь к этому аналитиков(по крайней мере кодить бизнес логику или писать dag в Composer, он же airflow), ведь они умеют писать код. Правда только на питоне. Это и дало нам некоторое ускорение переезда.

      После того, как основная часть аналитики переехала, мы оформляем этот код как отдельную либу, которой могут пользоваться аналитики и стараемся максимально облегчить ее использование(конфигурации yaml вместо кода). И освобождаем наши руки для сложных инженерных задач, где требуется в том числе scala + поддержка и развитие этой либы как self service постановки простых ETL в прод. Собственно код этой либы и является героем статьи.


  1. K_Chicago
    24.12.2022 00:31
    +3

    поставил плюс исключительно из-за подбора картинок.