Pull to refresh
4
0

Уверенный пользователь холодильника

Send message

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

Чистая, после trunc. Потом тестом (мы же тесты пишем?) туда добавляется два пользователя, и у каждого по картинке. Ну так как у нас ID там в обоих случаях 1 и 2, и пользователю 1 принадлежит картинка 1, то сами догадаетесь, как именно перепутанные аргументы могут пройти через сито и оказаться в проде?

нужен всего один класс на N количество разных типов.

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

как вы это поняли?

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

в данном случае еще метод ToOneUnit() поправить в том же классе и все

Нет, не всё. Ещё по уму нужна будет конвертация из OneUnit во все оставшиеся. Но тут как раз прояснилась интересная деталь - почему-то вы думаете, будто я зачем-то предлагал на каждую новую единицу измерения длины делать новый класс. Хотя я неоднократно уже говорил, что ничего подобного не было.

что за приложение и как делают его отладку?

Пусть это будет микросервис на C++, с покрытием тестами на уровне порядка 60% ветвлений (для виденных мной проектов - цифра космическая, на самом деле). Ну или на Scala, с теми же характеристиками. Отладка, как водится, ручками через дебаггер.

Что происходит в «современных IDE» с кодом на перле, руби, питоне, джаваскрипте?

Точно помню, что Eclipse и плагин JSDT, земля ему пухом, при написании кода иногда всё-таки показывали очевидные ошибки, которые на таком уровне были ему доступны. Сейчас там плагин WWD, и последний раз как я им пользовался, там не работали даже хоткеи для комментов, плевался очень много и сильно, особенно после того как сходил к ним в багтрекер и увидел их отношение к происходящему. Про остальные языки не в курсе, из них я только на питоне в блокнотике ещё писал, но блокнотик и не IDE, всё-таки.

Если вы только про джаву — то код компилировался непрерывно еще в Forte (позднее — NetBeans) — 25 лет назад.

Я точно помню, как на той самой Java, когда я учился на ней программировать, ошибки компиляции видел только вон как там вверху писали, перед запуском. Ещё и не все, а только одну, самую первую найденную. Но дело точно было не 25 лет назад, а меньше, и с тех пор всё точно стало значительно лучше, о чём и речь.

Вон даже Typescript появился, где реально можно отловить проблему с типизацией ДО того, как оно у пользователей взорвётся.

А пока они заняты выковыванием, нам совсем нельзя код писать?

Вернет пустой результат

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

Например класс MyUnit для ед. измерения, MyMoney для хранения всех валют и т.д.

Откуда тогда взялось 150 классов?

нет - она будет абсолютно простая

Ну уж точно сложнее, чем реализация ImageID в лоб.

помимо создания нового типа, вам его еще надо как-то обрабатывать, добавлять перегрузки, менять уже существующий код и т.д.

Ну да, типа того. А часто у вас новая фича состоит из добавления свойства в класс и всё? Существующий код менять всё равно нужно.

большой разницы нет - будут ли ошибки во время компиляции или во время первого запуска.

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

Код компилируются обычно перед запуском.

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

Ну с ИД пользователя возможно и не имеют, а с деньгами, н-р (например), вполне могут иметь.

Но при этом, деньга - это не число, а число-и-валюта. И там тоже нельзя просто взять и прибавить, если валюты отличаются.

А если это не ИД, а ед. измерения или валюты - сколько будет таких перезагрузок?

Столько, сколько потребует логика приложения.

findImagesByGroupId(uint id) - ничуть не хуже, все понятно. Какие это предикаты мне придутся перечислять?

"ByGroupId" - это как раз предикат. Упомянутый мной Spring Data из имени методов может запросы генерировать, вот.

Т.е. вы не знаете, что передаете, куда передаете и какой ожидается результат от функции?

Если это не мой код - то нет, сначала придётся всё прочитать. Код, написанный мной год назад - это, в принципе, уже тоже не мой код, при этом.

Как написал выше, ошибки в основном в самой реализации функции, а не в передаче не тех параметров (которые отлавливаются при первом запуске).

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

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

Если именно в этом коде задействовано 150 разных видов сущностей/переменных, то скрыть их настоящий тип за всякими int и string точно разработку сделает сложнее, а не проще.

как защита от дурака при куче не нужных конструкций.

