Balancer: Все сообщения за 24 Июля 2007 года

 
ПнВтСрЧтПтСбВс
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

Balancer

администратор
★★★★★
В XML - сила. Но у нас стоит задача минимизации трафика :)

Вообще, есть в качестве примера для подражания протколы L2 и WoW. Где, скажем, пакет CharMoveToLocation (один из самых часто посылаемых) занимает 29 байт (код операции + код объекта + 3 координаты исходной точки + 3 координаты конечной). В то время, как в XML он же будет занимать уже под две сотни байт:
code xml
  1. <packet action="CharMoveToLocation">
  2. <object_id>123456</object_id>
  3. <from>
  4. <x>123456</x>
  5. <y>56789</y>
  6. <z>-1234</z>
  7. </from>
  8. <to>
  9. <x>123499</x>
  10. <y>56789</y>
  11. <z>-1234</z>
  12. </to>
  13. </packet>


Итого - шестикарнтый проигрышь по трафику на таком простом примере. А даже бинарный протокол на не самом загруженном L2-сервере уже в упор забивает стомегабитные каналы на сервере и едва хоть как-то позволяет играть на хороших модемах.

С переходом на XML с той же загрузкой придётся улучшать серверные каналы до гигабита, а от юзеров с каналом меньше 256к - просто отказываться :)

Кроме того, у нас даже бинарный пакет будет больше размером (координаты придётся делать long, object_id - тоже не меньше long'а, если вообще не строкой...)
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★
Вот не понимаю я паранойи последнего времени на тему избавления новых языков от множественного наследования.

Вот уткнулся сейчас в проблему вообще в банальном PHP...

Задача - есть набор классов (с большим набором методов) тех или иных web/db-ресурсов. Это может быть простой ORM-маппинг, может быть дерево, хитро извлекаемое из БД, список...

Их наследники - конкретные типы объектов. Грубо говоря - простая страничка сайта, или вывод сложной формы...

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

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

Пока нам хватает стандартных настроек - всё прекрасно.

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

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

Но что делать, когда страницы должны принадлежать разным базовым классам??

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

А вот без него - фиг.

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

Как быть-то?
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★
AlexZr> Подскажите пожалуйста что храниться в таблице accounts колонка Comments?

"Русскаго языка" когда будем учить?

После долгой расшифровки было получено примерно следующее: "Подскажите пожалуйста, что хранится в колонке Comments таблицы accounts?"

Это имелось в виду?

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

Balancer

администратор
★★★★★
В том-то и дело, что интерфейсы мне вообще неинтересны (в PHP они просто не нужны, ты можешь вызывать любой метод любого класса, если он описан хоть где-то, если его нет - ошибку получишь во время исполнения).

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

Один - собственно, основная работа класса (данные страницы, заголовок и т.п.)

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

В принципе, я задачу сейчас решил, но - костылём. Загрузчик классов проверяет наличие в том же каталоге, откуда грузится нужный класс файла другого класса с зарезервированным именем и при его наличии - грузит и инициализирует, передавая в качестве параметра только созданный наш объект. Поскольку (повезло) все общие параметры конечных классов в этом частном случае можно задать через set-методы, то этот вторичный "класс-инициализатор" этим занимается. А все классы данной категории сайта лежат в одном каталоге, так что и инициатор для них - тоже один.

К сожалению, это очень частный случай.

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

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

В общем, куда ни кинь - одни костыли выходят.

И ради чего? Ради отказа от естественного представления объектов в окружающем мире.

Яблоко - это растение, объект зелёного цвета, пища.

Звезда - это астрономический объект, природный термоядерный реактор, центр планетарной системы...

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

И ООП, которое изначально сделало шаг в этом направлении, потом за совершенно неадекватными оговорками делает шаг назад и начинает вводить костыли в виде интерфейсов, композиций и т.п....

Главный (и единственный?) аргумент против множественного наследования - неоднозначности в случае появления одинаковых методов у разных родителей.

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

Так откуда тогда могут взяться неоднозначности?

Мне, всё же кажется, что тут у народа какой-то массовый заскок.
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★
Возможно, в отрыве от практики задача выглядит непонятно, постараюсь показать (упрощённо) ключевые моменты кода:

1. Есть базовый класс "страница сайта", содержащий массу методов, возвращающих параметры страницы (из которых система потом и собирает эту страницу):
title() - заголовок страницы
description() - её описание
source() - текст
body() - скомпилированный (разметка -> html) текст, по умолчанию сам собирается из source()
create_time() - дата создания
modify_time() - дата изменения
и т.д. и т.п.

У базовой страницы методы в основном абстрактные, но у неё куча наследников. Страницы, которые извлекают данные из файлов файловой системы, страницы, которые извлекают данные и базы данныех и т.п.

Извлечение из БД может идти тоже разными способами, это могут быть простые плоские данные, когда текст страницы берётся из некой таблицы, скажем, текст постинга на форуме по его ID. Может быть построение дерева из данных дерева категорий, заданного в виде графа, могут быть списки и т.п.

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

В случае множественного наследования проблем нет. Скажем, наш список наследует классы def_dbtree и my_section и в нём пишется, подчас, буквально несколько строк кода. Запрос, генерирующий данные для дерева (само дерево соберётся методами из def_dbtree, которые будут делать этот запрос), небольшая подстройка данных по умолчанию в my_section (скажем, у всех страниц единый ID баннера в баннерной сети, но для отдельного класса страниц он должен быть иной).

Но у нас множественного наследования нет.

Что можно предложить взамен?

Композиция отпадает сразу. Потребуются обёртки для многих десятков параметров.

Копипаст?

Мой вариант с вторичным инициализатором в конкретных условиях?

Костыли, одни костыли...
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★
timochka> Рома, объем кода давно никого не пугает, пугает сложность. Т.е. много простого кода лучше чем мало сложного.

Меня пугает. Если мне для реализации класса, который в ином случае реализуется в 10 строк, придётся писать 100 строк, то на весь проект вместо месяца работы мне понадобится год. А та же Авиабаза в нынешнем варианте потребовала бы уже не 10 лет экспериментов, а 100 лет :D

Как раз объём кода (утрированно, естественно) - это то, за чем упорно гонится весь программистский мир за последние лет 30 :) Каждое повышение уровня языка заключается в том, чтобы как можно меньшими усилиями реализовать как можно больший функционал. Одно из важных требований для осуществления этой задачи - как раз повышение функциональной насыщенности кода.

