All streams
Search
Write a publication
Pull to refresh
22
0
Алексей @pankraty

Разработчик

Send message

Ребёнок развивает языковые навыки в течение лет пяти, прежде чем его уровень владения языком можно назвать сколько-нибудь продвинутым. И это при абсолютно полном погружении в среду 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-ами сделал приватными, а публичными сделал обертки со строгой типизацией.

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

Да, баги есть, пытаемся фиксить по мере сил, только времени на все не хватает… Если не секрет, какие у вас всплыли?

Да, можно посмотреть тут https://closedxml.github.io/ClosedXML.Report/docs/ru/Flat-tables, раздел Горизонтальные области

Еще в мире .NET есть библиотека ClosedXML, которая предоставляет гораздо менее громоздкий (чем OpenXML) API для работы с книгами XLSX (сама библиотека использует OpenXML, т.е. по сути является "оберткой"). А конкретно для формирования отчетов по готовым шаблонам очень удобно использовать библиотеку ClosedXML.Report, явялющуюся надстройкой над ClosedXML. Вот тут есть примеры, как быстро создать отчет.


В шаблоне прописываются источники данных в виде наименований полей CLR-объектов (поддерживаются выражения, в т.ч. Linq):


image

И само формирование отчета производится в несколько строк:


        const string outputFile = @".\Output\report.xlsx";
        var template = new XLTemplate(@".\Templates\report.xlsx");

        using (var db = new DbDemos())
        {
            // You can get the value from anywhere, not only from the database
            var cust = db.customers.LoadWith(c => c.Orders).First();
            template.AddVariable(cust);
            template.Generate();
        }

        template.SaveAs(outputFile);

        //Show report
        Process.Start(new ProcessStartInfo(outputFile) { UseShellExecute = true });

Обе библиотеки распространяются под свободной лицензией и поддерживают .NET Core. Когда-нибудь, надеюсь, дойдут руки написать более подробную статью о них на Хабре.

Может, я что-то не так понял, но у меня сложилось впечатление, что внезапно 150+ тестов стали красными, при это ошибка только в одном, а остальные не смогли выполниться из-за этой ошибки. И да, исправить нужно только один тест, но сначала его надо найти из 150+ красных. Непродуктивная трата времени.
Если приложение Test Runner будет умирать на первом assert-e — программисты будут вынуждены починить этот ассерт для запуска остальных тестов. Нет проблемы.


Это если сразу понятно, какой из тестов обрушил остальные. Но когда внезапно падает 150 тестов, отыскивать тот единственный, из-за которого не работают все — удовольствие сомнительное. Оказывался в подобной ситуации, когда один из тестов начал выдавать StackOverflowException, чем обрушивал TestRunner.
Хм. Вот, допустим, процесс 1 хочет открыть файл file.txt, но в папке есть только FILE.txt. В соответствии с вашим алгоритмом, процесс открывает этот файл и работает с ним. В это время процесс 2 создает рядом файл File.txt. После этого процесс 1 проверяет наличие файла с именем file.txt — и не находит его! «Как же так?» — думает он, — «Я ж держу дескриптор открытым, а файл исчез!» И от отчаяния накладывает на себя руки вываливает ошибку.

Спасибо за статью.
У нас используется AppVeyor — бесплатен для OpenSource. Довольно гибко настраивается, есть веб-морда для настройки. С другими системами не сравнивал, поэтому, к сожалению, плюсы-минусы обозначить не могу.

Английское «please» в ответ на благодарность можно перевести как «ах, оставьте», «не стоит».
По Tree(2), мне кажется, у вас тоже неверно. Должно быть синий-синий, красный-красный, красный-синий. А то если деревья можно упорядочивать не по возрастанию числа вершин, последовательность легко можно сделать бесконечной.
Они своим словоблудием продвигают в массы только нужные им идеи, не заботясь ни о теории, ни о доказательствах

Полностью согласен! Взять хотя бы
В идеале должно быть всего 2 низкоуровневых языка и 3-4 высокоуровневых, построенных на их основе.

Information

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