Тестирование - это так-то тоже защита от дурака, ведь у настоящих программистов всё работает и так, ну максимум после второго запуска \srcsm.

А уж сколько для тестирования конструкций всяких придумали...

function ToOneUnit() - приведет к единым единицам.

Её тоже кто-то должен написать, то есть это усложняет код.

при добавлении/изменении типа, нужно менять остальной код

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

Если совсем строго - там про API. Который так-то тоже "interface".

Абстрактный класс с частичной реализацией не катит - абстракции не "должны зависит от деталей".

Опять же, не должны - но могут. И не надо сильно привязываться к похоже звучащим ключевым словам из других языков. Этот принцип применяется не только в рамках одного файла, но и в рамках целых модулей.

ну да, а если единиц измерения, помимо футов и метрах, еще есть в ярдах, миллиметрах, километрах, сантиметрах и т.д., то для каждой отдельную переменную и подтип делать?

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

Lengh{uint, LenghUnit} будет куда удобнее, а если его чуть более развить, но и никакого ToOneUnit не нужно, а вместо этого определить некий IsGreater, и пусть оно внутри уже само разбирается.

Компактно, легко понять, легко расширить и модифицировать, аккуратная архитектура. Чем хуже подтипов?

Ничем не хуже, а наоборот.

Вы скорее всего смешали аргументацию про тип ImageID с про тип Dimension из вообще другого комментария, от того и сомнения.

отвечу также - а почему не должно?

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

а почему не так:

Image? findImageBy(uint ImageId)

Image[] findImagesBy(uint UserId)

Потому что можно вызвать findImagesBy(image.id), и будет баг. А ещё потому что я могу добавить ещё какой-нибудь findImagesBy(ImageGroupID id) - а вам нужно будет в названии метода перечислять все предикаты, как это в Spring Data делается, и в противном случае диспетчеризация сломается.

программист знает, что передает, куда передает и какой ожидается результат.

Ну, так и запишем - в мире нет ни одного программиста. Потому что если бы это верно было, то в программах никогда не было бы багов.

код переусложняют лишними классами, интерфейсами и прочими не нужными конструкциями

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

а в чем упрощения не пояснили

Как это не пояснил, когда уже третье (или четвёртое?) сообщение на разные лады повторяю одно и то же пояснение?

для сравнения н-р ширины, нужно немного клея

Не понял, что такое н-р, но клей-то действительно нужен, особенно для сравнения 200em с 1920px - в вашем языке почти гарантированно нет возможности сравнивать такие вещи из коробки, а значит кто-то их должен был написать. И клей, если читать внимательно, я предложил только для конкретного особого случая. А в другом случае, предположенном в том же комментарии - я предлагаю, что не надо никакого специального кода для написания сравнения размеров окна и размеров картинки, потому что и то и другое в принципе можно выразить и общим типом Dimension.

Я уверен, что подтипы сделали не просто так и где-то они нужны, но точно не для упрощения кода, а скорее для безопасности.

Если я где-то сказал, что такой подход упрощает код - я оговорился. Но, вроде бы, я и не говорил именно про упрощение именно кода. Разработку такой подход точно упрощает, и будущую поддержку тоже.

Пользователь сказал, что ему нужно и получил, что ему нужно.

Текст запроса на SQL?

Давайте я вам чуть по-другому выделю:

the clients tend to own the abstract interfaces

Как видите, эта цитата вообще не противоречит тому, что

Абстракция там не обязательно про интерфейс.

без DI

Это как? Откуда там берутся зависимости в коде - каждый раз новый объект сервиса создаётся?

без абстрактных фабрик

SOLID не требует наличия абстрактных фабрик, это вещь ортогональная.

И как там с остальными буквами?

сразу определить enum?

В данном случае "наследовать от enum" и "определить enum" - это по сути одно и то же.

> Но не в методе pow, куда этот uint можно передать, и не после операции "+ 2" .

не понял

Что такое let id = pow(user.id + 2, 4), и почему это должно компилироваться?

Так проще названия нормальные дать:

findImageById(uint Id) - поиск картинки по ID

findImageByUserId(uint Id) - поиск картинки по ID юзера.

А почему не так:

Image? findImageBy(ImageId id)
Image[] findImagesBy(UserId userId)

?

Бонусом пойдёт то, что findImageById(user.id) компилироваться перестанет, в отличие от.

