Как стать автором
Обновить
22
0.4
Алексей @pankraty

Разработчик

Отправить сообщение

Недавно ревьювил код, и там было использовано слово forbid. У меня возникло ощущение, что ему тут не место, хотелось предложить заменить на prohibit, но чем обосновать — неясно. Переводчики оба слова переводят одинаково.
Проконсультировался с англоговорящим знакомым, тот подтвердил: смысл один, оттенки разные. Forbid более авторитарное, обычно имеется в виду, что кто-то персонально запрещает. А в случае организации или неопределённой группы лиц — скорее prohibit.

Если я правильно понимаю, раньше было 2 проприетарных платформы, работающих по сходим правилам: .net и java. Microsoft, чтобы "подтолкнуть развитие платформы и экосистемы", вывела .net в опенсорс; Oracle с той же целью сделала java платной. Очень интересно будет посмотреть в перспективе, чья стратегия к чему привела.

theCreature.Health = (theCreature.Health - damage).ButNotLess(than: 0).However().IfAndOnlyIf(theCreature is (Terribly)Lucky).Then(theCreature.Health + 2 * damage);

Fluent-подход отлично заходит, когда видишь одну строчку кода, и по ней понятно, что тут происходит. Например, создание маппинга в автомаппере:

configuration.CreateMap<OneThing, OtherThing>()
.ForMember(d => d.StatusId, ctx => ctx.MapFrom(s => s.Status))

(у меня тут правда большой вопрос к авторам, почему в CreateMap сначала Source, потом Destination, а в маппинге полей — наоборот. Ну да ладно, это к делу не относится)

Но когда в маппинг надо добавить выражения для 5, 10, 20 полей эта многословность начинает бесить. Куда выразительнее написать, к примеру,

configuration.CreateMap<OneThing, OtherThing>()
{
Status => StatusId,
Price => Cost,
Amount => Quantity,
Count => Number
};


Конечно, учитывая ограничения и синтаксис языка, это писалось бы, скорее так:
{ s => s.Price, d => d.Cost },. И тут, не зная контекста, сложнее понять что происходит, чем в случае fleunt-подхода. Но при многогратном повторении смотрится чище.
Если вызывать его на чём-то целом, да. Но когда у вас уже есть нечто разделённое, Separated(with: ", ")...

… как мне кажется, вызывает ступор и InvalidOperationException в мозгу.

SQL шел (идет?) по пути приближения к человеческому языку. Результат, как минимум, спорный, но и там не стали для объединения строк использовать ключевое слово SEPARATED BY. Назвать функцию STRING_AGG, думаю, тоже не было идеальным решением, но она хотя бы образована от AGGREGATE, не SEPARATE.
Join — это глагол, Separated — это прилагательное, первое — это действие, второе — это результат.

Даже если оба слова сделать активными (join, separate) или пассивными глаголами (joined, separated), суть не изменяется. Первый про объединение, второй про разделение, и действия эти направлены противоположно. Увидеть separated там, где ожидаешь увидеть joined, не ложится в прицнип наименьшего удивления.
Когда на входе — коллекция, а на выходе — строка, то это-таки «элементы, соединенные запятыми». Если же наоборот — то можно получить, допустим, список слов, разделенных [в исходной строке] пробелами.

Вот хоть убейте, Separate должен возвращать нечто разделенное (аналог string.Split). А у вас возвращается строка, склеенная из частей. Если бы я разбирался в АПИ незнакомой библиотеки, я искал бы concat, combine, join, glue, aggregate или что-то в этом роде. И когда, не найдя, я полез бы в справку и нашел там, что мне надо использовать separate, я подумал бы, что кто-то сошел с ума — или я, или автор библиотеки.
Особенно выразительно смотрится с пустым разделителем. chars.separate(""). Awesome

И ведь не GitUtils, а IRepository, ICommit, IBranch; не ExcelHelper, а ExcelDocument, ExcelSheet; не GoogleDocsService, а GoogleDocs.


С другой стороны, «Система контроля версий», а не «Коммиты». «Текстовый редактор», а не «Тексты». «Веб-браузер», а не «Веб-страницы».

«Кофемолка», «Холодильник», «Калькулятор», «Эскалатор», «Эвакуатор» — а не «Кофе», «Продукты», «Вычисления», «Ступеньки», «Беспредельщики»

Это еще и флотское приветствие. В Как я встретил вашу маму был персонаж, который со всеми здоровался только так.

Бесполезно с помощью модификаторов доступа пытаться защититься от того, что ваш класс "отрефлексируют". В метаданных сборки представлены все члены, даже самые приватные, иначе CLR не сможет с ними работать.


Модификаторы доступа — это не более чем контракт. Если вы объявили член публичным, то потребители вашей библиотеки вправе рассчитывать, что этот член не будет слишком уж часто меняться. А вот если они через рефлексию доставали internal классы, и после обновления библиотеки все перестало работать — так они ССЗБ.


