Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Подарки от программис'тов

6208   6 7 8 9 10 11 12 13 14 15 16 все
MrSanders коренной житель04.08.22 21:19
NEW 04.08.22 21:19 
в ответ alex445 04.08.22 15:54

Допотопное и самописное. Появилось примерно в одно время с хибернейтом, может года с 2002-2003, потом проект свернули. В проекте, в котором я это видел, заменять ни на что не стали, а купили права, и потом 10 лет допиливали его сами. Уже и как называлось не вспомню.

alex445 коренной житель05.08.22 01:58
NEW 05.08.22 01:58 
в ответ alex445 03.08.22 21:48, Последний раз изменено 05.08.22 02:41 (alex445)
Кто-нибудь встречал такой кейс, что базовые типы, типа строк, чисел, булевых и прочих (но не все) переписаны, в них добавлена встроенная валидация, способность определять, можно ли их отрисовывать (на основе встроенной авторизации и аутентификации), присутствуют состояния и сообщения об ошибках (т.е. в "базовых" типах заведена куча полей, логики, они сами из себя представляют лютую иерархию наследования)? И все остальные модели строятся на этих кастомным "базовых" типах.

Щас ещё глянул - как я писал, эти базовые типы наследуются от другого базового, у которого есть уникальный идентификатор GUID. И от этого базового наследуются вообще все типы - и строки, числа, булевы и т.п. данные, и всякие более высокоуровневые, типа меню, таблиц, отдельных строк таблиц, форм. При этом форма может состоять из строк и чисел, но все они наследуются от одного базового типа с полем уникального идентификатора. Т.е. получается, что все элементы и данные в приложении имеют зачем-то свой GUID.


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


По-моему, в проекте нарушены потоки управления. Вместо привычного, скажем, "форма залогинивания или объект пользователя управляет видимостью своих полей, проводит их валидацию и показывает ошибки", существует какой-то дикий треш, в котором каждый сам собой управляет, валидируется и предоставляет сообщения об ошибках. Это вообще ООП или что? Где инкапсуляция, где границы ответственности данных и объектов? Такое ощущение, что все данные всех объектов отделены от них и представляют из себя огромную кучу из атомарных данных со своими идентификаторами и встроенной независимой функциональностью. При этом они всё же объединены в формы и объекты, но типа для вида - всё равно эти формы и объекты ими не управляют.


Делали явно не от мира сего. Мне трудно представить себе какой-то уникальный процесс на фабрике в реальном мире, который бы моделировался подобной конструкцией. Нахрена иметь абсолютно уникальные айдишники для абсолютно всех данных, которые существуют, скажем, лишь на протяжении одной сессии? И всё это дерьмо ещё и логируется через каждые 3-5 строчек кода. Ну и что даст чтение логов через месяц, где будет отображено, что данное с айди таким-то при обработке в форме с айди таким-то получило ошибочные данные с айди таким-то? Я же не смогу воссоздать эту ситуацию и продебажить её - айди же каждый раз разные, даже для одинаковых данных.

alex445 коренной житель05.08.22 02:37
NEW 05.08.22 02:37 
в ответ alex445 05.08.22 01:58, Последний раз изменено 05.08.22 02:45 (alex445)

Ну и вишенка - этот GUID существует в базовом классе в виде... строки! При инициализации создаётся новый идентификатор через Guid.NewGuid(), что возвращает структуру типа Guid, и тут же переводится в строку через ToString. Т.е. не по месту где надо конвертиться в строку, а изначально гуляет по приложению в виде строки. Ну и потом ещё с ним манипуляции проводят, типа дополняют эту строку разными символами. Т.е. это уже не Guid, а хрень собачья - назад в Guid не сконвертишь. Но есть финт ушами - в одном месте есть метод GetUID, который проверяет строку на магическое число 36 (всё без комментариев, напомню). И если строка больше 36, то метод берёт подстроку в 36 символов.


Правда, нашёл ещё метод, который конкатинирует эти GUIDы в одну строку. Там создаётся локальная переменная szId и ей присваивается результат конкатенации. В принципе, пофиг, т.к. переменная существует лишь в этом методе, и можно назвать её хоть "абракадабра", и за пределами этого метода можно об этой бессмысленной переменной забыть. Но мне просто интересно, что может означать название "szId"? Комментов нигде ни строчки нет. Там человек ещё местами вкорячивает вперемешку немецкий с английским в названиях переменных. Но вот просто любопытно - если сконкатинировать два гуида, то почему получается szId?

alex445 коренной житель05.08.22 03:33
NEW 05.08.22 03:33 
в ответ alex445 05.08.22 02:37

