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

Контрактное программирование и классы данных в Python

Контрактное программирование и классы данных в Python

Сергей Левитин (Python & Go разработчик в Ostrovok.ru) @ Moscow Python Meetup № 41

"О том, как мы в Островке поддерживаем стабильность и расширяемость кода на Python вместе с PyContracts и типизированными Data-классами".

Видео: http://www.moscowpython.ru/meetup/41/kontraktnoe-programmirovanie-i-klassy-dannyh-v-pyt/

Moscow Python Meetup
PRO

December 22, 2016
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. Контракты
    и классы данных
    в Python
    Сделайте свой продукт стабильнее и легче
    в тестировании

    View Slide

  2. Что такое контракты?
    - Контракты – это правила валидации входных
    и выходных параметров функций;
    - Для работы с контрактами в Python мы
    используем библиотеку PyContracts.

    View Slide

  3. Пример функции с контрактом
    from contracts import contract
    @contract
    def sum(a, b):
    """
    :type a: int|float > 0
    :type b: int|float > 0
    :rtype: int|float
    """
    Функция sum принимает два аргумента типа int или float и
    возвращает значение соответствующего типа.

    View Slide

  4. Для чего нужны контракты?
    - Чтобы сделать динамически типизированный
    код стабильнее и защищеннее;
    - Чтобы писать больше тестов для бизнес-логики
    и не заморачиваться с проверкой корректности
    структур данных.

    View Slide

  5. Классы данных
    - Класс данных — это класс, который хранит
    только данные без описания поведения;
    - Мы используем собственное решение
    TypedDict для создания Data-классов.

    View Slide

  6. Пример класса данных
    class BookingResult(TypedDict):
    user_id = f.PositiveInt()
    order_id = f.PositiveInt()
    created_at = f.DateTime()
    comment = opt(f.StringNotEmpty)
    Класс BookingResult хранит информацию о результате
    бронирования.

    View Slide

  7. Для чего нужны классы данных?
    - Они помогают упростить обмен данными между
    сервисами;
    - Когда разработчик создает API, он описывает
    формат входных и выходных данных в классе и
    прикрепляет ссылку на этот класс к описанию API;
    - Поддержка валидации полей помогает не писать
    утомительные проверки для входных данных.

    View Slide

  8. Контракты вместе с Data-классами
    class BookingRequest(TypedDict):
    ROOM_TYPES = ('Economy', 'Standard', 'Premium')
    hotel_id = f.PositiveInt()
    checkin_date = f.Date()
    checkout_date = f.Date()
    room_type = f.StringNotEmpty(choices=ROOM_TYPES)
    Определим класс BookingRequest, который описывает структуру
    запроса для создания брони.

    View Slide

  9. class BookingResult(TypedDict):
    user_id = f.PositiveInt()
    order_id = f.PositiveaInt()
    created_at = f.DateTime()
    price = f.Decimal()
    comment = opt(f.StringNotEmpty)
    В классе BookingResult будет храниться информация о
    результате бронирования.

    View Slide

  10. @contract
    def make_booking(request: BookingRequest) -> BookingResult:
    # ...
    return BookingResult(
    user_id=1,
    order_id=10,
    created_at=datetime.now(),
    price=Decimal('10000'),
    comment='hello!'
    )
    Функция make_booking принимает BookingRequest, выполняет
    бронирование и возвращает BookingResult.

    View Slide

  11. Классы данных в тестах
    book_request = BookingRequest(
    hotel_id=10,
    checkin_date=datetime.date(2016, 01, 02)
    checkout_date=datetime.date(2016, 01, 10),
    )
    response = self.post('/api/book/', data=book_request.simplify())
    self.assertEqual(response.status, 200)
    # validate correct response format
    book_result = BookingResult(**response.json())
    self.assertEqual(book_result.order_id, 10)

    View Slide

  12. Удобство написания и поддержки тестов
    - Классы данных помогают избавиться от ручных
    проверок структур данных в тестах и сосредоточиться
    на тестировании бизнес-логики.
    - Контракты дают уверенность в корректности типов
    аргументов и возвращаемых значений;
    - Увеличивается качество регрессивного тестирования
    засчет двух предыдущих пунктов.

    View Slide

  13. Приятные мелочи
    - Pycontracts поддерживает синтаксис Python 3
    type hinting;
    - Контракты проверяются только в тестовом
    окружении и не замедляют продуктив;
    - TypedDict поддерживает простую сериализацию
    и десериализацию данных в JSON/XML/Msgpack.

    View Slide

  14. Резюмируя
    - Ваш продукт начинает работать стабильнее;
    - Код становится более поддерживаемым
    и тестируемым;
    - А разработчики и QA — немного счастливее.
    C контрактами и классами данных

    View Slide

  15. Полезные ссылки
    - PyContracts: https://andreacensi.github.io/contracts/
    - Библиотеки TypedDict пока нет в Open Source.
    Вместо него можно использовать Schematics:
    https://schematics.readthedocs.io/en/latest/

    View Slide

  16. Спасибо за внимание!
    Автор: Сергей Левитин
    Email: [email protected]
    Github: github.com/selevit

    View Slide