All streams
Search
Write a publication
Pull to refresh
10
0
Сергей Клевакин @Justerest

User

Send message
Тогда перефразирую)

некоторые разработчики, наивно полагают, что они могут сразу `function isCandy(value: DirtyApiResponse): value is Candy` и погнали
ну… примерно так. Я перестал возлагать много надежд на автоматизацию этих преобразований.
Вот схема из одного проекта, как у меня данные преобразуются и где ошибки ловятся:

DirtyApiResponse -> CandyParams -> CandyFactory -> Candy.

1) DirtyApiResponse -> CandyParams — это преобразование делает маппер (о котором я выше говорю): могут меняться названия полей, вложенность, простые преобразования строки в дату и т.п. Маппер гарантирует, что на выходе получится CandyParams.

2) CandyParams -> CandyFactory — хоть параметры и соответствуют интерфейсу, но внутри могут оказаться логические несостыковки. Эту валидацию более высокого уровня проводит CandyFactory.

Это не эталонная схема, просто пример. Но как видно, библиотеки типа quartet, наивно полагают, что они могут сразу преобразовать DirtyApiResponse в Candy, проведя все валидации. В результате, вы напрямую зависите от DirtyApiResponse, и подстраиваете свою модель под него. И наоборот, использование библиотеки для преобразования DirtyApiResponse в CandyParams часто является оверхедом. Вот таким образом я и пришёл к тому, что маплю всё руками. Немного рутины, но зато видно все соответствия/несоответствия на границе фронт/апи.
тип А — это что-то вроде Partial of ApiModel (в идеале unknown, но решаете по мере необходимости). И внутри маппера вы проводите преобразования, дефолтные значения подставляете (можете и ошибки бросать, если надо).

Да, конечно, маппер меняется. Но я под маппером подразумеваю функцию (две функции), которая тип А преобразует в тип Б. Но это вполне себе ограждение.

Сам писал нечто похожее с классами и декораторами, как и большинство комментаторов. Но ушел от этого.


Оказывается, апи и фронт, это разные контексты (удивительно). И вам не стоит заворачивать за общие модели. Несмотря на то, что мы используем сваггер, на границе фронт/апи я сейчас стараюсь использовать мапперы, написанные руками (что-то вроде карт контекстов из ДДД). Таким образом вы ограждаетете себя от изменений моделей апи. И наоборот, даёте себе свободу в изменениях. И споров между фронтом и бэком меньше.

Спасибо за ссылочки!

Спасибо автору! Я тоже считаю, что с фронтом что-то не так. Что-то не так в голове.


Но мне кажется, проблема современного фронта в странном восприятии проблемы "состояния". Мы почему-то хотим им управлять, подходы придумываем. Вот вы предложили отделять "состояние" от "знания". А разве это не основная идея сокрытия данных (инкапсуляции)? То есть, обеспечив инкапсуляцию, мы могли бы избавиться от любых мыслей про состояние, и от проблем связанных с ним.

"Мы уже научились разделять представление и остальное приложение, и мы знаем, как это делать правильно."
Серьезное заявление.

Это достойные причины для return. Я сказал "лучше", подразумевая идеальный случай, когда нет причин для досрочного выхода.


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

Тип void в typescript имеет смысл, если участники проекта понимают разницу между функцией и процедурой, и помечают возвращаемый тип процедур как makeCoffee(): void. И директиву return в процедуре лучше не писать в принципе. Это и есть отсутствие возвращаемого значения. То что undefined эквивалентен void допущение typescript, о котором пару слов говорится в документации.


Противоположностью для типа any является тип unknown (а не void).

Information

Rating
Does not participate
Location
Екатеринбург, Свердловская обл., Россия
Date of birth
Registered
Activity