Они там постоянно говорят о каких-то Unikat. Но это явно какие-то отдельные вещи, типа поступлений на склад или движения объектов по фабрике. Но не отдельный уникат на каждое свойство каждого объекта в каждой сессии. Надо расспросить получше, но последний вариант с уникатами на всё и вся - явно чушь.

alex445 коренной житель05.08.22 12:36
NEW 05.08.22 12:36 
в ответ alex445 05.08.22 02:37, Последний раз изменено 05.08.22 12:42 (alex445)

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

AlexNek патриот05.08.22 17:37
AlexNek
NEW 05.08.22 17:37 
в ответ alex445 05.08.22 01:58
В этот самый базовый тип встроена логика по аутентификации и правам

видимо ради этого всё и затевалось. Чтобы автоматом показывалось только то что можно пользователю.

alex445 коренной житель08.08.22 14:49
NEW 08.08.22 14:49 
в ответ AlexNek 05.08.22 17:37, Последний раз изменено 08.08.22 15:24 (alex445)

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


"введённое расположение не найдено"

"расположение не найдено"

"введённое вами расположение отсутствует в базе данных"

"такого расположения не существует"


Но все эти сообщения находятся под разными ключами, т.к. формат ключа "имяФормы_ещёМногоРазныхУсловныхОбозначений_ключСообщения". То, что в разных формах одна и та же обработка и одни и те же сообщения об ошибках должны быть - создатели такой архитектуры, похоже, не предусмотрели.


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

alex445 коренной житель08.08.22 14:53
NEW 08.08.22 14:53 
в ответ alex445 08.08.22 14:49, Последний раз изменено 08.08.22 14:54 (alex445)

Ну а вообще - бывает, что одна и та же сущность в разных случаях должна валидироваться по-разному? Как тогда?


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


Entity Location (location validation)


ViewModel LocationInLocationForm (location in location form validation)

ViewModel LocationInOrderForm (location in order form validation)

and so on...

AlexNek патриот08.08.22 18:18
AlexNek
NEW 08.08.22 18:18 
в ответ alex445 08.08.22 14:53
... А потом при отправке в БД согласовать их валидацию с валидацией в ORM. Правильно?

А есть море примеров где это нужно? Хотя придумать можно.

То есть однозначно сказать нельзя. Думаю, в большинстве случаев это не нужно. Например, возраст/год рождения.

AlexNek патриот08.08.22 18:20
AlexNek
NEW 08.08.22 18:20 
в ответ alex445 08.08.22 14:49
В этом проекте "гениальность" архитектуры соперничает

Видимо не один писал. Вначале чисто для себя, как думалось что клиент захочет. А после каждый дорабатывал как действительно надо.

alex445 коренной житель09.08.22 13:56
NEW 09.08.22 13:56 
в ответ AlexNek 08.08.22 18:20, Последний раз изменено 09.08.22 14:02 (alex445)

В одном месте встречаю проверку строки на целое число в методе IsInteger через Double.TryParse.

Через 10 строчек кода, в этом же методе эта же строка конвертится через Int.Parse.


В методе IsInteger после вызова Double.TryParse распарсенный результат проверяется на <=long.MaxValue и >=long.MinValue. Зачем? Вероятность ввода строки "NaN" явно исключена.


В одном методе при конвертации строки в число используется параметр культуры.

В перегрузке этого метода, не использующей параметр культуры, в комменте написано, что эта перегрузка использует актуальную культуру. А в коде тут же вызывается первая перегрузка с захардкоденным параметров "en-US".


Окончательно убедился в "гениальности" данного проекта.

alex445 коренной житель09.08.22 14:57
NEW 09.08.22 14:57 
в ответ alex445 09.08.22 13:56

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


Оцените подход. В проекте используются везде контролы, принимающие лишь строки. Хотя вводить в некоторые поля нужно и числа. Что делают авторы этого проекта? - В каждой форме пишут однотипный код по проверке введённой строки и показывании статуса - типа "поле не должно быть пустым", "введённое значение - не число" и т.п. Хорошо хоть методы парсинга строк в числа вынесли в переиспользуемый код. Но вот эти обработки со статусами - в каждой форме. На эти статусные сообщения - словарик ресурсов с локализацией.


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

AlexNek патриот09.08.22 17:41
AlexNek
NEW 09.08.22 17:41 
в ответ alex445 09.08.22 13:56
Double.TryParse распарсенный результат проверяется на <=long.MaxValue и >=long.MinValue. Зачем?

по определению

public const double MaxValue = 1.7976931348623157E+308;


