x
 
Федор Борщев
17 октября 2019
Советы почтой каждую неделю
Пожалуйста, получите наше письмо, чтобы подтвердить свой адрес:
Вы подписаны на «Советы за неделю»:

Как следить за качеством кода? Часть вторая: метрики


Качество кода

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

Качество кода

Цикломатическая сложность

Цик­ло­ма­ти­че­ская слож­ность — это коли­че­ство воз­мож­ных путей, кото­рые интер­пре­та­тор про­хо­дит через один блок кода. Вот, смотрите:

def charge(user):
  subscription = user.subscriptions.last()
  bank = Bank(user)
  if bank.charge(subscription.cost):
    subscription.prolong()

Внутри функ­ции charge() всего два пути: если полу­чи­лось снять деньги с поль­зо­ва­теля, то под­писка про­для­ется, если не полу­чи­лось — ничего не происходит.

Навер­няка во время про­дле­ния под­писки мы уве­дом­ляем поль­зо­ва­теля и мене­джера об успеш­ной опе­ра­ции, авто­ма­ти­че­ски создаём новую под­писку в слу­чае, если её ещё нет, обнов­ляем дату сле­ду­ю­щего про­дле­ния. В при­мере выше всё это попря­тано по отдель­ным местам — в методе под­писки prolong() или вообще вне функ­ции charge(). Смот­рите, что будет, если это не прятать:

def charge(user):
  if user.subscriptions.count():
    subscription = user.subscriptions.last()
    order = Order.objects.create(user=user, subscription=subscription, created=datetime.now())

    response = requests.post('https://bank.api/init', dict(
      amount=subscription.cost * 100,
      order_id=order.id,
    ))
    if response['OK'] is True:
      payment_id = response['payment_id']
      new_response = requests.post('https://bank,api/charge', dict(payment_id=payment_id))

      if new_response['OK'] is False:
        requests.post('htps://api.slack.com', {
          'to': '#money',
          'message': f'Не уда­лось опла­тить под­писку поль­зо­ва­теля {user}',
        })

      else:
        subscription.due_date = datetime.now() + timedelta(month=1)
        subscription.save()

  else:
    Subscription.objects.create(user=user)
    charge(user)

В этом при­мере 6 воз­мож­ных путей. Это уже мно­го­вато — алго­ритм вос­при­ни­ма­ется с тру­дом, если воз­мож­ных путей в нём больше 4.

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

Процент покрытия тестами

CI (Continous Integration) — процесс непрерывной сборки и проверки программы. Рассмотрим его подробно в следующем совете

Вто­рая важ­ная мет­рика — это про­цент кода, покры­того тестами. Ска­жем, если ваша про­грамма покрыта на 90% — зна­чит, в про­цессе про­гона тестов в CI вы задей­ству­ете 90% из всего напи­сан­ного кода. Ско­рее всего, это озна­чает, что 90% вашего кода рабо­тает так, как заду­мал про­грам­мист. 90% — непло­хой уро­вень покры­тия, 80% и ниже — сиг­нал, что что‑то идёт не так.

CI (Continous Integration) — процесс непрерывной сборки и проверки программы. Рассмотрим его подробно в следующем совете
Сер­вис Codecov под­све­чи­вает непро­те­сти­ро­ван­ную строчку

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

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

Время ответа и частота ошибок

Эти мет­рики пока­зы­вают не совсем каче­ство кода, а ско­рее каче­ство работы про­грамм­ного обес­пе­че­ния в про­дак­шене. Обычно частота оши­бок и время ответа рас­тут очень мед­ленно, по мере услож­не­ния про­граммы. Если у вас резко выросла одна из этих мет­рик — это сиг­на­ли­зи­рует, что только что в вашу кодо­вую базу при­внесли серьёз­ное ухудшение.

Экран мони­то­ринга про­из­во­ди­тель­но­сти в Datadog: видны гра­фики вре­мени ответа и оши­бок

Для сня­тия этих мет­рик под­хо­дит мно­же­ство инстру­мен­тов. Мы в «Где­ма­те­ри­але» исполь­зуем Datadog в связке с Sentry. Datadog изме­ряет частоту оши­бок и время ответа, а Sentry помо­гает с рас­сле­до­ва­нием, пока­зы­вая состо­я­ние при­ло­же­ния во время ошибок.

Добавьте свою метрику

Суще­ствует мно­же­ство более спе­ци­фич­ных мет­рик — коли­че­ство и длина строк, время сборки, коли­че­ство ком­ми­тов на один файл, раз­мер гото­вого образа. Чем больше вы сни­ма­ете мет­рик и чем больше огра­ни­че­ний на их зна­че­ния ста­вите — тем здо­ро­вее ваш проект.

P. S. Это был совет об управлении разработкой. Хотите больше знать о планировании спринтов, управлении продуктом или о настройке инфраструктуры? Присылайте вопросы.

Поделиться
Отправить

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

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

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

Вот такой веб 2.0.

Как следить за качеством кода? Часть третья: процессы 3 Как следить за качеством кода? Часть первая: зачем Несколько месяцев назад меня повысили из обычного разработчика до «тимлида» 1 Как правильно, эффективно и уважительно ставить KPI?




Недавно всплыло

2 Хочу научиться сторителлингу 12 10 дизайнерских товаров японских студий 2 2