Здравствуйте, gandjustas, Вы писали:
G>То есть у нас появился объект "считыватель карточек Х", где Х — термин предметной области, так? Это ведь уже не совсем ubiquitous language, про который говорит DDD.
Это опять результат того, что я не очень аккуратно написал. Дело не в считывании как таковом, а в том, что связи между "воин" — "визард" — "меч" — "посох" это, с моей точки зрения, ДАННЫЕ. Они должны создаваться отдельным редактором (который я, опять же, неаккуратно назвал "админкой") и загружаться движком. Их должно быть можно менять не-программистам, не меняя код. Данные такого типа, как я слышал, называют "ресурсы". А хардкодить ресурсы в классах движка (и вообще в коде) можно только от бедности. (Если посмотреть исходники старых игр, они любили БД с игровыми данными пихать прямо в Си в виде файла с дефайнами, но тогда же и железо другое было).
С одной стороны, это, конечно, моя вина, что я криво написал. А с другой стороны, я эту идею выразил достаточно чётко, можно было бы и не придираться к отдельным словам.
Мне вообще всё равно, как устроена сериализация (объект "считыватель карточек Х"), это малозначительный аспект кода. А вот когда я вижу класс Wizard, это для меня сразу красный свет. Кстати, многие в реальности так и проектируют, судя по всему. Например, редактор карт от Heroes 3 не позволяет создавать свои мечи и посохи (у каждого шмота в этой игре есть требования к персонажу, который может им владеть, но оно вообще составное, а некоторые его части — количественные). Он позволяет только выбрать из готовой коллекции и положить в заданное место или снабдить им игрока. Это, конечно, не значит, что сама коллекция у них обязательно прописана в коде. Может, в каком-то файле с данными лежит. Но вот то, что они её не вынесли на уровень редактора, это большая архитектурная ошибка. Мы бы до сих пор играли в Heroes 3... в смысле, ещё больше Была бы куча total conversions. Всё это неплохо окупается по оконцовке.
Если же ты имел в виду просто то, что "карточка персонажа" и "карточка предмета" — не ubiquitous language для RPG, то я не соглашусь. Люди играли в РПГ задолго до компьютеров, и многие настольные версии, насколько я знаю, не просто имели карточки, а карточки там были главными объектами, не считая многогранника ("кубика"). Ещё, насколько я читал, там были "мастера игры" — выделенные люди, которые "я, таки, не играю, я, таки, счёт веду". Может быть (это не точно, надо думать), что даже можно было бы назвать какой-нибудь класс GameMaster — и это тоже был бы ubiquitous language.
G>Продолжаем мысленный эксперимент с софтом для МРТ. Предположим у нас не просто аппарат, а целая система, когда аппарат снимки на сервер сохраняет, а компьютер у врача, возможно совершенно в другому месте, отображает. Так вот по этой логике какой класс должен заниматься сохранением карточек\файлов МРТ на сервере и их считыванием на клиенте?
Класс сторонней библиотеки, разумеется. Называться он будет так, как его назовут разработчики облачного SDK. Даже если ты будешь писать его сам, не надо делать вид, что это всё ещё часть "софта для МРТ".
Здравствуйте, Alekzander, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
A>>>При этом важно то, что если подумать, всегда можно переписать код так, что хелперы исчезнут. Останутся только классы, отражающие предметную область. Функционал будет в них, и код станет гораздо лучше организован. G>>И это неправда.
A>Это я поленился уточнить: "эмпирическое утверждение по моим наблюдениям". У меня нет теории, из которой бы следовало, что это гарантировано возможно, а просто всегда как-то получалось. Ну и если посмотреть, например, на API крупных продуктов (всяких ОС), на стандартные библиотеки известных ЯП — то как-то и им это удаётся, что косвенно подтверждает. Это я объяснил, почему так считаю, обосновать я не могу.
Это означает что на каком-то подмножестве относительно простых задач это возможно, а в общем — нет. Задача, которую нарисовал липперт, вроде достаточно простая, но уже на ней возникли сложности DDD.
И если быть честным, то DDD хорошо работает, как раз на простых задачах.
Re[5]: Domain-Driven-Design и DataGridView не совместимы?
AJD>Я в свое время пытался найти, чем известен или чего достиг Эванс, помимо своей книги. Ничего не смог найти. А раз так, блог инженера/архитектора создавшего реальную рабочую систему имеет в разы большую ценность.
А каких вы знаете инженеров/архитекторов, которые создали реальную рабочую систему, и которые ведут блог на тему архитектуры?
Интересно было бы почитать.
Re[12]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, gandjustas, Вы писали:
A>>>>При этом важно то, что если подумать, всегда можно переписать код так, что хелперы исчезнут. Останутся только классы, отражающие предметную область. Функционал будет в них, и код станет гораздо лучше организован. G>>>И это неправда.
A>>Это я поленился уточнить: "эмпирическое утверждение по моим наблюдениям". У меня нет теории, из которой бы следовало, что это гарантировано возможно, а просто всегда как-то получалось. Ну и если посмотреть, например, на API крупных продуктов (всяких ОС), на стандартные библиотеки известных ЯП — то как-то и им это удаётся, что косвенно подтверждает. Это я объяснил, почему так считаю, обосновать я не могу.
G>Это означает что на каком-то подмножестве относительно простых задач это возможно, а в общем — нет.
Это означает, что я не могу доказать свою правоту за неразвитостью теории проектирования (и признаю это). Больше ничего.
И надо, наверно, подчеркнуть, что я не отстаиваю DDD в том виде, в котором в неё входят все эти агрегаты и прочие перечисленные паттерны. Только самый базовый принцип — код должен формулироваться в терминах предметной области.
>Задача, которую нарисовал липперт, вроде достаточно простая, но уже на ней возникли сложности DDD.
А давай-ка вернёмся к задаче Липперта. Я тут подумал над ней в свободное время... как я уже сказал, я очень его уважаю и найти ошибку в его рассуждениях для меня — ачивка 80-ого уровня. Сразу скажу: из спортивного интереса я пока не читал продолжение (чтобы сначала самому подумать), и не знаю, оставил ли он эту ошибку в учебных целях, или мне действительно удалось подловить маэстро.
Смотри. Эрик жалуется, что после очередного изменения в коде компилятор перестал проверять правильность отношений между мечом, посохом, магом и воином. Проверка переехала в рантайм, а это плохо. Правильно? Или я не так понял?
Так вот: отношения между мечом, посохом, магом и воином — это игровая логика. Она постоянно меняется — в целях достижения игрового баланса, например. Или чтобы тупо было интереснее играть. И во многих других случаях. Поэтому в реальном мире люди зачастую начинают писать одну игру, а заканчивают совсем другую. И это же распространяется и на софт класса... как он там его назвал?.. Papers and Paychecks. Просто "wizards and warriors are more fun to write about". Значицца, игровая логика в реальных проектах меняется постоянно. Как же так получается, что столь изменчивую вещь мы фиксируем настолько, что её аж должен ПРОВЕРЯТЬ КОМПИЛЯТОР, а проверок в рантайме недостаточно? Учитывая, насколько она изменчива по своей природе, её даже в рантайме проверять (выбрасывая исключения) не надо — как описали, так и описали, просто грузи, проверяй, и разрешай или запрещай персонажу взять предмет. По сути, это тоже самое, что заставить компилятор проверять, что у нас иконка прямоугольная.
Здравствуйте, Alekzander, Вы писали:
A>Здравствуйте, samius, Вы писали:
S>>Хорошо, а если подумать, то где должен быть расположен код считывания карточки, выполняющей функцию мультиметода, как у Липперта? В оружии?
A>Не понял вопрос. Можно процитировать код Липперта и ткнуть пальцем?
Можно, но не нужно. Это то место, где у него отношения между монстром, персонажем, оружием, локацией и фазой луны. Если об таком отношении написано в карточке, то в каком классе должно написать код чтения карточки, что бы не нарушить высокоуровневый принцип и у нас нет хелперов?
Re[13]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, Alekzander, Вы писали:
A>Так вот: отношения между мечом, посохом, магом и воином — это игровая логика. Она постоянно меняется — в целях достижения игрового баланса, например. Или чтобы тупо было интереснее играть. И во многих других случаях. Поэтому в реальном мире люди зачастую начинают писать одну игру, а заканчивают совсем другую. И это же распространяется и на софт класса... как он там его назвал?.. Papers and Paychecks. Просто "wizards and warriors are more fun to write about". Значицца, игровая логика в реальных проектах меняется постоянно. Как же так получается, что столь изменчивую вещь мы фиксируем настолько, что её аж должен ПРОВЕРЯТЬ КОМПИЛЯТОР, а проверок в рантайме недостаточно? Учитывая, насколько она изменчива по своей природе, её даже в рантайме проверять (выбрасывая исключения) не надо — как описали, так и описали, просто грузи, проверяй, и разрешай или запрещай персонажу взять предмет.
Логика меняется независимо от кода программы? Или все-таки логика это часть кода программы. Почему во втором случае не стараться сделать её проверяемой при компиляции?
A>По сути, это тоже самое, что заставить компилятор проверять, что у нас иконка прямоугольная.
Картинка это внешние данные, о которых компилятор не знает. Но после получения и валидации внешних данных и создания класса RectangularIcon весь остальной код может рассчитывать на то, что иконка прямоугольная. В этом и суть абстрации, ООП дает инструменты абстракции в виде классов.
Re[14]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, gandjustas, Вы писали:
A>>Так вот: отношения между мечом, посохом, магом и воином — это игровая логика. Она постоянно меняется — в целях достижения игрового баланса, например. Или чтобы тупо было интереснее играть. И во многих других случаях. Поэтому в реальном мире люди зачастую начинают писать одну игру, а заканчивают совсем другую. И это же распространяется и на софт класса... как он там его назвал?.. Papers and Paychecks. Просто "wizards and warriors are more fun to write about". Значицца, игровая логика в реальных проектах меняется постоянно. Как же так получается, что столь изменчивую вещь мы фиксируем настолько, что её аж должен ПРОВЕРЯТЬ КОМПИЛЯТОР, а проверок в рантайме недостаточно? Учитывая, насколько она изменчива по своей природе, её даже в рантайме проверять (выбрасывая исключения) не надо — как описали, так и описали, просто грузи, проверяй, и разрешай или запрещай персонажу взять предмет.
G>Логика меняется независимо от кода программы?
Именно так.
Представим себе, что тестировщики говорят перед релизом: какой-то слабый воин у нас получается. А маг имбовый. Если мы так всё и оставим, никто не будет играть за воина, только за мага. Дизайнеры думают: надо что-то поменять... а не разрешить ли ему брать и посох? Других отличий между ними хватает ведь. И что — им, чтобы проверить своё предположение, надо идти к программистам и просить изменений в код? Через тикеты в Джире? Представляешь, во что превратится такой процесс разработки?
Или — другой пример — как потом моддерам писать моды, если всё в код зашито? Для игр это тоже очень важно.
Слова "игровая логика" не должны сбивать с толку, потому что это с тем же успехом можно назвать "игровой дизайн".
Чтобы до этого додуматься, можно даже не работать в геймдеве, а просто поиграть в Heroes. Или в Dark Messiah of Might and Magic. Мне кажется, в этом и был корень ошибки — в магах и мечах тоже надо разбираться, прежде, чем приводить в пример. (При всём уважении!)
A>>По сути, это тоже самое, что заставить компилятор проверять, что у нас иконка прямоугольная. G>Картинка это внешние данные, о которых компилятор не знает. Но после получения и валидации внешних данных и создания класса RectangularIcon весь остальной код может рассчитывать на то, что иконка прямоугольная. В этом и суть абстрации, ООП дает инструменты абстракции в виде классов.
Смысл сравнения с прямоугольной иконкой в том, что программе (объективно!) абсолютно начихать на её форму. Не начихать может быть менеджеру. Он может сказать: сейчас в моде прямоугольный дизайн, и поэтому рассматривайте форму иконки как бизнес-требование. А чтобы вам было легче рассматривать, давайте заставим компилятор её проверять. Технически это можно сделать — Post Build Steps, Continuous Integration, вся фигня — но разумно ли это?
Архитектор, по идее, должен понимать, какие идеи являются контрактами, которые надо закреплять в коде, а какие — нет.
Re[15]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, Alekzander, Вы писали:
A>Или — другой пример — как потом моддерам писать моды, если всё в код зашито? Для игр это тоже очень важно.
Может показаться, что НА САМОМ ДЕЛЕ это не очень важно. Вот компании Blizzard так однажды и показалось — и сегодня миллионы на DotA зарабатывает Valve. Но там, насколько я в курсе, проблемы были не с архитектурой, а с тупоголовыми менеджерами. Архитектура вполне позволяла изменять игровую логику после релиза (и без доступа к исходникам).
Counter-Strike, Team Fortress — это всё тоже когда-то начиналось как моды.
Благодаря открытой архитектуре Valve снизила нагрузку на собственные Left4Dead сервера (которые чистый убыток при фиксированной цене игры), потому что в ваниль сегодня всем скучно играть. Авторы модов поднимают свои сервера, и оплачивают их с донатов.
Моды — это, на самом деле, отрасль экономики с многомиллиардными оборотами.
Re[12]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, samius, Вы писали:
S>>>Хорошо, а если подумать, то где должен быть расположен код считывания карточки, выполняющей функцию мультиметода, как у Липперта? В оружии?
A>>Не понял вопрос. Можно процитировать код Липперта и ткнуть пальцем? S>Можно, но не нужно. Это то место, где у него отношения между монстром, персонажем, оружием, локацией и фазой луны. Если об таком отношении написано в карточке, то в каком классе должно написать код чтения карточки, что бы не нарушить высокоуровневый принцип и у нас нет хелперов?
Именно чтения? В классе сериализатора (например). Естественно, внешнего по отношению к нашему проекту.
Re[13]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, Alekzander, Вы писали:
A>Здравствуйте, samius, Вы писали:
S>>Можно, но не нужно. Это то место, где у него отношения между монстром, персонажем, оружием, локацией и фазой луны. Если об таком отношении написано в карточке, то в каком классе должно написать код чтения карточки, что бы не нарушить высокоуровневый принцип и у нас нет хелперов?
A>Именно чтения? В классе сериализатора (например). Естественно, внешнего по отношению к нашему проекту.
Могло бы быть отличным ходом, если бы внешний к нашему проекту проект умел бы обращаться с логикой нашего проекта. Но боюсь, если внешний проект начнет понимать, что такое оборотень, палладин и полнолуние, то это будет не такой уж и внешний проект. Внешний проект может дать нам XML, JSON или какое-то другое представление (табличное, например), далекое от сущностей нашего высокоуровневого дизайна. Все еще кому-то надо разобрать токены (или что там) представления карточки и вкорячить их в сущности нашего проекта, если мы хотим избежать того, что бы код нашего проекат бегал бы по представлению данных внешнего по отношению к нам проекта при обработке каждого действия/взаимодействия сущностей нашего проекта.
Кроме того, мне очень не понятно, почему сильная связность с внешним проектом лучше, чем связность с внутренним хелпером. Если бы это было действительно так, то все хелперы можно было бы размазать по "внешним" проектам и типа, этот говнокод не мой говнокод, у меня все высокоуровнево.
Re[14]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, samius, Вы писали:
S>>>Можно, но не нужно. Это то место, где у него отношения между монстром, персонажем, оружием, локацией и фазой луны. Если об таком отношении написано в карточке, то в каком классе должно написать код чтения карточки, что бы не нарушить высокоуровневый принцип и у нас нет хелперов?
A>>Именно чтения? В классе сериализатора (например). Естественно, внешнего по отношению к нашему проекту. S>Могло бы быть отличным ходом, если бы внешний к нашему проекту проект умел бы обращаться с логикой нашего проекта. Но боюсь, если внешний проект начнет понимать, что такое оборотень, палладин и полнолуние, то это будет не такой уж и внешний проект. Внешний проект может дать нам XML, JSON или какое-то другое представление (табличное, например), далекое от сущностей нашего высокоуровневого дизайна. Все еще кому-то надо разобрать токены (или что там) представления карточки
Я же спросил: "Именно чтения?". Чтобы отделить сериализацию от разбора давно придуманы способы типа SAX или построения DOM.
Если совсем просто: для сериализатора "possible_owners" и "wizard,warrior" это просто пара строк ключ-значение. А для класса предмета — это данные, на основе которых он вычисляет bool CanObtain().
Я другого не пойму: что вы все с этой сериализацией докопались до меня? Наличие классов Wizard и Warrior — это грубейшая ошибка проектирования, вызванная бездумной, механической, неудачной попыткой следовать принципу "Designing good class hierarchies is all about capturing the semantics of the business domain in the type system", а вопросы при этом задают мне и про сериализацию.
Здравствуйте, Alekzander, Вы писали:
A>Здравствуйте, samius, Вы писали:
A>Я же спросил: "Именно чтения?". Чтобы отделить сериализацию от разбора давно придуманы способы типа SAX или построения DOM.
A>Если совсем просто: для сериализатора "possible_owners" и "wizard,warrior" это просто пара строк ключ-значение. А для класса предмета — это данные, на основе которых он вычисляет bool CanObtain().
A>Я другого не пойму: что вы все с этой сериализацией докопались до меня? Наличие классов Wizard и Warrior — это грубейшая ошибка проектирования, вызванная бездумной, механической, неудачной попыткой следовать принципу "Designing good class hierarchies is all about capturing the semantics of the business domain in the type system", а вопросы при этом задают мне и про сериализацию.
Я пытался понять, где же должен быть расположен "код считывания констрейнтов на оружие", если расположение его в "отдельном хелпере" нарушает "высокоуровневые принципы". Ну и походу выяснил, что вместо расположения кода в хелпере высокоуровневые принципы предпочитают DOM и непрограммистов с редактором ресурсов.
А если взять правильный DOM, правильный редактор ресурсов и правильного непрограммиста, то и программисты с хелперами не нужны. Главное — непрограммисту про DDD не рассказывать.
Re[16]: Domain-Driven-Design и DataGridView не совместимы?
S>Я пытался понять, где же должен быть расположен "код считывания констрейнтов на оружие", если расположение его в "отдельном хелпере" нарушает "высокоуровневые принципы". Ну и походу выяснил, что вместо расположения кода в хелпере высокоуровневые принципы предпочитают DOM ...
DOM — это что такое?
Document Object Model?
Re[17]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, zelenprog, Вы писали:
S>>Я пытался понять, где же должен быть расположен "код считывания констрейнтов на оружие", если расположение его в "отдельном хелпере" нарушает "высокоуровневые принципы". Ну и походу выяснил, что вместо расположения кода в хелпере высокоуровневые принципы предпочитают DOM ...
Z>DOM — это что такое? Z>Document Object Model?
Здравствуйте, samius, Вы писали:
S>А если взять правильный DOM, правильный редактор ресурсов и правильного непрограммиста, то и программисты с хелперами не нужны.
Абыдно, да?
Многие начинают путь в нашей профессии со знакомства с играми про волшебников и магию, и думают, что программировать их будет так же весело, как и играть в них. А на деле оказывается, что движок просто процессит карточки, а всё веселье, как всегда, достаётся пользователям (игровые дизайнеры это пользователи движка, хотя и не конечные).
Поэтому, когда тебя приглашают в игровую студию в команду движка, никто не говорит, что тебя ждёт мир мечей и магии. Тебе говорят: увидишь своё имя в титрах, бесплатные котлетки с пюрешкой, и проездной на метро.
Но в глубине души люди продолжают верить в сказки, и пишут статьи про ООП и DDD с мечами и магами.
Здравствуйте, Alekzander, Вы писали:
A>Здравствуйте, samius, Вы писали:
S>>А если взять правильный DOM, правильный редактор ресурсов и правильного непрограммиста, то и программисты с хелперами не нужны.
A>Абыдно, да?
Кому? Я не занимаюсь моделированием поведения сущностей домена, т.к. не нахожу это полезным или интересным.
A>Многие начинают путь в нашей профессии со знакомства с играми про волшебников и магию, и думают, что программировать их будет так же весело, как и играть в них. А на деле оказывается, что движок просто процессит карточки, а всё веселье, как всегда, достаётся пользователям (игровые дизайнеры это пользователи движка, хотя и не конечные).
A>Поэтому, когда тебя приглашают в игровую студию в команду движка, никто не говорит, что тебя ждёт мир мечей и магии. Тебе говорят: увидишь своё имя в титрах, бесплатные котлетки с пюрешкой, и проездной на метро.
A>Но в глубине души люди продолжают верить в сказки, и пишут статьи про ООП и DDD с мечами и магами.
Не вижу ничего плохого в сказках. Статья не стала бы лучше, если бы в ней был пример на тему Студент.Учись, Поциент.Лечись, Штраф.Оплачивайся, Кредит.Возвращайся. Сказка здесь не в том, что в предметной области появились мечи и маги. А в том, что моделирование поведения сущностей доменной области в ООП и DDD имеет какой-то практический смысл в задачах, цель которых не заключается именно в моделировании поведения.
Re[18]: Domain-Driven-Design и DataGridView не совместимы?
Здравствуйте, samius, Вы писали:
S>>>А если взять правильный DOM, правильный редактор ресурсов и правильного непрограммиста, то и программисты с хелперами не нужны.
A>>Абыдно, да? S>Кому? Я не занимаюсь моделированием поведения сущностей домена, т.к. не нахожу это полезным или интересным.
За профессию. Потому, что ты всё правильно написал: никакие программисты с хелперами тут не нужны. И без хелперов не нужны. Для выстраивания отношений персонажей и шмота в рамках игры вообще не нужны программисты.
A>>Многие начинают путь в нашей профессии со знакомства с играми про волшебников и магию, и думают, что программировать их будет так же весело, как и играть в них. А на деле оказывается, что движок просто процессит карточки, а всё веселье, как всегда, достаётся пользователям (игровые дизайнеры это пользователи движка, хотя и не конечные).
A>>Поэтому, когда тебя приглашают в игровую студию в команду движка, никто не говорит, что тебя ждёт мир мечей и магии. Тебе говорят: увидишь своё имя в титрах, бесплатные котлетки с пюрешкой, и проездной на метро.
A>>Но в глубине души люди продолжают верить в сказки, и пишут статьи про ООП и DDD с мечами и магами. S>Не вижу ничего плохого в сказках. Статья не стала бы лучше, если бы в ней был пример на тему Студент.Учись, Поциент.Лечись, Штраф.Оплачивайся, Кредит.Возвращайся. Сказка здесь не в том, что в предметной области появились мечи и маги. А в том, что моделирование поведения сущностей доменной области в ООП и DDD имеет какой-то практический смысл в задачах, цель которых не заключается именно в моделировании поведения.
Я к тому, что мечи и маги это тоже работа. И в ней тоже надо думать. И решение часто оказывается очень скучным. А если погнаться за весёлым, оно именно поэтому может оказаться неверным (как и произошло). Это случается чаще, чем многие думают. Вон по соседству тряпку полощут — двадцать ответов уже, и ни одного правильного.
P.S. Если не гнаться за весельем, это, к сожалению, тоже не гарантирует правильных ответов. Что и доказывают примеры "Студент.Учись, Поциент.Лечись, Штраф.Оплачивайся, Кредит.Возвращайся" (не зная деталей, я бы, увидев такое, решил, что с вероятностью, близкой к единице, это ошибка проектирования).