public const long MaxValue = 9223372036854775807;
alex445 коренной житель09.08.22 21:13
NEW 09.08.22 21:13 
в ответ AlexNek 09.08.22 17:41, Последний раз изменено 09.08.22 21:25 (alex445)

И? Я логику всё равно не понимаю. Ну парси тогда лонг сразу?

Дальше-то оно всё равно через обычный int парсится. Программист в десяти строчках кода не может решить, с каким типом он работает - три разных использует.


С другой стороны, я когда на эту всю вакханалию смотрю, то тоже не охота ничего особо править. У меня задача - перевести на новый интерфейс. Тупо беру и копирую код. Там и так править много, чтобы под новую версию фреймворка подогнать, так что исправлять ещё и косяки и странности остального кода, до кучи вникая, зачем это и почему было сделано, и не порушит ли что другое - нет ни времени, ни желания особого. Но вот такие штуки просто в глаза бросаются. Думаешь про себя - да хер с ним, раньше же как-то у них много лет работало, значит и сейчас как-то будет работать, если я просто скопирую. Мне постоянно напоминают, мол "клиент этого не заказывал, того не заказывал" - т.е. времени править все грехи всех предыдущих погромистов нет, и за это не заплатят. Но из-за этого иногда приходится вкорячивать костыли, чтобы обойти костыли предыдущих бедолаг. Вот так код и приходит в совершенную негодность и "проще выкинуть" через несколько таких итераций "да нам по-быстрому, лишь бы на новых версиях железа/ПО заработало". У заказчика только одна претензия к этому ону мамонта - не работает нормально в новых браузерах, а только в ИЕ. Работало бы в новых - они до сих пор сидели бы на попе ровно с этим кодом 15-20-летней давности, который никуда не масштабируется и к которому прилагаются старинные PDA с Вин Мобайл на борту и специальным гуём, вместо единообразной адаптивной вёрстки десктоп/мобилы.

AlexNek патриот09.08.22 21:26
AlexNek
NEW 09.08.22 21:26 
в ответ alex445 09.08.22 21:13
Я логику всё равно не понимаю. Ну парси тогда лонг сразу?

Если вводятся только строки, то скорее всего ориентация идет на double, как базовый тип.


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

alex445 коренной житель09.08.22 21:27
NEW 09.08.22 21:27 
в ответ AlexNek 09.08.22 21:26, Последний раз изменено 09.08.22 21:27 (alex445)

Главное, в конце всё равно распарсивается как обычный инт32 и получившееся идёт в обработку. ))

Ну вот про это - не заморачиваться - я и написал выше. ))

MrSanders коренной житель10.08.22 09:49
NEW 10.08.22 09:49 
в ответ AlexNek 09.08.22 21:26
Совершенно не следует понимать, почему так сделано

Я-я, натюрлихь! Тафай-тафай, прокраммируй, не задумывайся, блин. Самый отвратительный совет, который только можно дать.

Прям 1 в 1 мои коболисты. А чо, работает же? А то что ты уже за эти полгода пятый раз ошибки правишь в этом куске кода, ничерта не понимая, добавляя очередной if-else ни на какие мысли не наводит, нет. Главное быстро тикет сделать.

AlexNek патриот10.08.22 13:00
AlexNek
NEW 10.08.22 13:00 
в ответ MrSanders 10.08.22 09:49
Тафай-тафай, прокраммируй, не задумывайся, блин

Похоже мы смотрим в разные стороны. Имелось в виду совершенно другое.

Понять как "правильно" делать - это вроде как само собой разумеется. То, что у всех может быть разное мнение по этому поводу - вопрос дополнительной дискуссии.

alex445 коренной житель10.08.22 13:17
NEW 10.08.22 13:17 
в ответ AlexNek 10.08.22 13:00
Похоже мы смотрим в разные стороны.

"Живём на разных островах" же! ))

alex445 коренной житель16.08.22 18:20
NEW 16.08.22 18:20 
в ответ alex445 10.08.22 13:17, Последний раз изменено 16.08.22 18:23 (alex445)

Встретил такое


свойство


public bool HasFocus

get

internal set


метод


public void SetFocus


Нафига, чтобы прочитать свойство, нужно обратить себя к свойству, а чтобы установить его - к специальному методу?


Разная логика при установке свойства? Типа есть логика внешняя для пользователя класса, и внутренняя - для своего внутреннего фреймворка? Ну так сделай, чтобы пользователю было удобно и он с твоими свойствами работал привычно, а не через задницу. А сам внутри своего фреймворка можешь через задницу устанавливать свои свойства.

6 7 8 9 10 11 12 13 14 15 16 все