Статьи

Римские цифры, к повторному использованию

Некоторое время назад я начал заниматься ката римскими цифрами, проблема которого заключается в преобразовании из позиционного в непозиционное представление:

1 => I
2 => II
3 => III
4 => IV
5 => V
...

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

Основное решение

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

100 => C
90 => XC
50 => L
40 => XL
10 => X
9 => IX
5 => V
4 => IV
1 => I

Я мог бы начать с 1000 => M; эта серия поддерживает номера до 399.

При обсуждении моего решения ( слишком сложного ) в отношении классического возникли две вещи :

  • Я пошел в направлении удаления дубликатов, неукоснительно применяя одно из оставшихся правил простого дизайна. Я дошел до того, что смог сконфигурировать свой код только с символами I, V, X, L, C и их значениями вместо их вычитающей комбинации. Были еще некоторые большие предположения, которые необходимо учитывать, например магическое число 10, жестко закодированное в алгоритме.
  • Большинство классических решений для kata — это отдельные процедуры, которые как таковые не могут соблюдать принцип Open / Closed, когда требование изменяется или добавляется. Как и в случае ката для боулинга, вариации могут привести к взрыву краткого трехстрочного решения. Любое решение взрывается при рассмотрении требований, которые нарушают его предположения; в случае ката Боулинга есть много более жестко закодированных значений.

Итак, вчера я запустил git init. на новую папку, и я пошел в направлении повторного использования …

Этрусские цифры

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

Таким образом, одно дополнительное требование для ката — поддержка древней этрусской системы счисления, которая идентична римской, за исключением того факта, что символы отличаются:

1 => I
5 => ...
10 => ...

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

Создание настраиваемой субтрактивности

Когда существовала фактическая Римская империя, римские цифры еще не имели вычитающего правила. Правило было введено в средневековые времена, чтобы сократить обозначения. Итак, древнеримские цифры были написаны так:

4 => IIII
9 => VIIII
10 => XVIIII

Одно дополнительное требование для расширения ката — это также поддержка этой нотации; в объектно-ориентированном решении это обычно достигается путем настройки графа объекта по-разному. Я дошел до этой точки:

new RomanNumeralsSystem([ // supports the classic numerals
  new SubtractiveRule(),
  new AdditiveRule()
])
new RomanNumeralsSystem([ // supports the additive only case
  new AdditiveRule()
])

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

Еще больше вариаций

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

  • Что делать, если символы следуют за другой шкалой, такой как 1 => I, 5 => V, 20 => T вместо 1, 5, 10?
  • Что если символы могут быть вычтены более одного раза? Вы могли бы иметь такие номера, как IXL вместо XXXIX.
  • А как насчет другого направления конверсии? Насколько легко конвертировать XXXIX в 39?

Я экспериментировал с этими новыми требованиями, но пока не нашел хорошей реализации.

ретроспективный

Одна вещь, которую я узнал на Agile Days в этом году, это проведение небольшой ретроспективы после каждого учебного события, поэтому я решил применить это и к выполнению ката (7 Pomodoros должны быть хорошо потрачены). Просто потратьте несколько минут на изучение `git log` и проблем, с которыми вы столкнулись, чтобы увидеть, есть ли недостатки, которые вам нужно исследовать (вам нужно часто совершать коммиты, чтобы это работало).
Некоторые выводы, которые я получил из своего анализа:

  • Существует напряженность между ранним извлечением объектов (что вынуждает вас разлагать проблему и дает возможность получать отзывы о модульных тестах для этих объектов) и ожиданием, пока вы не узнаете больше о проблеме (что позволяет легче реорганизовать обязанности между объектами). ; но это может быть афера .)
  • Вы можете быть более точным, но мои оценки на уровне Pomodoro при выполнении ката легко в 2 раза.
  • Я не выбрал дизайн, но сразу выбрал один. Я должен убедиться, что оценил по крайней мере три различных варианта, прежде чем приступить к реализации всего этого, или изложил ограничения в начале ката.
  • Иногда больше рефакторинга не делает код лучше. Я должен начать создавать временные рамки для улучшения и выбросить код, если он не улучшился в конце выделенного времени, — предложение, которое я подобрал на курсе.