Как эффективно управлять базой кода Clojure? - PullRequest
22 голосов
/ 18 октября 2011

Коллега и я - новички Clojure.Мы запустили проект пару месяцев назад, но быстро обнаружили, что нам сложно работать с нашей кодовой базой - к 500 LOC мы практически не знали, с чего начать с отладки, когда что-то пошло не так (что было часто).Вместо пар функции получали списки, или числа, или что-то еще.

Теперь мы начинаем новый, но связанный проект и переносим старый код.Но мы снова попали в стену.

Нам интересно, как нам эффективно управлять проектом Clojure, особенно когда мы вносим изменения в существующий код?

Что мы придумали:

  • свободное использование юнит-тестов
  • свободное использование предварительных, постусловий
  • неформальные объявления типов в комментариях к функциям
  • use defrecord /defstruct / defprotocol для реализации модели данных, которая действительно упростит тестирование

Но предварительные условия, по-видимому, используются не очень часто.Юнит-тестирование + комментарии только очень помогут.И похоже, что программисты Clojure обычно не реализуют формальные модели данных.

Разве мы не получаем Clojure? Как программисты Clojure знают, что их код является надежным и правильным?

Ответы [ 3 ]

9 голосов
/ 19 октября 2011

Я думаю, что это на самом деле развивающаяся область - Clojure на самом деле недостаточно давно для разработки всех лучших практик и связанных с ними инструментов для управления большой базой кода.

Некоторые предложения из моего опыта:

  • Структурируйте ваш код «снизу вверх» - в общем, способ, которым вы хотите структурировать свой код, будет иметь «служебный» код вверху файла (или импортированный из другого пространства имен) и код «бизнес-логики», который использует эти служебные функции в конце файла. Если это кажется трудным сделать, то, вероятно, намек на то, что ваш код нуждается в некотором рефакторинге.

  • Тестирование в качестве примеров - Тестовый код в clojure очень хорошо работает как для проверки вашего кода, так и для документации (например, «какой параметр ожидает эта функция?»). Если вы обнаружили ошибку, обратитесь к тестам, чтобы проверить свои предположения, и напишите пару новых тестов, чтобы выяснить, что идет не так.

  • Сохраняйте функции простыми и составляйте их - своего рода расширение " принципа единственной ответственности " для функционального программирования. Я рассматриваю более 5-10 строк в функции Clojure как основной запах кода (если это кажется экстремальным, просто помните, что вы, вероятно, можете достичь в 5-10 строк Clojure столько же, сколько вы могли бы с 50-100 строками Java / C #)

  • Остерегайтесь «императивных привычек» - когда я впервые начал использовать Clojure, я написал много псевдо-императивного кода в Clojure. Примером может быть эмуляция цикла for с «dotimes» и накопление некоторого результата внутри атома. Это может быть больно - это не идиоматично, это сбивает с толку, и обычно есть гораздо более умный, простой и менее подверженный ошибкам функциональный способ сделать это. Это требует практики, но в конечном итоге это того стоит ...

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

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

9 голосов
/ 19 октября 2011

простые составные абстракции

«Лучше иметь 100 функций, работающих с одной структурой данных, чем 10 функций, работающих с 10 структурами данных».- Алан Дж. Перлис

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

DRY, Серьезно, просто не повторяйте себя

начиная с хорошо разложенных функций в куче пространств имен;каждый раз, когда мне нужна одна из составных частей где-то еще, я «поднимаю» функцию, которая функционирует до библиотеки, включенной в оба пространства имен.Таким образом, ваши часто используемые абстракции эволюционируют в ходе проекта в «просто достаточную структуру».Это очень трудно сделать, если у вас нет действительно составных абстракций.

1 голос
/ 19 февраля 2014

Извините, что выкопал этот старый вопрос, ответы Микеры и Артура превосходны, но я тоже удивился этому, изучая Clojure, и подумал, что упомяну, как мы организуем файлы. *

Аналогично тому, как каждая функция выполняет одно задание, мы группируем связанные функции в пространства имен, чтобы упростить навигацию по коду. Таким образом, у нас может быть пространство имен для функций, обеспечивающих доступ к конкретной базе данных или предоставляющих набор утилит, связанных с HTTP. Это делает каждый файл относительно небольшим и облегчает поиск тестов. Это также делает рефакторинг намного проще. В этом нет ничего нового, но стоит иметь в виду.

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