это защита от совсем непрограммистов и если подходить с этой стороны, то весь код должен состоять из валидаций/проверок

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

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

Ну а про поиск использования любой переменной

Нет, речь не про поиск использования одной переменной - речь про поиск использования одного типа переменной. Без хотя бы алиасинга для идентификаторов, как много вы найдёте у себя в проекте случаев использования uint, и как много из них будут иметь отношение к семантическому типу UserID?

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

Можно, разумеется. Точно так же, как можно заменить большинство uint на any, выбросить тесты, сложить весь код в один файл, и тому подобное. В программировании вообще много чего можно.

потому что они разных типов

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

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

Это может послужить, также, хорошим напоминанием о том, что размеры картинок и окон бывают в пикселях, а бывают в em .

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

это же все равно строка, число или еще что-то.

Да нет же. У него могут быть какая-то логика создания из строк или чисел, но сам по себе этот тип - не строка и не число. Если в ЯП, на котором оно пишется, enum не относится к числам - то ImageType в принципе можно от enum унаследовать, но и это само по себе не обязательно.

ну стандартные типы данных все и так знают и помнят, в отличии от подтипов и поле uint User.Id - вполне за себя говорит

Это оно там за себя говорит (если рядом где-то встречается User, и есть прямой путь от него к id). Но не в методе pow, куда этот uint можно передать, и не после операции "+ 2" .

тип данных uint, а не какой-нибудь UserIdentifier

Но с uint можно сделать множество операций, которые для настоящего UserIdentifier не имеют абсолютно никакого смысла - тот же пресловутый "+ n" из блока чуть выше.

а зачем нужно еще ограничивать пространство применений переменной? - есть стандартные модификаторы доступа

Например, чтобы не было соблазна передать UserIdentifier в какой-нибудь

Image? findImageById(uint id)

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

И поиск по UserIdentifier вернёт места, где используется такой тип значений, а не места, где разработчик соответствующим образом назвал переменную (например, UserIdentifier friendId поиском по uint userId найти куда сложнее).

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

Если уж проводить аналогию - государство это не спасатель на пожаре, это управдом

Не нужно мне напоминать, что ты не знаешь, чем обусловлен уровень поддержки правительства в Эль Сальвадоре - я и так прекрасно помню, времени прошло всего ничего.

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

ImageType - это какой тип данных - string, int, enum или еще какой-то

ImageType - это ImageType, конечно же. Хотя это и не исключает наличия правил конвертирования его в int, string и обратно.

Мы же здесь про упрощение кода говорим?

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

Дело не в классе и его полях, а в остальном коде. При вашем подходе у вас будет какой-то int, и какой-то string. А при определении подтипов - сразу везде становится понятно, что эта конкретная переменная не просто некое число, а целый идентификатор картинки - а значит, по нему, скорее всего, можно поискать саму картинку где-нибудь, и он, например, уникален среди всех остальных хранящихся ImageID , но не будет уникален среди каких-нибудь UserID, а также что нет самостоятельного смысла в том, чтобы по ImageID искать пользователя.

В чуть более продвинутых системах, переменная типа Dimension ,скажем, не сможет иметь отрицательное значение, и это будет вам гарантировать компилятор вашего ЯП, а не "честное слово" предыдущего разработчика.

Вон, в Си до сих пор нормально goto сделать в конец функции для освобождения памяти

break, continue, throw и ранний return - это в Java тоже есть, и широко применяется.

А ещё вот, хоть это и редкость, и у многих людей от непривычки мозг вскипит:

mmark: if (condition) {
    dep0.call(); 
    if (!dep0.verify()) {
        break mmark;
    }
    dep1.call()
    dep2.call();
}

Или в JS можно пяток функций вспомогательных сделать, а в джаве сразу класс, методы

А как же Function<String, Integer> helper = a -> Math.pow(a.length(), 1337);?

Церемонии чуть больше, но это только из-за типизации. На кондовом Typescript оно столько же места займёт.

В питоне используют множественное наследие для Миксинов

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

Если два разраба не могут договориться, пусть зовут тимлида, пусть он скажет, как понятнее.

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

Ну и каждый раз тимлида ненадёргаешься, и в итоге будет выстроена снова какая-то система, не факт что лучше SOLID.

Information

Rating
Does not participate
Location
Россия
Registered
Activity