[JavaScript, TypeScript, Анализ и проектирование систем, ООП, Проектирование и рефакторинг] Нерушимые законы крутого кода: Law of Demeter (с примерами на TypeScript)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Когда я узнал об этих принципах, качество моего кода выросла х2, а скорость принятия решения х5.
Если SOLID – это набор принципов написания качественного кода, то Law of Demeter (LoD) и Tell Don’t Ask (TDA) – это конкретные приемы как добиться SOLID.
Сегодня поговорим про Law of Demeter («Закон Деметры»).
Утрированно
Это принцип помогает определиться: «Как я буду получать / изменять вложенные объекты» – применим в языках, где можно определить «классы» со свойствами и методами.
Часто складывается ситуация, когда мы откуда-то (например, из HTTP запроса) получили id сущности `a`, пошли за ней в БД и из сущности `a` нам надо получить / изменить сущность `b` вызвав метод `Method`.
Так вот Википедия гласит:
Код `a.b.Method()` нарушает Закон Деметры, а код `a.Method()` является корректным.
Пример
У Пользователя есть Посты, в которых есть Комментарии. Вы хотите получить «Комментарии последнего Поста».
Можно запилить такую ересь:
const posts = user.posts
const lastPostComments = posts[posts.length-1].comments
Или вот такую (одного толку):
const userLastPostComments = user.getPosts().getLast().getComments()
Проблема: код, который вызывает это должен знать о всей иерархии вложенных данных.
Соответственно, если эта иерархия меняется / расширяется, везде, где был вызвана вот эта цепочка, придется вносить изменения (рефакторить код + тесты).
Чтобы решить проблему, применяем LOD:
const userLastPostComments = user.getLastPostComments()
А вот уже в `User` пишем:
class User {
// ...
getLastPostComments(): Comments {
const lastPost = this.posts.getLastPost()
return lastPost.getComments()
}
// ...
}
Та же самая история с добавлением комментария. Мы из:
const newComment = new Comment(req.body.postid, req.body.content)
user.getPosts().addComment(newComment)
Или, если вы хотите блеснуть 3-ей хромосомой:
const newComment = new Comment(req.body.postid, req.body.content)
const posts = user.posts
posts[posts.length-1].comments.push(newComment)
Превращаем вот в это:
const posts = user.addComment(req.body.postid, req.body.content)
А у `User`:
class User {
// ...
addComment(postId: string, content: string): void {
// The cleanest
const post = this.posts.getById(postId)
return post.addComment(content)
}
// ...
}
Уточнение: `new Comment` можно создать и вне `user` или `post`, все зависит от того, как устроена логика вашего приложения, но чем ближе к владельцу сущности (в данном случае, `post`), тем лучше.
Что это дает?
Мы скрываем детали реализации, и если когда-нибудь произойдет изменение / расширение иерархии (например, посты начнут лежать не только в свойстве `posts`) вам придется только отрефакторить метод `getLastPostComments` и переписать юнит-тест только этого метода.
В чем минусы
Много доп. кода.
В небольших проектах большая часть методов окажутся просто `getter` / `setter`.
Когда использовать
(1) Вы видите, что цепочки запросов внутрь сущностей становятся слишком длинными (более 3-х `.`)
(2) Код требует понятия: «Получить комментарии последнего поста» – а посты у вас не в 1-ом свойстве, а в 2-х и более, тогда, точно нужно делать метод `getLastPostComments` и уже там мерджить несколько свойств с разными постами.
(3) Я стараюсь максимально часто использовать этот принцип, когда речь идет о трансформации (изменение, создание, удаление) данных. И реже, когда речь о получении данных.
(4) Основываясь на здравом смысле.
Что для этого нужно
LOD хорошо работает в том случае, если у вас правильно сделано дерево / иерархия зависимостей сущностей.
Что почитать
(1) https://qna.habr.com/q/44822
Обязательно почитать все комментарии и комментарии комментариев (до коммента Вячеслав Голованов SLY_G), помня, что там и правильные и неправильные примеры
(2) https://ru.wikipedia.org/wiki/Закон_Деметры
(3) Статья
P.S.
Я мог напортачить с некоторыми деталями / примерами или объяснить недостаточно понятно, поэтому отпишитесь в комментарии что заметили, я внесу изменения. Всем добра.
===========
Источник:
habr.com
===========
Похожие новости:
- [Интервью, Проектирование и рефакторинг, Системное программирование, Управление проектами] И снова о Legacy. Вечная боль техдира
- [Laravel, PHP, Проектирование и рефакторинг] Подсистема событий как способ избавиться от задач по «допилу»
- [JavaScript, Тестирование веб-сервисов] Регрессионная спираль смерти (перевод)
- [Angular, JavaScript, Open source, TypeScript] Как писать хорошие библиотеки под Angular
- [Анализ и проектирование систем, Управление сообществом] Как внедрить геймификацию в профессиональное сообщество
- [IT-инфраструктура, IT-стандарты, Анализ и проектирование систем, Системное администрирование, Финансы в IT] Классификация критичности информационных систем
- [JavaScript] Формульный движок с обратной польской нотацией на JavaScript
- [JavaScript, Node.JS, Программирование, Разработка веб-сайтов] Руководство по Deno: примеры работы со средой выполнения TypeScript (перевод)
- [Solidity, Децентрализованные сети, Криптовалюты] Разбираемся с форматами токенов на Ethereum
- [Анализ и проектирование систем, Управление персоналом, Управление проектами] Опять отчет? Ну сколько можно?
Теги для поиска: #_javascript, #_typescript, #_analiz_i_proektirovanie_sistem (Анализ и проектирование систем), #_oop (ООП), #_proektirovanie_i_refaktoring (Проектирование и рефакторинг), #_typescript, #_oop (ооп), #_solid, #_lod, #_tda, #_javascript, #_typescript, #_analiz_i_proektirovanie_sistem (
Анализ и проектирование систем
), #_oop (
ООП
), #_proektirovanie_i_refaktoring (
Проектирование и рефакторинг
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 23:53
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Когда я узнал об этих принципах, качество моего кода выросла х2, а скорость принятия решения х5. Если SOLID – это набор принципов написания качественного кода, то Law of Demeter (LoD) и Tell Don’t Ask (TDA) – это конкретные приемы как добиться SOLID. Сегодня поговорим про Law of Demeter («Закон Деметры»). Утрированно Это принцип помогает определиться: «Как я буду получать / изменять вложенные объекты» – применим в языках, где можно определить «классы» со свойствами и методами. Часто складывается ситуация, когда мы откуда-то (например, из HTTP запроса) получили id сущности `a`, пошли за ней в БД и из сущности `a` нам надо получить / изменить сущность `b` вызвав метод `Method`. Так вот Википедия гласит: Код `a.b.Method()` нарушает Закон Деметры, а код `a.Method()` является корректным.
Пример У Пользователя есть Посты, в которых есть Комментарии. Вы хотите получить «Комментарии последнего Поста». Можно запилить такую ересь: const posts = user.posts
const lastPostComments = posts[posts.length-1].comments Или вот такую (одного толку): const userLastPostComments = user.getPosts().getLast().getComments()
Проблема: код, который вызывает это должен знать о всей иерархии вложенных данных. Соответственно, если эта иерархия меняется / расширяется, везде, где был вызвана вот эта цепочка, придется вносить изменения (рефакторить код + тесты). Чтобы решить проблему, применяем LOD: const userLastPostComments = user.getLastPostComments()
А вот уже в `User` пишем: class User {
// ... getLastPostComments(): Comments { const lastPost = this.posts.getLastPost() return lastPost.getComments() } // ... } Та же самая история с добавлением комментария. Мы из: const newComment = new Comment(req.body.postid, req.body.content)
user.getPosts().addComment(newComment) Или, если вы хотите блеснуть 3-ей хромосомой: const newComment = new Comment(req.body.postid, req.body.content)
const posts = user.posts posts[posts.length-1].comments.push(newComment) Превращаем вот в это: const posts = user.addComment(req.body.postid, req.body.content)
А у `User`: class User {
// ... addComment(postId: string, content: string): void { // The cleanest const post = this.posts.getById(postId) return post.addComment(content) } // ... } Уточнение: `new Comment` можно создать и вне `user` или `post`, все зависит от того, как устроена логика вашего приложения, но чем ближе к владельцу сущности (в данном случае, `post`), тем лучше. Что это дает? Мы скрываем детали реализации, и если когда-нибудь произойдет изменение / расширение иерархии (например, посты начнут лежать не только в свойстве `posts`) вам придется только отрефакторить метод `getLastPostComments` и переписать юнит-тест только этого метода. В чем минусы Много доп. кода. В небольших проектах большая часть методов окажутся просто `getter` / `setter`. Когда использовать (1) Вы видите, что цепочки запросов внутрь сущностей становятся слишком длинными (более 3-х `.`) (2) Код требует понятия: «Получить комментарии последнего поста» – а посты у вас не в 1-ом свойстве, а в 2-х и более, тогда, точно нужно делать метод `getLastPostComments` и уже там мерджить несколько свойств с разными постами. (3) Я стараюсь максимально часто использовать этот принцип, когда речь идет о трансформации (изменение, создание, удаление) данных. И реже, когда речь о получении данных. (4) Основываясь на здравом смысле. Что для этого нужно LOD хорошо работает в том случае, если у вас правильно сделано дерево / иерархия зависимостей сущностей. Что почитать (1) https://qna.habr.com/q/44822 Обязательно почитать все комментарии и комментарии комментариев (до коммента Вячеслав Голованов SLY_G), помня, что там и правильные и неправильные примеры (2) https://ru.wikipedia.org/wiki/Закон_Деметры (3) Статья P.S. Я мог напортачить с некоторыми деталями / примерами или объяснить недостаточно понятно, поэтому отпишитесь в комментарии что заметили, я внесу изменения. Всем добра. =========== Источник: habr.com =========== Похожие новости:
Анализ и проектирование систем ), #_oop ( ООП ), #_proektirovanie_i_refaktoring ( Проектирование и рефакторинг ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 23:53
Часовой пояс: UTC + 5