Рубрики
Без рубрики

Ramblings по рефакторингу, API Design и запись тестируемого кода.

Есть много ресурсов, касающихся проектирования хороших API. Я лично нашел разговор с Джошуа Б … Помечено программированием, Python, Design, Software Engineering.

Есть много ресурсов, касающихся проектирования хороших API. Я лично нашел Разговор с Джошуа Блох Чтобы быть чрезвычайно информативным, Мартин Фуэлер тоже был превосходным со своим блогем, разговорами и книгами. Конструктивные шаблоны Erich Gamma et al. также является проницательным ресурсом. Я упоминаю все это, так как я пытаюсь передиснуть всю свою мудрость и смешать его с моим опытом. Моя работа была в основном строит веб-службы, и я собираюсь использовать API в качестве держателя места для HTTP API в контексте этого блога, но он также может быть применим к любому виду API.

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

Должно быть легко учиться и запоминать.

Каждый из нас имеет или будет испытывать (d) Как хорошее/плохое соглашение об именах может повлиять на легкость работы с определенным API. Быть последовательным является одним из самых простых способов добиться простоты в дизайне. Снижение избыточности – это еще одна.

Однажды я построил что-то вроде следующих конечных точек для получения двух разных видов отелей.

api/XHotels/
api/XHotel/


api/search/Y/?method=list
api/search/Y/?method=detail

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

Адаптируется для изменения. Уверенность проектирования по деталям реализации затрудняет добавление/удаление логики.

Все вещи в программном обеспечении начинаются с понимания требований сначала. В некоторых случаях требования проходят прямые, но чаще всего не нужно задавать вопросы добиться точности при достижении «Что нужно сделать». «Что» более нюанс, чем просто иметь конечный результат: «Что» также будет включать «Как» как в том, как просто/Насколько легко/как быстро/Насколько безопасны и т. Д. Реализация должна быть скорректирована на желаемое использование, а не наоборот. Интуитивно понятный дизайн API может быть достигнут сначала сосредоточены на случаях использования, а затем перейти к реализации.

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

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

def create_organisation_profile(**kwargs):
    if 'registration' in kwargs:
        model = PremiumUser
    else:
        model = BasicUser
    ...

Создание логики зависят от того, содержит ли входные данные определенным элементом, делает код плохой подгонкой для будущих дополнений/удаленных типов клиентов в нашем приложении. Гораздо более эффективно иметь дополнительное поле, передаваемое на функцию/API, чтобы отличить какую логику для выполнения. Решение между логиями V/S Enums становится важным в этом случае, зависит от того, может ли наш корпус на использование иметь более двух вариаций или нет, то есть четко прогнозируя, может ли быть только 2 своего рода. Гораздо более долговечный способ написания вышеуказанной логики будет следующим –

def create_organisation_profile(**kwargs):
    if kwargs['type'] == PREMIUM:
        model = PremiumUser
    elif kwargs['type'] == BASIC:
        model = BasicUser
    ...

Где можно добавить еще условные элементы ELIF для обработки любых будущих типов клиентов.

Разделение кода, который взаимодействует с различными слоями программного обеспечения как можно больше. Для E.g.: DB-запросы, сторонние API вызовы, push-уведомления и т. Д.

Я обнаружил, что имение исходного кода, разделенного на разные логические слои, чрезвычайно полезно как в разработке, так и в обслуживании приложения. Другими словами после шаблона MVC/MVP/MTV. Вышеупомянутые паттерса реализуются путем начала создания отдельных файлов для моделей, контроллеров и представлений. Но то, что упускается из виду или забыто, в то время как процесс разработки должен сознательно использовать это разделение, чтобы решить, где ваш код должен быть написан. Другими словами, задавая вопрос – «Куда должна быть эта логика?» – Каждый раз, когда вы пишете кусок кода. Еще одна вещь, которую можно часто пропустить, чтобы остановиться после создания этих 3 файлов. Лучше, более чистая структура проекта может быть достигнута, имея дальнейшую классификацию записи логики (или созданных файлов).

def register_user(request):
    . . .
    user = User.objects.create(username=username,
        email=email,
        password=password,
        first_name=first_name,
        last_name=last_name)

    email_text = email_text.replace('#FIRST_NAME',user.first_name)

    notification = Noitification.objects.create(user=user,
       notification_type=SIGN_UP)
    notification.send(text=text)

Как вы можете видеть сверху, имея всю вашу операционную логику в пределах одной функции, даже если доказательство ошибок является плохой идеей. Одним из ключевых моментов преобразования новичком разработчика не попадает в ловушку мышления «Что не так с этим, это работает отлично». Более опытный разработчик положил бы его немного по-другому – «Это работает совершенно сейчас, но что может пойти не так», «другое использование разделения кода – это позволяет сухой код, т. Е. Если у нас есть метод/функция, которая имеет Наша логика аутентификации мы можем повторно использовать ее, не переписывая код везде.

Используйте шаблоны дизайна, где бы применимо .. делает код более читаемым и отключенным.

Шаблоны дизайна являются полезными инструментами при приближении к проблеме. Они помогают нам в размышлениях с точки зрения повторного использования, изоляции, рефакторимости и т. Д. В обычный день я обычно пишу свою логику поверх уже хорошо спроектированной структуры, которая имеет все правильные шаблоны, запеченные в. Но время от времени я столкнулся с проблемой, которая заставляет меня настроить предусмотренные предусмотренные решения. Это при помощи образцов дизайна. Использование их разумно, где бы ни был необходим/применимо, может чрезвычайно улучшать читаемость и ремонтность кода.

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

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

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

...

if payment.customer in discounted_customers:
    # custom flow for premium customers

if payment.get_pending_amount() > 0:
    # flow for handling pending payments
else:
    # usual flow 

...

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

# strategy.py
def get_customer_strategy(payment):
    if payment.customer.type == PREMIUM:
        return process_premium_customer
    return process_free_customer

def get_payment_strategy(payment):
    if payment.get_pending_amount() > 0:
        return remind_pending_amounts
    elif payment.get_pending_amount() == 0:
        return process_order

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

Найдите правильный баланс между обобщением и специализация сферы качества каждого аспекта API – когда сомневаетесь, оставьте это

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

def post(request):
    ...
    create_event(**data)
    create_attendee_types(**types)
    create_attendees(attendee_list)
    ...

Хорошим примером является создание родителей и записей детей из того же вызова API. Это приводит к неудачам, вызванным иметь слишком много зависимостей и может испортить состояние приложения.

Написание тестируемого кода.

Наконец-то тестирование также играет важную часть проектирования API. Хорошо написанный тестовый люкс может ловить дизайнерские лазейки и ошибки в начале процесса разработки и многое другое.

  • Помогает в регрессионном тестировании после каждого исправления ошибки, рефакториста или добавления.
  • Кристаллические требования – какой код ожидается?
  • Заставляет вас думать, действительно ли вы решили проблему.
  • Заставляет вас принимать лучшие дизайнерские решения.
  • Дает вам меру качества и прогресса.
  • Ловит жуков рано.
  • Помогает в передаче знаний.
  • Делает ваш код читабельным и простым в навигации.

Там нет секрета для написания тестов .. Есть только секреты для записи тестируемого кода. – Милко Хрели из Google

Написание тестируемого кода – это арт. Но, к счастью, написание тестируемых перекрытий кода с проектированием хороших API/программного обеспечения.

Оригинал: “https://dev.to/svemaraju/ramblings-on-refactoring-api-design-and-writing-testable-code-3pbp”