В противном случае до сих пор бы все программировали в машинных кодах :D

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

Видишь ли, я как раз уже нарывался несколько на эти проблемы именно в групповой разработке на Java :) Когда вместо простого и наглядного решения через множественное наследование приходилось добавлять никому непонятные костыли.

timochka> 1) Для влезания в середину существующего кода желательно изучать как можно меньше. Т.е. разлишные модули должны быть слабо связанны.

Множественное наследование этому никак не мешает.

timochka> 2) Для того что-бы переиспользовать существующую реализацию нельзя требовать изучения толстого унаследованного API (крайне желательно перечислить большинство методов объекта прямо в классе реализации).

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

Ведь точно такая же проблема вылезает, скажем, в той же Java при импорте. Совершенно разные классы разных пакетов могут иметь одно имя и может вылезать конфликт имён при массовом испорте сторонних пакетов. Компилятор в этом случае просто ругается и программист уточняет, чей конкретно класс он имел в виду.

Почему для имён классов такой подход допустим, а для имён методов в случае множественного наследования - нет?

timochka> 3) У множественного наследования есть еще проблема с многократным наследованием реализации (и данных) одного базового класса от нескольких родителей

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

timochka> В большом коллективе 80% работы это задачи типа есть неправильное поведение в таком-то случае.

Компилятор способен в 100% случаев отловить проблемы множественного раследования. Как он отлавливает те же проблемы со "множественным импортом".

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

timochka> Поэтому считают что лучше явно прописать все методы в классе при агрегации, чем полагаться на унаследованную реализацию.

При пропагандируемом сейчас принципе максимального рефакторинга получается полнейший бред. Приходится писать в 10 раз больше кода, при этом в 10 раз возрастает риск пропустить ошибку. Ежу понятно, что любой типичный программист начинает делать копипаст. И вместо:
code cpp
  1. int modify_time() { return parent2->modify_time(); }
  2. int create_time() { return parent2->create_time(); }


мы получим:

code cpp
  1. int modify_time() { return parent2->modify_time(); }
  2. int create_time() { return parent2->modify_time(); }


И ошибку такого рода отлавливать будем очень долго. Я сам на эти грабли (в немного более сложных случаях, естественно, но таких же по принципу) наступал несколько раз.

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

Balancer

администратор
★★★★★
Скорее всего, в будущем система и будет на Питоне.

Но будет это не раньше, чем Питон массово появится на виртуальных хостингах :) Пока же это, ИМХО, в принципе невозможно. На сколько я знаю, никакая из реализаций связки Питон + веб-сервер не обеспеивает per-user виртуального хостинга :-/
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★


// Взято с _ransom: Жесть
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★
timochka> Считается, что ошибки не от опечаток (это проверит компилятор)

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

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

Balancer

администратор
★★★★★
Wyvern-2> Странник - Адольф Виссарионович Полпот фон Штирлиц-Исаев :)

Надо же было так смешать ТИМы "Гамлета", "Максима Горького", не знаю кого и, собственно, "Штирлица" :D Ну ничего в них общего нет :-p
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Balancer

администратор
★★★★★
Сергей-4030> Ничего подобного, с какой стати? ОК, есть обьект "страничка". Иногда статическая. Иногда динамическая, ис БД. ОК, наша страничка имеет ссылкы на DataProvider . Где ты увидел удвоение классов?

Ну вот. У меня есть наворочанная система, использующая прямые вызовы. Да, идея с DataProvider в голову приходила. Но:
- Есть тонны кода, который придётся тупо переписывать.
- Получаем заметное падение производительности, поскольку у нас появляется лишняя операция извлечения этого DataProvider.
- Наконец, придётся переписать всю систему шаблонов, так как используемая не понимает метода от метода для класса. Ну вот такие у Smarty ограничения.

Итого - имеем человекомесяц лишней работы... Да проще уж, действительно, всё на Python переписать, где это множественное наследование есть :D Объём работы сопоставим будет. И перспективы, опять же...

Сергей-4030> Что такое "текужее представление"?

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

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru