>«нужно выполнять задачи из этого списка, внимательно и прилежно, а результат должен соответствовать уровню наших конкурентов, сроки выполнения указаны тут, если не укладываетесь сообщить туда, по всем вопросам сюда»
А где в этом месте покупка моих скольких-то высокопроизводительных часов?
Нигде, я никогда не писал о высокопроизводительных часах. Я писал о том, что выше обозначено, а также вот об этом
Будут прилагать максимально возможный уровень усилий, который позволит вам продолжать эту деятельность, без падения продуктивности, до выхода на пенсию.
Вместе это и есть мое определение "продуктивного времени". Трудовых подвигов ala Стаханов никому не надо, надо просто работать нормально и все.
Ну вот я успешно исполняю это за 4 часа и дальше пью чаи в ожидании авралов, а сосед — косячит за 8 часов. Оклад у нас одинаковый.
Почему оклад одинаковый? Как вы успели задачи из практически бесконечного беклога сделать за 4 часа?
И да, мне очевидно, что senior делает простые формочки с такой же скоростью как стажер, но стажер не может делать то, что может делать senior и поэтому senior получает больше денег. Кажется странным, что мы должны о таких базовых вещах договариваться на профессиональном ресурсе...
>>>>TDD требует тестировать практически каждый класс. Без моков этого сделать нельзя. ...
>>>Вот тут не правда. Тестировать-то можно и без тотального мокирования.
>>Если класс А зависит от репо, то мне нужен мок. И так по цепочке. Классу Б нужен класс А, либо мокать А, либо мокать репо. Как с этим бороться?
>Запускать тесты в изолированном контексте, где репо заменён на мок, и всё.
"вы либо трусы наденьте либо крестик снимите" :)
Все, что зависит от репо явно и не явно будет зависеть от моков. Причем это справедливо не только для репо, а вообще для любого кода, который делает IO - БД, API, файлы и т.п. А это почти весь код приложения. Так что я не понимаю как утверждения
Тестировать-то можно и без тотального мокирования.
Нужно мокать все, что делает IO
Примерно весь код типичного веб приложения так или иначе завязан на IO (через репо или иные обертки)
Если оклад это не продажа продуктивного времени, то это продажа чего? Положим я купил ваши 8 (или 6.5, как вам угодно) часов вашего времени и сказал - «нужно выполнять задачи из этого списка, внимательно и прилежно, а результат должен соответствовать уровню наших конкурентов, сроки выполнения указаны тут, если не укладываетесь сообщить туда, по всем вопросам сюда». Скажете ли вы что
это уж слишком продуктивно, не похоже на электрика и откажетесь
Попросите прибавку, потому что тут же работать надо
Будете выполнять работу на отъ..ись ибо работодатель должен уже и так кайфовать от факта покупки времени
Будут прилагать максимально возможный уровень усилий, который позволит вам продолжать эту деятельность, без падения продуктивности, до выхода на пенсию.
Список шуточный, но в каждой шутке… мне интересно как вы на поставленный вопрос ответите с позиции «продажи времени»
А что там сложного? Распарсил запрос, вызвал нужную ручку апи. Абстрактных ручек единицы-десятки.
Одно из таких абстрактных API это OData, а вот это
cloc AspNetCoreOData-master
Language code
C# 107805
намекает, что тезис про простоту тула не очень согласуется с реальностью.
Да, это всё в конфигурацию выносится. Это всего несколько сотен строк, которые и тестировать не надо.
Узкоспециализированный тул (5K - 10K LoC) + несколько сотен строк конфига против 1K - 2K LoC единообразного кода, который осилит любой джун. Выигрыш не всегда очевиден.
Я уже даже не помню, зачем я в это обсуждения ввязался, наверное категоричность заявления про абстрактное апи меня задело. И "копипаста" и абстрактное апи имеют место быть. Для меня, когда-то было открытием, что пачка тупых контроллеров в поддержке часто оказывается дешевле, чем если тоже самое делать с наворотами ради DRY.
Можно далеко идти в архитектуру, но зачем? У меня простые утверждения
>>из репозитория нельзя выставлять IQueryable, а это мега удобно.
>Не знаю специфики вашей платформы. Если я правильно понимаю, это что-то вроде Query Builder. Да, это должно быть отделено от бизнес-логики.
Да это Query Object и это все еще удобно. На ваш аргумент "это должно ..." я ответу еще более мощным "это не должно ..." Чем внезапно repo.FindById оказался лучше db.FindById ?
>>Каждый клиент теперь зависит от мока. Значит как только в репо изменится сигнатура какого-то метода получим некоторый кайф.
>У вас же статический ЯП? То есть даже тесты смотреть не нужно.
Это не про статическую типизацию, это про то, что часть моков отвалится и вам нужно будет их чинить. Пользы от этого действия 0, это дань архитектуре.
И цепочка рассуждений такая: TDD требует тестировать практически каждый класс. Без моков этого сделать нельзя. Следовательно везде будут интерфейсы и DI. а также обертки над любом API которое делает IO. А это почти все, не побоюсь утверждать, что это 90% всего что есть в природе. Как следствие на моки будут завязаны почти все тесты. Изменение любого внутреннего интерфейса приводит к каскадному эффекту - ломаются моки в тестах клиентов этого интерфейса.
Прям таки простой? И как это фасад узнает по каким полям можно фильтровать, а по каким нельзя, по каким можно сортировать, а как нельзя, какие юзеры доступны этой роли, а какие нет? Может все таки для каждой сущности у для него таки будет конфигурация какая-то? И очень интересно посчитать сколько строк в этой конфигурации будет и сравнить.
На 40 сущностей "копипасты" будет около 1000-2000 строк. Ваш фасад + конфиг будет сильно больше и его будет сильно сложнее менять, не находите?
Другой большой вопрос в том, что будет с вашим фасадом, когда появятся требования что-то кешировать, где-то рассылать нотификации и всякое такое. В случае с "копипастой" я допишу по строке там где нужно. И даже могу что-то зарефакторить и спрятать в сервис. А в случае фасада вы будете допиливать свой DSL. Ради экономии примерно 1 строки на каждую сущность :)
А чего вы тогда не сидите и не плюете в потолок по 40 часов в неделю, вы же время продали... Или сидите и плюете? Или работаете но так, чтобы видимость создать, лишь бы не уволили?
Вы пример кода приведите на основе абстрактного апи и мы сравним. Если апи на конфигурации/аннотациях ездит, то из посчитаем, а так посмотрим сколько кода надо написать. Только чтобы было честно давайте не будем брать узкоспециализированные решения типа ActiveAdmin.
Аргумент вида "в пост мясо есть нельзя, в писании так сказано". Как только появится определение abstraction в виде понятного формализма, мы сможем серьезно об этом говорить. А пока я могу взять два куска кода, предположить возможные изменения требований и сравнить как они будут меняться. Несложно увидеть, что конкретно в этом случае репо сосет и будет меняться на каждый чих (вместо с тестами на него)
GET /users?email=me@me.com
dbContext.Users.Where(x => x.Email == email).ToJson();
userRepo.FindByEmail(email).ToJson();
изменения
Новые фильтры
Сортировка по разным полям
Ограничение на то, каких юзеров можно и нельзя видеть
Включить/выключить список ролей юзера в ответе
GET /users?email=me@me.com&name=Peter&role=1
var users = dbContext.Users.ScopedBy(user.Role)
.Where(x => x.Email == email && x.Name == name);
if (role) users = users.Include(x => x.Roles);
return users.ToJson();
Я тут сортировку не добавил, думаю вы сами догадаетесь как ее можно сделать.
Попытка все это реализовать с помощью репо приведет к созданию кривой версии IQueryable, которую еще придется поддерживать. Это утверждение, можете меня поправить, если не так.
Что произошло при вызове метода с params? Выделил память (инкремент счётчика), заполнили, использовали и забыли. Далее GC (внимание) проходит по живым, достижимым объектам, среди которых нашего params массива уже нет. GC компактит кучу и перетирает память выделенную под params так никогда и не узнав, что он вообще существовал.
То есть непонятно зачем вы оптимизировали временные объекты если их создание и удаление это (почти) бесплатная операция? GC (почти) никогда эти объекты не увидит и не тронет. Все ваши оптимизации привели к тому, что снизилось давление на кучу, реже стал запускаться full GC, но он все также тратит много времени на эти запуски. Не то, чтобы это вообще было бессмысленно, но такое.
Гораздо веселее разобраться почему GC тратит время на обход и компакт кучи. Если модель заточить под GC, то беспокоиться о params и итераторах уже не нужно. Я хочу сказать, что создавать сотни тысяч и миллионы объектов в секунду это не проблема, если они живут секунды. А вот напихать в кеш кучу развесистых изменяемых объектов это прямой путь к тормозам.
Другими словами - все что делает IO нужно спрятать за API и замокать. Само АПИ тестировать с живой ОС, БД и т.д.
Тогда имеем следствия
из репозитория нельзя выставлять IQueryable, а это мега удобно.
Каждый клиент теперь зависит от мока. Значит как только в репо изменится сигнатура какого-то метода получим некоторый кайф.
Там где у меня будет extension method для DbContext у вас будет репо, интерфейс, DI и геморой с моками. Но самое главное - я буду использовать IQueryable и это сэкономит мне тысячи строк кода. А вы нет, потому что IQueryable замокать так себе удовольствие.
Как замокать API memory mapped file? Есть код, который в много потоков потоков что-то в него пишет, ротирует сегменты и т.п. Хочется понять, что этот код правильно с ним работает.
Как замокать БД, так чтобы в тесте все же проверить, что SQL генерируется правильный синтаксически и что выбираются верные данные? Нужно учесть, что в работе с БД активно используется всякие Postgres специфические upsert, sequence и прочая.
Любое изменение состояния, особенного глобального - статические переменные, запись в файл, сеть, БД. Про связь этого с модульностью я лучше SICP не напишу, лучше там читать.
Преклоняюсь перед вашим опытом, расскажите же мне, сирому и убогому, как решаются обозначенные мной проблемы в конторах «без бардака» И не стесняйтесь, расскажите как называются эти чудо организации.
Согласен. Но почему-то все говорят о xDD, вместо обсуждения реальных проблем. О том, как можно изолировать базу, как сеть, как HTTP и так далее. Обычный ответ - моки, но это не ответ вовсе, а уход от проблемы.
Слышала и пробовала, тут все же профессионалы собрались. Я пишу биржу, 80% моего кода активно работает с БД, а 20% многопоточка. Подскажите, как мне замокать базу и потоки? Тестировать что класс А вызвал класс Б не интересно. Интересно увидеть, что в результате получился корректный SQL, а база в ответ на него вернул то, что ожидается.
Согласен, но не вижу повода для сожаления, такова реальность. В SICP очень классно расписана связь между модульностью и побочными эффектами. Хотите инкапсулировать поведение - получите состояние. Или таскайте везде явно или неявно параметр типа World, что ничего существенно не меняет.
"легко тестировать код без побочных эффектов" и как следствие "сложно тестировать код с побочными эффектами" это хорошая и обоснованная платформа для критики TDD. Либо покажите как тестировать побочные эффекты легко, либо научите писать код вообще без них, а заодно расскажите как быть с модульностью в этом случае. Либо признаем, что чаще всего TDD применять сложно и вполне справедлив вопрос о целесообразности.
А я бы сказал, что легко тестировать код, который без IO. А тяжело тот, который это IO делает или многопоточный. К качеству кода все это отношение не имеет. Даже если код это атомная лапша Гейзенберга, но его можно запустить не показ миллион сервисов и не поднимая базу, то писать тесты легко, но тестов надо будет много. Но все равно их писать легко.
Вопрос в том как выбираются эти задачи. Если они все одного уровня сложности, то дело было просто в моей тупости. А если сложность гуляет, то мне могло просто не повезти. Есть ли где-то примеры задач? Я бы порешал на досуге, а то надоело в hearhtstone играть.
Нигде, я никогда не писал о высокопроизводительных часах. Я писал о том, что выше обозначено, а также вот об этом
Вместе это и есть мое определение "продуктивного времени". Трудовых подвигов ala Стаханов никому не надо, надо просто работать нормально и все.
Почему оклад одинаковый? Как вы успели задачи из практически бесконечного беклога сделать за 4 часа?
И да, мне очевидно, что senior делает простые формочки с такой же скоростью как стажер, но стажер не может делать то, что может делать senior и поэтому senior получает больше денег. Кажется странным, что мы должны о таких базовых вещах договариваться на профессиональном ресурсе...
"вы либо трусы наденьте либо крестик снимите" :)
Все, что зависит от репо явно и не явно будет зависеть от моков. Причем это справедливо не только для репо, а вообще для любого кода, который делает IO - БД, API, файлы и т.п. А это почти весь код приложения. Так что я не понимаю как утверждения
Тестировать-то можно и без тотального мокирования.
Нужно мокать все, что делает IO
Примерно весь код типичного веб приложения так или иначе завязан на IO (через репо или иные обертки)
Могут быть все одновременно истинными.
Если оклад это не продажа продуктивного времени, то это продажа чего? Положим я купил ваши 8 (или 6.5, как вам угодно) часов вашего времени и сказал - «нужно выполнять задачи из этого списка, внимательно и прилежно, а результат должен соответствовать уровню наших конкурентов, сроки выполнения указаны тут, если не укладываетесь сообщить туда, по всем вопросам сюда». Скажете ли вы что
это уж слишком продуктивно, не похоже на электрика и откажетесь
Попросите прибавку, потому что тут же работать надо
Будете выполнять работу на отъ..ись ибо работодатель должен уже и так кайфовать от факта покупки времени
Будут прилагать максимально возможный уровень усилий, который позволит вам продолжать эту деятельность, без падения продуктивности, до выхода на пенсию.
Список шуточный, но в каждой шутке… мне интересно как вы на поставленный вопрос ответите с позиции «продажи времени»
Если класс А зависит от репо, то мне нужен мок. И так по цепочке. Классу Б нужен класс А, либо мокать А, либо мокать репо. Как с этим бороться?
Одно из таких абстрактных API это OData, а вот это
намекает, что тезис про простоту тула не очень согласуется с реальностью.
Узкоспециализированный тул (5K - 10K LoC) + несколько сотен строк конфига против 1K - 2K LoC единообразного кода, который осилит любой джун. Выигрыш не всегда очевиден.
Я уже даже не помню, зачем я в это обсуждения ввязался, наверное категоричность заявления про абстрактное апи меня задело. И "копипаста" и абстрактное апи имеют место быть. Для меня, когда-то было открытием, что пачка тупых контроллеров в поддержке часто оказывается дешевле, чем если тоже самое делать с наворотами ради DRY.
Можно далеко идти в архитектуру, но зачем? У меня простые утверждения
Да это Query Object и это все еще удобно. На ваш аргумент "это должно ..." я ответу еще более мощным "это не должно ..." Чем внезапно repo.FindById оказался лучше db.FindById ?
Это не про статическую типизацию, это про то, что часть моков отвалится и вам нужно будет их чинить. Пользы от этого действия 0, это дань архитектуре.
И цепочка рассуждений такая: TDD требует тестировать практически каждый класс. Без моков этого сделать нельзя. Следовательно везде будут интерфейсы и DI. а также обертки над любом API которое делает IO. А это почти все, не побоюсь утверждать, что это 90% всего что есть в природе. Как следствие на моки будут завязаны почти все тесты. Изменение любого внутреннего интерфейса приводит к каскадному эффекту - ломаются моки в тестах клиентов этого интерфейса.
Какое из утверждений выше не истинно?
Прям таки простой? И как это фасад узнает по каким полям можно фильтровать, а по каким нельзя, по каким можно сортировать, а как нельзя, какие юзеры доступны этой роли, а какие нет? Может все таки для каждой сущности у для него таки будет конфигурация какая-то? И очень интересно посчитать сколько строк в этой конфигурации будет и сравнить.
На 40 сущностей "копипасты" будет около 1000-2000 строк. Ваш фасад + конфиг будет сильно больше и его будет сильно сложнее менять, не находите?
Другой большой вопрос в том, что будет с вашим фасадом, когда появятся требования что-то кешировать, где-то рассылать нотификации и всякое такое. В случае с "копипастой" я допишу по строке там где нужно. И даже могу что-то зарефакторить и спрятать в сервис. А в случае фасада вы будете допиливать свой DSL. Ради экономии примерно 1 строки на каждую сущность :)
А чего вы тогда не сидите и не плюете в потолок по 40 часов в неделю, вы же время продали... Или сидите и плюете? Или работаете но так, чтобы видимость создать, лишь бы не уволили?
Вы пример кода приведите на основе абстрактного апи и мы сравним. Если апи на конфигурации/аннотациях ездит, то из посчитаем, а так посмотрим сколько кода надо написать. Только чтобы было честно давайте не будем брать узкоспециализированные решения типа ActiveAdmin.
Аргумент вида "в пост мясо есть нельзя, в писании так сказано". Как только появится определение abstraction в виде понятного формализма, мы сможем серьезно об этом говорить. А пока я могу взять два куска кода, предположить возможные изменения требований и сравнить как они будут меняться. Несложно увидеть, что конкретно в этом случае репо сосет и будет меняться на каждый чих (вместо с тестами на него)
изменения
Новые фильтры
Сортировка по разным полям
Ограничение на то, каких юзеров можно и нельзя видеть
Включить/выключить список ролей юзера в ответе
Я тут сортировку не добавил, думаю вы сами догадаетесь как ее можно сделать.
Попытка все это реализовать с помощью репо приведет к созданию кривой версии IQueryable, которую еще придется поддерживать. Это утверждение, можете меня поправить, если не так.
Что произошло при вызове метода с params? Выделил память (инкремент счётчика), заполнили, использовали и забыли. Далее GC (внимание) проходит по живым, достижимым объектам, среди которых нашего params массива уже нет. GC компактит кучу и перетирает память выделенную под params так никогда и не узнав, что он вообще существовал.
То есть непонятно зачем вы оптимизировали временные объекты если их создание и удаление это (почти) бесплатная операция? GC (почти) никогда эти объекты не увидит и не тронет. Все ваши оптимизации привели к тому, что снизилось давление на кучу, реже стал запускаться full GC, но он все также тратит много времени на эти запуски. Не то, чтобы это вообще было бессмысленно, но такое.
Гораздо веселее разобраться почему GC тратит время на обход и компакт кучи. Если модель заточить под GC, то беспокоиться о params и итераторах уже не нужно. Я хочу сказать, что создавать сотни тысяч и миллионы объектов в секунду это не проблема, если они живут секунды. А вот напихать в кеш кучу развесистых изменяемых объектов это прямой путь к тормозам.
Другими словами - все что делает IO нужно спрятать за API и замокать. Само АПИ тестировать с живой ОС, БД и т.д.
Тогда имеем следствия
из репозитория нельзя выставлять IQueryable, а это мега удобно.
Каждый клиент теперь зависит от мока. Значит как только в репо изменится сигнатура какого-то метода получим некоторый кайф.
Там где у меня будет extension method для DbContext у вас будет репо, интерфейс, DI и геморой с моками. Но самое главное - я буду использовать IQueryable и это сэкономит мне тысячи строк кода. А вы нет, потому что IQueryable замокать так себе удовольствие.
Тогда у меня есть пара вопросов.
Как замокать API memory mapped file? Есть код, который в много потоков потоков что-то в него пишет, ротирует сегменты и т.п. Хочется понять, что этот код правильно с ним работает.
Как замокать БД, так чтобы в тесте все же проверить, что SQL генерируется правильный синтаксически и что выбираются верные данные? Нужно учесть, что в работе с БД активно используется всякие Postgres специфические upsert, sequence и прочая.
Любое изменение состояния, особенного глобального - статические переменные, запись в файл, сеть, БД. Про связь этого с модульностью я лучше SICP не напишу, лучше там читать.
Преклоняюсь перед вашим опытом, расскажите же мне, сирому и убогому, как решаются обозначенные мной проблемы в конторах «без бардака» И не стесняйтесь, расскажите как называются эти чудо организации.
Согласен. Но почему-то все говорят о xDD, вместо обсуждения реальных проблем. О том, как можно изолировать базу, как сеть, как HTTP и так далее. Обычный ответ - моки, но это не ответ вовсе, а уход от проблемы.
Слышала и пробовала, тут все же профессионалы собрались. Я пишу биржу, 80% моего кода активно работает с БД, а 20% многопоточка. Подскажите, как мне замокать базу и потоки? Тестировать что класс А вызвал класс Б не интересно. Интересно увидеть, что в результате получился корректный SQL, а база в ответ на него вернул то, что ожидается.
Согласен, но не вижу повода для сожаления, такова реальность. В SICP очень классно расписана связь между модульностью и побочными эффектами. Хотите инкапсулировать поведение - получите состояние. Или таскайте везде явно или неявно параметр типа World, что ничего существенно не меняет.
"легко тестировать код без побочных эффектов" и как следствие "сложно тестировать код с побочными эффектами" это хорошая и обоснованная платформа для критики TDD. Либо покажите как тестировать побочные эффекты легко, либо научите писать код вообще без них, а заодно расскажите как быть с модульностью в этом случае. Либо признаем, что чаще всего TDD применять сложно и вполне справедлив вопрос о целесообразности.
А я бы сказал, что легко тестировать код, который без IO. А тяжело тот, который это IO делает или многопоточный. К качеству кода все это отношение не имеет. Даже если код это атомная лапша Гейзенберга, но его можно запустить не показ миллион сервисов и не поднимая базу, то писать тесты легко, но тестов надо будет много. Но все равно их писать легко.
Вопрос в том как выбираются эти задачи. Если они все одного уровня сложности, то дело было просто в моей тупости. А если сложность гуляет, то мне могло просто не повезти. Есть ли где-то примеры задач? Я бы порешал на досуге, а то надоело в hearhtstone играть.