Типичный REST серевер на nodejs

wow-dog
Для человека уставшего от многословности, тяжеловестности и вязкости/неповоротливости существующих общепринятых платформ nodejs с coffeescript выглядит просто глотком свежего воздуха.

Динамическая типизация, милион библиотек на каждый чих, приятный python-подобный синтаксис, очень лаконичные конструкции – все это хорошо, пока проект не вырос до 10 строк кода. Дальше начинается болезненная организация кода. А для людей избалованной статической типизацией и fail-fast на определённом месте мир с розовыми пони превращается в ад, в котором если не протестировал каждую строчку – не мужик.

На текущем этапе для себя определил такую структуру:

nodejs-rest-server-stucture

Разумеется, в любом языке/технологии есть лучшие практики, но в моём случае nodejs местами на столько расслабляет, что хочется дать себе небольшую уступку в правилах, которые сам же себе определил. И это обычно больно наказывается в рантайме. В случае с динамическим языком – особенно больно.

Для себя я вывел несколько строгих правил, которые пока покрывают мои нужды уже в нескольких проектах. Некоторые читатели могут заметить, что это практически то, как делают проекты в java-мире, другие же напишут что это все чушь и так пишут только ламеры. И все будут правы, всем мир :)

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

  • Service. Верхний уровень доступа – занимается композицией результатов. Может обращатсья только к существующим DAO, не имеет права напрямую взаимодейтвовать с источниками данных. Имеет право обращаться к другим сервисам.

  • Route. В парадигме MVC это было бы контроллером. Инициирует работу с данными, может обращаться напрямую к DAO для простых операций, однако лучше стараться вызывать из Service.

DAO & Service обязуются не хранить внутренее состояние, за такое давно пора бить по рукам(на случай если вы ещё не начали)

Почему так?

Повторюсь, что писать на этом стеке очень легко. И ещё проще запутаться. Особенно мне. Выстраивание такое иерархии доступа к данным примерно может гарантировать спокойный сон иногда, если хорошо обложить тестами эти слои.

Тесты

Я ярый противник написания тестов ради тестов, горячий привет любителям TTD. Для меня есть два критерия когда стоит тратить на это своё драгоценное стартаперное время:

1) Тестирование блока кода руками занимает слишком много времени;
2) Блок является mission-critical для логики приложения;
3) Возникает неведомая фигня сложно воспроизводимая руками(дважды не получилось воспроизвести цепочку → keep calm and write tests)

Выделенные слои позволяют тестировать функциональность, а не то, как виртуальная машина складывает 2+2

Кэширование

К уровню DAO можно легко прикрутить кэш, где бы он не находился (а я надеюсь он не находится у вас где нить в отдельном рядом бегущем инстансе memcached/redis/etc). Мысли в слух: можно и к сервису, но чувсвтвую неладное


Очень интересна критика реальных программистов ну и диванные эксперты для наброса на вентилятор тоже приветствуются. Напомню, что все описанное выше делается для стартапов и наколенных прототипов – я ещё в здравом уме чтоб не писать нормальный продакшн на nodejs :D