Еще, модификатор класса "перекрывает" модификаторы его членов. Например, если класс (вложенный) объявлен как private, у него вполне легально может быть public конструктор, но использовать его можно будет только в пределах внешнего класса (опять же, не беря в расчет рефлексию).

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

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

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

iss.supply_hold.use_supplies(«parts», 2)
iss.supply_hold.load_supplies(«parts», 10)


У описанного подхода, наряду с преимуществами, есть огромный такой подводный камень. Если внешние (по отношению к классу) сущности знают про ее составные части (supply_hold, thrusters, etc.), то практически невозможно предотвратить их повсеместное использование. И это через какое-то время приводит к тому, что код опять становится плохо тестируемым (= трудноподдерживаемым).

Утрированный пример: пусть наш класс SpaceStation описывает космический корабль, а у нас стоит задача подсчитать суточную потребность межгалактического космопорта в топливе. Подход «в лоб» —
* пройтись в цикле по всем терминалам космопорта,
* собрать все корабли, находящиеся в терминале,
* добавить в коллекцию все корабли, которые планируют прилететь в ближайшие сутки,
* отфильтровать только те, которые планируют вылететь в течение суток,
* просуммировать вместительность всех их баков и вычесть топливо, в этих баках находящееся.

Так вот, если в этом примере код будет спускаться на уровень FuelTank-а каждого корабля, то создать моки для того, чтобы протестировать описанную логику, — будет очень, очень, очень громоздкой задачей. Как результат, на написание тестов часто будут «забивать» по причине горящих сроков, и в конце концов получится забагованный спагетти-код.

Нет, я не спорю, разделять сущности в соответствии с SRP — нужно. Но одновременно с этим вложенные сущности придется прятать в приватных полях, наружу выставляя более высокоуровневые методы (условно, GetFuelTanksCapacity(), GetFuelResidue()...). Это, в свою очередь, приведет к тому, что класс SpaceStation снова превратится в god object с множеством методов с совершенно различными обязанностями. Да, большинство этих методов будет тонкими обертками вокруг вложенных сущностей (a.k.a. паттерн фасад), да, этот класс будет сравнительно легко использовать в модульных тестах, но выглядеть он все равно будет страшно. Мало того, со временем разные потребители класса будут стремиться расширить класс еще более.

Отчасти это можно компенсировать при помощи принципа разделения итерфейсов: класс SpaceStation может реализовывать множество интерфейсов, в каждом из которых будет 1-2-5… методов, и внешний код будет работать с «толстой» сущностью только по «тонкому» интерфейсу, даже не зная, что работает с таким сложным божественным объектом. Но кода, увы, будет уже не в 2 раза больше, а раз этак в 6…

Увы, но у сложных проблем редко бывают простые решения, почти всегда что-то приносится в жертву.
Странно, что никто не вспомнил про такой менеджерский способ решения проблемы как делегирование. Вместо мытья туалета самостоятельно — нанять уборщицу; с учетом выходного дня — прозвонить несколько объявлений от частников, найти кто готов «вотпрямщас». Вместо написания гимна — обратиться к профессионалам и т.п.

Условиям задачи это вроде никак не противоречит, но позволяет решить проблему эффективнее.

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

Вижу, что перевод, но все же спрошу.


  1. Не будет ли такой подход вызывать сильную фрагментацию данных и тормозов с VACUUM?
  2. Почему бы не добавить индексированное поле, в котором хранится md5, с ограничением уникальности? При вставке данных можно просто отбрасывать уже существующие (делать UPSERT), тогда и чистить не придется.
  3. Нет ли опасности удалить что-то нужное при коллизии хешей?
От версии версии к версии у Студии меняется значок, и это, конечно, правильно. Но разработчикам приходится запоминать визуальный образ значка, чтобы ориентироваться между различными версиями. В Автокадом, кстати, такая же чехарда.
А вот в Нанокаде, например, гораздо удобнее: там номер версии прямо в значке, ошибиться невозможно. Может, стоит перенять их опыт?

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

Спасибо! Знаю теперь, какой вопрос на следующем собеседовании задать Не был знаком с такой терминологией.

Недавно у меня был характерный случай, когда Nominal typing проявил свои отрицательные качества. Суть: есть два класса, определенные во внешней библиотеке, имеющие одинаковую семантику, одинаковые поля (по крайней мере, в той части, которая меня интересовала), даже называются одинаково, но находятся в разных пространствах имен. И мне нужно конвертировать сущности любого их этих классов в мой собственный класс и обратно, по возможности с минимумом дублирования кода. Интерфейса общего нет, предка общего нет, копипасту плодить очень не хочется… Выручил как раз подход в стиле Structural typing — метод принимает dynamic и обращается к нужным свойствам, выполняет конвертацию. Чтобы не выстрелить себе в ногу, методы с dynamic-ами сделал приватными, а публичными сделал обертки со строгой типизацией.

Информация

В рейтинге
1 959-й
Откуда
Саратов, Саратовская обл., Россия
Дата рождения
Зарегистрирован
Активность