Все началось как вызов. Успейте сделать это до понедельника как можно лучше. Я поставил цель провести один продуктивный день на этой задаче. Это означает ~ 6 часов кодирования, чтобы сделать все это, так как всегда есть более важные дела, чем развлечения.
Большую часть времени я думал о простоте и дизайне программ на Ruby, и это основная тема того, что вы собираетесь прочитать. Я решил написать об этом в блоге, так как мне очень нравится разработка Ruby, и, вероятно, из-за предстоящего eruko2016.org, вдохновившего меня поделиться некоторыми причинами, по которым я люблю Ruby. Вернемся к правилам игры.
Короче говоря: создайте CLI-редактор изображений.
— Пиксель изображения представлен символом в верхнем регистре.
— Пользователь должен иметь возможность рисовать другим цветом (скажем, символом) с заданными координатами x и y.
— Пользователь должен иметь возможность рисовать линии по вертикали и горизонтали слева направо и справа налево
— Изображение должно отображаться/отрисовываться в консоли
06:00 Планирование
Простота, удобочитаемость и расширяемость. Это были мои приоритеты. Держать его просто глупо.
Я действительно не хотел переусердствовать. Излишняя инженерия так же плоха, как непроверенный или недокументированный код. Сложность может отпугнуть разработчиков от рефакторинга и даже чтения такого кода быстрее, чем можно было бы подумать.
Итак, я начал со списка того, что нам определенно нужно. Я решил не добавлять ни строчки кода, если в этом нет необходимости.
- Для программы с интерфейсом командной строки нам определенно нужен «клиент» CLI, который обрабатывает ввод-вывод.
- Модель изображения, содержащая пиксели, представленные символами. 2D-массив? Матрица?
- Четкий способ редактирования изображения и добавления новых функций. (Нужно ли нам хранить историю?)
- Интерфейс рендерера с базовым консольным рендерером, который можно легко заменить на тот, который выводит в файл.
05:30 Нейминг
Это всегда самая важная часть. Никогда не недооценивайте.
05:29 Реализация
app/ |_edit.rb # module that holds all edit actions |_cli.rb # class to handle user input |_image.rb # somethin to represent image |_renderer.rb # renders image in console runner.rb # runs the whole party
Все работает, пара спецификаций покрывает это, и базовая структура выглядит правильно, верно?
03:30 Нет.
После того, как я создал и протестировал изображение, средство визуализации и базовый интерфейс командной строки, пришло время заняться реальным делом. Редактирование. Цель состояла в том, чтобы сохранить его легко обширным. Напишите 1 или 2 коротких метода, если хотите добавить новый инструмент.
Несмотря на то, что он оставался базовым с изображением и средством визуализации, он, безусловно, содержал код в чистоте (массив 2d, содержащий пиксели), кажется, что редактирование изображения не требует ввода, и edit.rb быстро вырос до более чем сотни loc, что является умственным барьер для меня. Пришлось разделить.
app/ |_edit/ |_base.rb # initialize(@image); |_clear.rb # exec(params) |_dot.rb # exec(params) |_vertical_line.rb # exec(params) |_horizontal_line.rb # exec(params) cli.rb: Edit::Clear.new(@image).exec # seems legit
03:27:56.8
Конечно, это решение мне нравилось целых 3,2 секунды, пока в голове не закипели все остальные варианты.
Эй, если вы хотите произвести впечатление на всех, загрузите эти команды редактирования во время выполнения!
О боже, о боже!
Должен ли я перечислить их в .yml, чтобы команды имели описания и
все автоматически считывались во время выполнения??
Нет, нет, даже лучше! DSL из редактора, чтобы каждый мог писать свои редакторы, используя «язык», который отличается от руби, скорее всего, в негативном смысле, но они будут любить вас!
Придерживайтесь своего плана. Упростите это. Не усложняйте. Следует задавать такие вопросы, как «Нам это нужно?», «Нам это когда-нибудь понадобится?», «Как мы можем справиться с ситуацией тогда, если мы не сделаем этого сейчас?». Если вы сомневаетесь, всегда задавайте их в этой последовательности. Просто не позволяйте себе думать слишком далеко без причины. Тик-так. Код.
01:00 Брейн, ты рад, что я ничего этого не делал?
Я придерживался своего основного первоначального решения. Все просто работает. Никаких хаков, никаких умопомрачительных джунглей объектов. Меню всего пять, когда дела в цикле? Делает работу на данный момент. Не сексуально, но все же достаточно хорошо. Когда (если) он растет, это нужно изменить на какой-то интерпретатор. Упаковать в драгоценный камень? Ставить КИ? Думаю, вы поняли. Это легкие части, и их всегда можно сделать позже. Тратьте время с умом и производите меньше.
После того, как структура прототипа заработает, не пытайтесь сделать ее более причудливой. Как раз наоборот — постарайтесь сделать его проще. Сделать ваш код приятным для чтения и понимания чаще всего можно, удалив треть его, а не добавляя больше.
Как всегда, правильное тестирование (имеется в виду последние 10%) займет большую часть времени, но даже с несколькими крайними сценариями мы можем покрыть 90% логики. Метод делает что-то необычное? Специфицируйте это! В противном случае не утруждайте себя тестированием рубиновых структур и методов.
00:10 Заканчиваем. Я всегда хотел…
… строки юникода должны обрабатываться одинаково! Я решил, что последний час я потрачу на какую-нибудь крутизну, например, на Ruby 2.40, а также на поддержку
"мария".upcase() # out of the box. Mind blown.
Заворачивать.
00:00. git push
Мне понравилось, как концентрация на достижении простой цели простым способом дает чистый и удобный код. Если я чему-то и научился, так это тому, чтовключайте инструмент только тогда, когда обходной путь сложнее, чем просто его использование.
Я считаю, что при работе над короткими, но концентрированными фрагментами, а не в течение нескольких дней, люди склонны не упускать из виду цель, знать, что необходимо сделать, и видеть более конкретные решения. И это то, что касается кодирования с помощью ruby. Это весело.
Начинается неделя рубинового чуда. ❤ или подпишитесь, чтобы узнать больше.