9 июля 2010 в 12:37

13 антисоветов разработчику, желающему написать хороший веб-сайт

PHP*
Привет, разработчики на хабре!

Этот шуточный пост составлен из проблем, с которыми приходится сталкиваться практически постоянно при сопровождении больших и серьезных сайтов.
Это не пост ненависти! Это призыв к прекращению траты своего и чужого времени на исправление неочевидных при первоначальной разработке и использовании проблем.

1. Не проставляйте ключи!


СУБД пишут умные люди. Некоторые из них даже получают за это деньги. Зачем подсказывать им, как устроены данные? Пускай догадываются сами из названий полей и самих данных. В крайнем случае, админы поправят профайлером.


2. Используйте строковые PK вместо числовых!


Ведь использовать 12345 — некрасиво и небезопасно! Намного красивее и безопаснее — 098f6bcd4621d373cade4e832627b4f6. И ни в коем случае не стоит создавать таблицу соответствия строка->int и пользоваться номером в остальных таблицах! СУБД интереснее выбирать по строке, чем по какому-то сухому, скучному и непонятному числу.
Кстати, строку надо генерировать как md5() от ip-адреса клиента, текущего времени и Вашего ника. Пользователи NAT'a поблагодарят.

3. Не используйте таймауты!


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

4. Используйте system()!


Это гарантирует Вам переносимость — вдруг кто-то из команды разработчиков языка решит удалить используемую Вами функцию? А консольные аналоги всегда останутся при Вас. Кроме того, несколько форков на обработку запроса — это столько интересной работы планировщику!

5. Не думайте об алгоритмах!*


Если Вам надо найти что-то в отсортированном массиве — пройдитесь по нему по порядку! Больше данных увидите. Тем более, бинарный поиск как-то непонятно работает. Если Вам надо найти подстроку в строке — просравнивайте все, с начала до конца! Странные линейные алгоритмы могут ошибаться.
* На самом деле, надо правильно выбрать баланс между написанными в стандартной библиотеке неэффективными алгоритмами и написанием своего кода. Если Ваша реализация эффективного займет больше трех страниц кода, то надо использовать именно ее, меньше — готовую функцию.

6. Кладите информацию в файл!


Конечно, есть СУБД, но и она неидеальна: просит какие-то странные команды. Нет, чтобы просто дать контент! Обычные файлы намного лучше. Да и админу будет интереснее поднимать кластер с rw /home на кластерной ФС, чем с ro /home на обычной.
Напротив, картинки надо класть в базу и отдавать скриптом — как же тогда контроллировать безграничное скачивание статики?

7. Пользуйтесь модулями, заброшенными в 2006 году!


Действительно, что с тех пор изменилось, да и вообще, изменится? Внутренний API — вещь стабильная. Ну а если там были какие-то изменения, то команда с удовольствием их изучит и получит полезные знания, заставляя этот модуль скомпилироваться и заработать.

8. Пишите рерайты!


Много рерайтов! Пишите изящные, занимающие два экрана инструкции апачевскому mod_rewrite с обратной логикой, RewriteCond'ами и специфичными особенностями. Никогда не сопоставляйте префикс какому-то отдельному скрипту. Веб-серверу интересно матчить каждый запрос по сотне регекспов, выделять в них что-то и вызывать Ваши программы. А админу интересно переписывать их в нормальный вид и на другой веб-сервер.

9. Для авторизации и сессии используйте одну и ту же куку!


Вообще, любой порядочный скрипт должен начинаться с session_start(). Если пользователь авторизовался, то об этом надо сделать пометку в $_SESSION. Пускай фронтэнд сам догадывается, отдавать кешированный ответ, или идти к Вашему скрипту.

10. Обижайтесь, когда Вас не пускают на продакшн!


Вы достаточно хорошо умеете программировать, чтобы править сайт на работающем сервере. На работающем сервере нет FTP? Надо поставить! Работающих серверов несколько? Так за счет пункта 6 Вам поставили кластерную ФС! Код надо тестировать перед публикацией? Ну вылетит ошибка, сразу поправите!
Не используйте систему управления версиями. Откатываются из бекапов, а не из непонятных программ.

11. Не выносите код за пределы DocumentRoot!


Всякие ваши cgi-bin придумали странные глупые люди, которые ничего не понимали в сайтах. Намного лучше, когда выполняется не все из cgi-bin, а все из /, соответствующее регекспу ~ \.php. Не забудьте о замечательной фиче, как path_info — ведь это круто, когда скрипт выглядит как папка! А с тем, чтобы upload/avatar.php.jpg не запускался, как-нибудь разберется и админ.

12. Выполняйте долгие действия внутри клиентского запроса!


Памяти у сервера много, времени у клиента — тоже. Так почему бы не заресайзить 100 картинок из resize.php, запрашиваемого пользователем? Буферизация, не дающая выводить по одной точечке на фотографию? Кривой сервер. Клиентские таймауты? Кривой клиент. Очередь долгих операций — слишком накладно и непонятно клиенту.

13. Не используйте средства вебсервера!


Его писал непонятно кто, мог набажить. Если Вам надо отдать клиенту файл с ограничением по скорости и проверкой куки, забудьте о X-Accel-Redirect+X-Accel-Rate-Limit/X-Sendfile! Отдавайте его своим скриптом, в цикле, по кусочкам. Для ограничения скорости используйте sleep(). Если Вам надо проверить, что картинки не личатся, зарерайтите их на свой скрипт и отдавайте их только после проверки реферера.

Disclaimer


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

Не знаю, в какой блог правильнее разместить, разместил в PHP, так как советы, в основном, относятся к писателям на этом языке.
Boris @borisko
карма
49,7
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (101)

  • +4
    А это действует только на PHP?
    • +3
      Вам никто не мешает применять все это на любом другом языке :))
    • +1
      Нет, поэтому внизу и приписка. Не нашел подходящего блога — ни высокая производительность, ни серверная оптимизация как-то не получаются.
  • +4
    Улыбнуло.
    Понимаю — накипело. Особенно когда сталкиваешься с этим регулярно.
  • +4
    Ещё, в дополнение к правилу 2, языковые сообщения в мультиязычных системах пишите номерами, кодами, а никак не мнемоническими именами на английском типа $getText('Login'), $getText('I-m-alpply'). Гораздо проще просто пронумеровать: $getText(4), $getText('89'), а последующие разработчики сами легко найдут тексты в таблице.
  • +34
    Когда-то давным давно на каком-то ресурсе кто-то написал подобный пост. Потом его решили перевести на другие языки. Но т.к. русский велик и могуч, а тега irony еще не было, то в Индию и Китай этот текст попал как инструкция.
  • –12
    Между прочим, часть советов, вполне имеет право на существование в некоторых случаях.
    А вот это вообще убило: «Кстати, строку надо генерировать как md5() от...». Когда уже похапешники перестанут считать, что MD5 — это строка из 32 символов? MD5 — это хэш-функция, возвращающая 128 бит (16 байт).
    • +6
      md5() — конкретное название конкретной функции, трансформирующей одну строчку в другую по каким-то непонятным правилам. Именно поэтому и стоят скобочки. Правила легко могут быть и алгоритмом хеширования.

      ru2.php.net/md5:
      string md5 ( string $str [, bool $raw_output = false ] )
      Returns the hash as a 32-character hexadecimal number.

      • +3
        Чтобы правила стали понятными, стоит ознакомиться с ru.wikipedia.org/wiki/Md5 ;-)
  • +1
    А где самый главный совет: «пишите велосипедов больше красивых и разных!»
    • 0
      Он под звездочкой в совете 5. Правда, ему как-то мало выделилось места :-(
      • –3
        надо перестать читать по диагонали :)
        • 0
          надо просто начинать читать :)
  • +2
    В крайнем случае, скрипт убьет система
    насяльника промта бешельме мешельме

    6. Кладите информацию в файл!

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

    Да и как-то всё смешалось и ДБА и программирование на пхп.
    • 0
      Пожалуйста, не надо.
      Некоторые принимают это за серебряную пулю, и после этого то, что должно быть в реляционной БД люди мне присылают в виде XML на миллион элементов. А отношения между ними «сам восстанови, там же есть номера что с чем в отношении».
      • +1
        Но согласитесь же, то что не влазит в кеш в базы данных — лучше хранить в файле, чем собирать из нескольких таблиц.
        • +1
          Я соглашусь, но меня приводит в уныние то, что люди где-то прочитали о том что XML-благо, не поняли того, что хотел сказать автор, и после этого миллион сложных однотипных элементов (Ну если быть точнее — 3 типа разных элементов) вместо того чтобы сразу быть добавленными в БД из исходных файлов с данными (doc) — они конвертятся в промежуточный XML (который ничуть не лучше чем исходник выходит) и потом я уже должен эти XML добавлять в БД, в которой они собственно и будут активно использоваться.
          Среди моих знакомых «программистов» просто мания какая-то на XML, причем даже работать они с ним при этом не умеют абсолютно.
          Просто грустно, надеюсь если кто-то будет читать эту ветку — хоть не будет так бездумно совать XML где ни попадя…
          • +1
            согласен с вами. применять его [xml] нужно с умом. совсем недавно столкнулся с небольшой cms (самописная под сайт), где данные хранились именно в xml. Оправданно было бы, если бы там не было mysql, да и то на такой случай есть sqlite. А так это неуважение к другим разработчикам — написать не думая о последующей поддержке.
      • +3
        Ну бывает и вообще великолепный вариант, когда в базе хранится XML. Порой просто огромного размера, чтоб его и поредактировать стандартными средствами работы с базой данных было б никак. Пусть последующие разработчики сделают какие-нить специальные инструменты, чтоб какую-нить мелкую фитюлинку поменять.

        А вообще по поводу баз данных добавил бы ещё пунктиков

        N. Храните всю разметку в базе данных — база ж для данных предназначена! Значит все таблицы, фонты, цвета и размеры должны быть там!

        N+1. Гораздо удобнее все данные хранить в одной таблице. Ну и что, что из 300 полей в каждой записи будут задействованы только 10-20?! Зато всегда понятно, в какой таблице данные надо искать.

        N+2. Для каждого селекта, инсерта и апдейта надо делать отдельную процедуру. Когда число процедур в базе перерастает три сотни, начинаешь по особому чувствовать свою значимость!

        N+3. Никогда при вставке значений в таблицу не перечисляй поля! Никогда! Только значения! И если какой-то лопух попытается потом таблицу изменить, пусть ка найдёт все твои процедуры, которые в эту таблицу что-то писали, а теперь падают из-за несоответствия типов или несовпадения количества параметров! Пусть почувствует всю глубину своего падения. А то наставят порой дефолтных значений, думают, что их это защитит…
        • 0
          А у меня обратная ситуация, непонятно зачем мне предоставили схему БД в которой одинаковые данные хранятся в двух разных БАЗАХ (нет, не таблицах, в двух разных базах!) и при этом логически между ними настолько тесная связь, что нужна одна таблица и дополнительное поле — флаг (а если подумать то и оно не нужно).
          • 0
            Ну из этого можно сделать обратный совет —

            N+4. все данные должны храниться в разных таблицах и связываться длинными строковыми ключами. Так же красивее :)

            Естественно, везде нужен здравый смысл. Но нормализацию базы проводить всё же надо, имхо :)
            • +1
              Здесь речь не о нормализации уже (разделили реально не по таблицам даже, а по базам), и при нормализации как раз всё равно эти данные в одной таблице.
              • 0
                Ну, судя по всему, Вы согласны с тем, что нормализация нужна? Важно, чтоб её результатом было повышение эффективности, а не просто «разделение данных, потому что так в книжках пишуть». Я правильно Вас понима?
                • 0
                  Конечно, нормализация нужна, а уж если производительность не является очень узким местом — то нормализация просто необходима (Хотя в противном случае я бы посоветовал серверов БД купить побольше, а не базу портить).

                  Но это было что-то типа: «Мужчины и женщины в нашей БД ничем не различаются, но мы для мужчин создадим одну базу, а для женщин отдельную базу (именно базу а не таблицы)»
                  • 0
                    Ну в данном конкретном случае я с Вами совершенно согласен. И заведение другой базы только усложняет работу. Особливо если данные действительно однотипные. Это ж значит что и сопутствующие таблицы/процедуры/функции/вью — всё надо в двух базах хранить. Или вообще в третьей…

                    Но меня обуял вопрос по поводу этой Вашей фразы:

                    Конечно, нормализация нужна, а уж если производительность не является очень узким местом — то нормализация просто необходима (Хотя в противном случае я бы посоветовал серверов БД купить побольше, а не базу портить).


                    Не хотите ли Вы этим сказать, что нормализация — всегда ухудшает производительность?
                    • +1
                      Это сложный вопрос. Нет, она не всегда ухудшает, иногда получается даже увеличить производительность (за счет более логичной структуры и отсутствия дублирования). Да, можно отчасти нивелировать это при помощи вьюшек, но в целом — достаточно ситуаций когда нормализация ухудшает производительность (особенно в 5ой нормальной форме).
                  • 0
                    Реальный проект: наши клиенты ничем не отличаются (в плане структуры данных), но для каждого создадим свою базу данных, а имя базы будем брать из url

                    Таким образом прежде всего исключается из каждого запроса к БД условия вида «account_id = %s» (первым шагом к ускорению обработки была денормализация таблиц, в каждую вводили поле account_id в целях избавления от многоэтажных джойнов в каждом запросе, но оказалось всё равно медленно: или более-менее приемлема скорость выборки, но тормозит вставка, а данные вставляются часто, или ужасна скорость выборки без индекса,). «Бесплатный» бонус — конфендициальность данных клиента не нарушится, если забуду вставить в запрос фильтр по аккаунту
                    • 0
                      Вы создаёте отдельную БД для каждого клиента, и Вас ещё не убил босс, желающий посмотреть аналитику?
                      Или я что-то путаю?
                      • 0
                        Наверное я не совсем подробно описал. Наши клиенты — юрлица и ИП, обслуживающие прежде всего физлиц. Они ведут оперативный учёт через нашу веб-морду (что-то вроде аутсорса получается). Первоначально была одна нормализованная БД, в «корне» которой была таблица «accounts» (фактически только одно поле — id), то есть любая запись в любой таблице БД относится к определённому аккаунту и данные аккаунтов никак не пересекаются (вернее одно пересечение может быть — клиенты наших клиентов, но приняли решение дублировать записи)
                        • 0
                          Ну так я о том, что мне нужно одновременно работать с данными которые находятся в разных базах. Т.е. сделать запрос в одну, проверить ответ, извлечь индекс и потом сделать запрос в другую с этим индексом. Ня?
                          • 0
                            У нас чуть по другому — сделать запрос в одну, проверить ответ, если всё ок то подключиться к БД имя которой получено первым запросом (раньше, когда была одна БД, это был первичный ключ) и работать в дальнейшем с ней (раньше полученный первичный ключ вставляли во все запросы). После окончания работы со второй БД обновить записи в первой БД (типа лога). В принципе главное отличие, как я понял, что у нас система баз иерархическая (пускай всего два уровня — «корень» и «листья»), а у вас, видимо, одноуровневая
                    • 0
                      Вы делаете SaaS?
                      • 0
                        В принципе да, хотя ни разу об этом не задумывался :) Мыслил в категориях «тонкий клиент» и т. п. Подкину нашим «маркетологам», если что с меня, нет, с них причитается ;)
                        • 0
                          Здорово :)

                          Получается, у Вас еще один «бонус» — можно разнести разные базы по разным серверам, а не мучиться с разнесением таблицы по серверам. А насколько это удобно управляется? Ведь какой-нибудь alter table на 1000 баз будет выполняться достаточно долго.
                          • +1
                            Это тоже имелось в виду при принятии решения о разбиении на базы, собственно в структуре «корневой» БД имя сервера уже прописывается и используется для коннекта (если не совпадает с «корневым», если совпадает, то просто USE). Пока хватает двух серверов — app и db, ну и backup ещё, он же в теории будет использоваться для alter table в продакшене. Если честно, то со страхом жду необходимости делать ALTER TABLE, поскольку наша «система контроля версий» на «живых людях» ещё не работала с модификацией БД (только скрипты меняли), на тестах всё ок, но «не надо искать злой умысел там, где всё можно объяснить простой глупостью» (с) по памяти. Управляется пока (закрытый альфа тест типа) всё ручками, согласовывая с клиентом время апдейтов.
    • 0
      >насяльника промта бешельме мешельме
      исправил :)

      >Кстати за частую совет очень и очень даже хороший.
      Да, бывает. Но, на мой взгляд, сайт надо разделять на три части:
      1) код. пишется, дорабатывается, потом — перемещается на продакшн.
      2) статика. появляется один раз, удаляется 1 раз. Время между первым и вторым — достаточно большое.
      3) данные. меняются, запрашиваются постоянно.

      Например, если сейчас у нас эти три понятия разделены, то статику можно бекапить по мере создания, а данные — раз в N часов. Получаются тривиальные скрипты — один вызов tar cf или mysqldump. А если мы выносим данные в файлы, то теперь в бекапе статики нам придется делать exclude, в бекап данных — добавлять tar.
      Но основная проблема, как я описал — в разнесении всей информации на кластер, поддержании нормальной скорости доступа к ней, блокировок и так далее.
      • 0
        Пример из жизни. Есть такой каталог icecat. С него магазин дёргает данные. На продукт может быть от 1 до 50 свойств. Так вот — все свойства записаны в файлы. Просто взяли XML файл с каталога и сохранили у себя. По свойствам, котрым должен едити поиск, сделаны записи в базе данных. Когда показывается страница с продуктом читается информация из файла.

        Кластер — как синхронизировать статитику между кластерами — это уже проблема сисадмина. Для не большого проекта и rsynс подойдёт (не большой это так 5-6 серваков в кластере).

        А тепрь дальше вопрос о файлах. Так что механизм SSI для высоконагруженных систем в топку?

        Выше правильно сказали, нельзя создавать файлы с миллионым количеством записей.
        • 0
          >Когда показывается страница с продуктом читается информация из файла.
          А смысл? Не нагружать базу?

          >Кластер — как синхронизировать статитику между кластерами — это уже проблема сисадмина.
          Я считаю, что программист и сисадмин должны работать вместе, а не придумывать друг другу проблемы. Ведь еще не понятно, что будет неэффективнее — забить данные в базу, или переходить на NAS/SAN для хранения файлов и распарсивать XMLки.
          Кстати, в Вашем случае, как я понял, XMLка обновляется достаточно редко, поэтому можно без кластерной ФС хранить по экземпляру на каждой ноде (или база огромного размера?), и не заботиться о моментальной синхронизации, а раз в N времени синхронизировать их скриптом. В этом случае использование файлов — оправдано.

          Пункт в основном был о «изящном» решении, которое я недавно повстречал на одном проекте. Весь контент был в XML-файлах. В базе хранились какие-то ошметки метаинформации — структура папок, путь до xml файлов, поля их элементы. Данные обновлялись часто.

          Вообще, в советах нет крайностей — нигде нет слов «Всегда» или «Никогда». Значит, при инвертировании, в советах не получится этих же слов. Использование всего этого бывает оправдано (правда, кроме пары пунктов), но перед использованием надо очень хорошо подумать.

          >Так что механизм SSI для высоконагруженных систем в топку?
          Идея SSI — не в том, чтобы инклюдить статику в динамику, а в том, чтобы разбивать сайт на независимые блоки, генерящиеся параллельно/разными машинами. А то, для чего Вы хотите использовать SSI — это уже кеш тех самых независимых блоков.
    • 0
      >>Есть моменты когда проще сохранить XML файл с описанием продукта и его свойствами, чем их всех хранить в базе данных. И дёргать именно файл.

      А уж сколько радости и счастья такой подход принесёт программисту, работающему после вас! Это же не какие-то там таблицы с полями, индексами и ключами: разбираться в горе XML и, в общем случае, определять структуру по пишущему/читающему его велосипедному коду — ни с чем не сравнимое удовольствие для любого разработчика!

      :D
      • 0
        Зачотно, наверное твой смех хорош.

        Любой дурак может написать программу, которую поймёт компьютер. Подумай о чём это тут.
  • +2
    Оо, первые два пункта — то, с чем я мучаюсь уже год (забираю данные из чужой БД), хоть и на Oracle, но все равно актуально.
  • +4
    Что-то у меня совсем пятница. После третьего совета уже собирался писать длинный, холиварный, разрушающий, возмутительный комментарий. Потом мозг всё-таки включился. Теперь весел.
  • НЛО прилетело и опубликовало эту надпись здесь
  • +9
    еще советы для тех, кто хочет написать супер хороший сайт
    — не отделяйте верстку от кода, ни в коем случае не используйте шаблонизаторы или MVC, так делают ламмеры :)
    — не проверяйте параметры запросов >:-) это же весело :)
    — не пишите комментариев, это же Ваш код :)
    — ни в коем случае не тестируйте перед заливкой в SVN, это ведь все равно сделают пользователи
    — не пишите unit test, это пустая трата времени
    — не забывайте — ВЫ ГЕНИЙ :)

    • 0
      include ($_GET['page']);
      • 0
        еще

        echo($_GET['title']);
        • +1
          Да что мелочится, веселее:

          eval($_GET['q']);
          и больше нет проблем! :)
          • 0
            для полного счастья
            mysql_query("SELECT * FROM USERS WHERE `login`='{$_GET['login']}';");
  • +2
    блин, кто спер мою инструкцию?
    • 0
      поздно, уже все распечатали и на стенку повесили)
  • +1
    А еще ни в коем случае не используйте ООП.
    Не называйте переменные и функции так, чтобы по названию можно было понять, что они делают и для чего используются.
    Не разделяйте логику на части, пишите всё в одной функции.
    • +2
      Вот мне, кстати, всегда было интересно понять, для чего люди в вебе пользуют ООП.
      Оговорюсь сразу — я больше юниксоид-сетевик, нежели программер, потому на тонкое знание предмета не претендую.

      Однако, предположим ситуацию. Пишем мы 2 варианта игры про лошадку, скачущую по экрану: виндовый и вебовый.
      Вариант 1. Есть объект «лошадка». У него есть методы: вправо, влево, вверх, вниз. Где-то сбоку вертится вечный цикл (возможно, системный), который ждет нажатия соотв. кнопки и с радостью отдает на съедение нашему объекту. При этом объект у нас один, живет все время, пока запущено приложение и используется постоянно.
      Вариант 2. Пользователь запросил урл страница?go=right
      Где-то в БД у нас есть текущая координата лошади (в последний раз ее меняли, допустим, раз 5 назад). В памяти интерпретатора есть гордый объект «лошадь» со всеми методами: вправо, влево, вверх, вниз. Уже съели память на размещение объекта (объект по классике равно данные плюс методы обработки). Более того, в каждом методе могут быть еще временные переменные и т.д. И все это вместо того, чтобы в структурном программировании подгрузить файлик с функцией right, ей дернуть одну запись из БД, отдать ответ клиенту и завершить выполнение скрипта!

      Господа веб-программисты, поясните, для чего лишний раз грузить сервер ради эфемерной красоты кода?
      • 0
        Такое использование ООП — излишне. Но абстрагироваться от хранилища, базы данных, конента страницы, пользователя — никогда не мешает.
      • 0
        Я лично вообще убежденный структурщик.
        Фактически легкость сопровождения/модификации зависит больше от кривизны/прямизны рук программера, чем от того, объектно код написан или структурно.
        Принципиального отличия записи $obj->MoveRight() от MoveRight($obj) я не вижу.
        • +2
          Единственное отличие — в сложности расширения и добавление нового функционала.
          class Obj1
          {
              public:
                  virtual void move_right();
          }
          class Obj2 : Obj1
          {
              public:
                  virtual void move_right();
          }
          
          void do(Obj1* o)
          {
              o->move_right();
          }
          
          int main()
          {
              vector<Obj1*> v;
              /* положить в v экземпляры Obj1 и Obj2 */
              for(typeof(v.begin()) it = v.begin(); it != v.end(); ++it) do(it);
          }
          
          • –1
            какие сложности для реализации простой задачи…

            завести в структуре поле, задающее тип объекта (obj1/obj2) и union с набором параметров, специфичных для каждого типа объекта, после чего написать MoveRight, который в зависимости от типа объекта выполнит нужную операцию, никак нельзя?
            И выглядеть это будет куда менее cryptic.
            • +1
              А если объектов — 200, и каждый из них пишется отдельным программистом?
              • 0
                а мне казалось, что топик про веб разработку. где вы в веб разработке видели такие задачи?
                • 0
                  Любая броузерная онлаин-игрушка.
                  • 0
                    Вот забавно — я разработал большую браузерную игрушку и ни разу такой необходимости не видел. Как же так?
                    • 0
                      С любой, наверно, погорячился.

                      Но неужели у Вас не было мест, которые можно было бы упростить, добавив ООП?
                      • –1
                        Скажу так, может быть и была пара мест таких, но мест, где введение ООП все бы только усложнило, было больше.
                        В конечном итоге я считаю применение/неприменение ООП делом вкуса, а не панацеей от всех бед, как его некоторые представляют.
                        • 0
                          Эм, а кто предлагает его панацеей? Как и любое другое средство, оно имеет свои границы применимости, и перед решением, использовать его, тоже надо думать.
                          • 0
                            Да много кто предлагает.
                            И частенько слышишь что-то вроде «Как, ты пишешь без ООП? фууу»
      • +1
        Я не утверждаю, что ООП надо использовать в вебе всегда и везде.
        А что касается ваших примеров, то усложним задачку — пусть у нас будут лошадки разных типов и с ними можно делать какие-то действия, которые меняют различные параметры лошадки (её положение, её силы и т.д.), и для каждого типа лошадки возможны свои формулы и своя логика, например маленькая лошадки перемешается на меньшее расстояние.
        И вдруг стало нужно добавить новый тип лошадки, который немного отличается от какого-нибудь из существующего. С ООП надо будет создать класс под новый тип унаследованный от существующего типа и переопределить там несколько методов, без ООП в лучшем случае вам придётся копипастить код и потом его изменять в одном месте, а в худшем открывать 20 файлов и добавлять там условия на новый тип лошадки.
        А если надо будет поменять какую-то формулу общую для всех или почти всех лошадок, то с ООП достаточно будет отредактировать базовый класс, без ООП либо редактировать все типы, либо возиться с условиями в файлах с действиями.
      • +1
        В Вашем случае красота действительно эфемерна. Но вообще представьте, что у вас есть объект «животинка». И от него унаследованы и лошадка и собачка и овечка и слоник. И движение right у каждого из них — своё собственное. Слоник и собачка в очень даже разные щёлочки пролезают. Овечку вообще за забор не пускают. А уж если добавим, например, совушку, так там вообще четвёртый разговор.

        А в случае с ООП стукнулся сервер к объекту «животинка» — а тот уж пусть сам разбирается, кто он, что он и куда и как двинется.

        А если таких лошадок — писят штук? И каждая в своём месте сидит? К объектам в таком случае обращаться ой как удобно.

        ЗЫ: да что я Вам рассказываю сказки про инкапсуляцию, наследование, полиморфизм — Вы ж и так наверняка всё знаете. Важно, чтоб ООП для пользы дела было, а не просто для ООП-ния.
        • 0
          Да, красиво, не спорю. Но что делать, если таких животинок в онлайне порядка 100000? И каждая ест память и процессор на поддержку объектной красоты? Может я неправ, но кажется мне, что не загружать весь объект весом в сколько-то килобайт и сколько-то процессорного времени на парсинг, инициализацию и прочее будет разумнее.
          • 0
            Совершенно с Вами согласен — вопрос лишь в том, чьё время в данный момент выгоднее экономить — программиста или сервера. При большой нагрузке порой выгоднее

            * иметь ненормализованные таблицы, чтобы избежать лишних джойнов;
            * использовать директ вызовы запросов к базе данных;
            * выполнять или кучу запросов в одной транзакции, чтобы сэкономить время на создание/закрытие коннекций;
            * или наоборот разделять одну транзакцию на части, потому что иначе процесс коммита/роллбака займёт нереально много ресурсов

            … да мало ли ещё каких извращений в жизни бывает.

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

            Конечно, это имеет смысл тогда, когда выигрыш во времени разработки действительно ощутим. И если приложение «одноразовое» — один раз создано и больше его никто трогать не будет — то, возможно, заморачиваться с красотой кода смысла нет. Но кто гарантирует, что через месяц/полтора не потребуется что-то дорабатывать? Об удобстве этого достаточно подробно высказался konsoletyper чуть ниже.
      • +3
        А ты посмотри в сторону ASP.NET MVC. Или в сторону какого-нибудь Spring Framework. Откроешь для себя массу нового:
        1. У нас нету координаты лошади. У нас есть объект «лошадь», которая как-то там грузится из некоего репозитория в persistence layer'е, а описывается этот момент XML-файлом, но алгоритм совершенно не зависит от…
        2. А если у нас не PHP, то никто не мешает лошадке вообще жить в памяти, в зависимости от. И никуда она не денется, ибо AppDomain/тред с лошадкой будет жить, пока запущен веб-сервер
        3. Вообще весь сайт может быть сделан как набор взаимодействующих друг с другом объектов (а вовсе не веб-страниц), которые как-то там маппятся на рельные view, описанные шаблонами.
        4. Это всё отжирает память, согласен. Но уж лучше пусть хранится лишних два объекта, чем на каждый int уходит по 128 байт вместо 4 (да-да, это же PHP, глобальный и надёжный).
        5. И лучше уж пусть отжирается память, чем всё время дёргается БД. Я, например, переписав чат на одном местном сайте на Java, получил огромный прирост производительности. Да, в PHP-ной версии использовался memcache. Но всё это кажется такими костылями, когда есть возможность держать очередь сообщений в памяти и отдавать ответы на запросы прямо из неё, вообще не делая новые коннекты к базе. Хотя какие нафиг коннекты? sessionFactory.openSession(). И ни о каких БД я не знаю!
        6. В результате я получаю код, в который проще, в разы проще вносить изменения. Вот увидел я, что некие персистентные сущности тормозят работу сайта. Я просто настрою кэширование в Hibernate/Entity Framework. А в PHP со структурным подходом мне придётся мало того, что добавить кэширование данных при их запросе, так ещё и вставлять убийство «прокисшего» кэша во всех местах, где эти сущности как-то меняются.
        7. Конечно, в PHP можно абстрагироваться, выделить слой работы с данными, слой представления. Но тогда мы либо используем средства ООП в PHP, либо, упрямствуя, получим точь-в-точь ООП как GTK+, без поддержки со стороны языка. И, кстати, оно будет тормозить систему. Ибо тот же ORM надо будет поднимать не при старте сервера, а при _каждом_ запросе. И, замечу, всяческие акселераторы не спасают.
  • +2
    Храните данные в базе одной строкой, разделенной пробелом, зачем куча полей в таблице. Ведь куда приятней использовать implode(), explode() для получения каждого значения по отдельности. А если еще нужно будет реализовать поиск по каким-то значениям: используйте регулярные выражения в sql запросах.
  • –1
    Дежавю какое-то — что текст, что каменты.
    Месяц назад почти один в один было. Не надоело?
    • 0
      Помнится была поговорка «У кого что болит, тот о то и говорит».
      • 0
        Все так, все так.
        Однако почти любой из приведенных в статье и каментах «анти-советов» можно применить на практике с пользой в некоторых специфических ситуациях: хранение информации в файлах, хранение нескольких значений в одном поле БД, тот же system() и пр. — все это прекрасно работает на проектах, где для этого есть необходимость.
        • 0
          Да, я с Вами полностью согласен. Но, к сожалению, очень часто некоторые вещи применяются абсолютно не уместно и неумело.
  • 0
    1. Не проставляйте ключи!
    СУБД пишут умные люди. Некоторые из них даже получают за это деньги. Зачем подсказывать им, как устроены данные? Пускай догадываются сами из названий полей и самих данных. В крайнем случае, админы поправят профайлером.

    Имеются в виду первичные и внешние ключи? Ну тогда при чём тут подсказка? И при чём тут профайлеры? Или MySQL настолько суров, что LAMP'овцы даже не слышали выражения «целостность данных»? А скорость запроса вообще зависит от многих вещей, в том числе от индексов, которые, замечу, далеко не во всех СУБД делаются неявно (например, мой любимый PostgreSQL не делает по умолчанию индексы на внешние ключи, ибо чревато как раз потерей производительности).

    2. Используйте строковые PK вместо числовых!

    А что? Некоторые СУБД поддерживают guid'ы нативно. И умеют автоматически генерить их. И Hibernate, например, умеет генерить guid'ы для полей БД. Иногда это бывает оправданно. Хотя да, использовать это налево и направо чревато.
    • 0
      А что? Некоторые СУБД поддерживают guid'ы нативно. И умеют автоматически генерить их. И Hibernate, например, умеет генерить guid'ы для полей БД. Иногда это бывает оправданно. Хотя да, использовать это налево и направо чревато.


      Ну речь идёт не только о гуидах? Работал, помнится, с чётырёхгигабайтной базой, где все ключи были строковые. Фильмы, актёры, режиссёры — все ключи были в виде DVD334534, STAR887744, DIR897778. 50 тыщ фильмов, 200-300 тыщ актёров и базюка с удовольствием начинала пыхтеть и пыжиться.

      Ну, справедливости ради надо заметить, что кроме строковых ключей там были и другие бомбы запроектированы «дизайнерами», но и ключи тоже свою роль играли. И немалую.
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    А можно остановится подробнее на пункте 9? Я помоему именно так и делаю. Поясните плиз что плохого в данном методе, ну или пару слов для поиска в google
    • 0
      Плохо — то, что (скорее всего) скрипт начинается с session_start(), и кука выдается клиенту сразу. Когда встанет проблема увеличения посещаемости, понадобится отдавать страницы из кеша вместо генерации их для каждого запроса.
      В самом простом случае выбирается схема: авторизованные пользователи всегда получают сгенерированный ответ, незарегистрированные — получают страницу из кеша. Этих пользователей надо каким-то образом различать. Если у каждого пользователя будет только по сессионной куке, то для того, чтобы определить, авторизовался он, или нет, надо лезть в хранилище сессий php. Намного удобнее — при успешной авторизации проставлять какую-нибудь куку authiorised-as, и снимать ее после выхода.
      Ссылок накидать вряд ли смогу, можете попробовать прочитать статью о кешировании на dklab.

      Честно говоря, это — один из самых легкоисправимых пунктов этой статьи :)
      • 0
        Спасибо, Бориско.
        Т.е. грубо говоря лишь в случе если человек правильно ввел логин и пароль, мы прописываем некую куку например MD5(id + IP + SecredWord + еще что-то)… Но тогда получится, что при каждом запросе человека с кукой — нужно будет брать из базы SecretWord для id и т.д, разве это не замедлит еще больше? Или я чего то недопонимаю.
        • 0
          Нет. При успешной авторизации мы записываем об авторизации в сессию, а так же выдаем новую куку с любым значением, например, логином вошедшего пользователя. Авторизованность по ней проверяться не должна, по ее присутствию определяется только возможность кеширования.
          • 0
            Всё. Вкурил. Нужно для скорости выдачи из кеша, чтобы каждый раз не обращаться к файлу с данными сессии? Но при этомесли нужно проверять авторизованность — то всё равно нужно туда обраться :) какой то замкнутый круг. Наверное зависит от конкретных задач.
            • 0
              Да. Суть — в том, что из вебсервера, который не знает ничего о php, структуре его файла сессии/записи в memcached, и вообще, может располагаться на другой машине, чем сессии, намного сложнее проверить авторизованность по сессии, чем самому скрипту.
            • 0
              У нас примерно такая схема: если стоит кука с «MD5(id + IP + SecredWord + еще что-то)», то отправляем на скрипт (там аутенфикация и авторизация и там уже кэширование на уровне приложения работает, то есть кэш «кусочками»), если куки нет, то пытаемся найти кэш урла средствами веб-сервера, если нашли, то отдаём, если нет, то тоже идём на скрипт (который кэш генерирует по ходу дела для следующего посетителя или рефреша). В перспективе хотим и для аутенфицированных пользователей кеш на уровне веб-сервера организовать (sql запросы часто идут одни и те же, а значит и html/xml/json тот же самый выдаётся), но пока не до того — довольно большой объём работы по нашим оценкам, чтобы обеспечить 100% валидность кэша так, чтобы кэширование имело смысл (то есть не сбрасывать весь кэш отображений полностью при любом изменении моделей)
          • 0
            К слову про MD5, на одном из эмуляторов игрового сервера наблюдал такое хеширование пароля:

            base64_encode(pack('H*', hash('whirlpool', substr($_REQUEST[«password»], 0, 32))));
  • +1
    Я бы добавил совет (хотя возможно просто объединил имеющиеся)
    «Если ваша писанина заработала на вашем компе, значит всё правильно, остальное проблемы на стороне клиента» =)
  • 0
    Думаю если бы текст был написан без иронии то был бы более информативен и полезен. А так в каждом абзаце читается лишь очередное «накипело».
    • 0
      Описать «как нужно написать хороший сайт» куда сложнее (если вообще возможно), чем описать «как его не нужно писать, если нет веских оснований писать именно так». А форма «антисоветов» и предполагает иронию, если не сарказм :)
      • 0
        Хм. Ну мне кажется что автора просто «butthurt», а не форма «антисоветов». Как-то так.
        • 0
          Вы частично не правы. Конечно, всё это накипело очень сильно, но форма была выбрана в основном для привлечения внимания.
          На очередную сухую статью о том, как правильно писать приложение, никто не обратил бы внимания, она не возымела бы эффекта — ведь таких написаны уже десятки, а все равно, ими никто не пользуется. А эта статья могла отложить больший отпечаток в памяти прочитавшего программиста, и, возможно, когда он будет писать следующее приложение, он задумается.
      • 0
        у автора*
  • 0
    а разъясните мне, пожалуйста, пункт 11, особенно применительно к PHP.
    зачем мне cgi-bin, как в папке upload окажется php-шник под видом jpg-а и почему jpg-и будут указаны в настройках сервера как скрипты для php?
    по ощущениям этот пункт опоздал уже лет эдак на 6-7 :)
    • 0
      1) Разделяем скрипты и контент. Удобнее бекапить, удобнее использовать svn для скриптов. В папку со скриптами может писать только отличный от вебсервера/php пользователь, что гарантирует невозможность переписать скрипт в случае обнаружения дыры в нем.
      2) В папке upload он может оказаться опять же в виде какой-нибудь ошибки, приводящей к заливке файла upload.php или upload.php.jpg. В основном, php матчат по регекспу \.php, а не \.php(\/|$), что позволит злоумышленнику выполнить upload.php.jpg как скрипт. Да и то, в данном случае, если злоумышленник сможет создать папку с именем что-то.php, и положить в нее свой jpeg, то он обработается.
      • 0
        1) svn используется абсолютно одинаково в обоих случаях, контент добавляем в svnignore и все. бекапить контент не проблема, бекапить скрипты нет необходимости — ибо svn.
        вылезти же на уровень выше ДокРута может не давать правильно сконфигурированный сервер, да бы через лежащий неподалеку wordpress никто не влез на другие сайты.

        2.1) это не какая-нибудь ошибка, это уже полный бардак :) и такому программисту сначала надо основы изучить, а потом уже за «вредные советы» браться.
        2.2) Кто, простите, кого и по каким еще регекспам матчит?
        • 0
          1) KISS. Зачем делать что-то сложно, добавлять excludes, менять их при изменении скрипта, порождая возможные ошибки, если можно просто вести одну папку в SVN и бекапить другую?
          Про то, при чем тут ДокРут — не понял. Смысл в том, чтобы была специальная папка, которую нельзя поменять запросом из вебсервера, и чтобы только она могла исполняться.

          2.1) Тем не менее, люди — не роботы, ошибки встречаются. Лучше уж «железно» застраховаться от них, чем надеяться на то, что код — без ошибок.
          2.2) Веб-сервер смотрит на URI-запроса и решает, что же с ним делать — отдать пхп, отдать статикой или еще что-то.
          • 0
            1) не знаю, какие у вас сложности с использованием svnignor-а, даже боюсь спрашивать.
            2.1) повторюсь. это не ошибка, это незнание основ.
            2.2) AddHandler application/x-httpd-php .php — не вижу никаких регулярок.
            • 0
              1) В том, что люди — не машины. Кто-то при каком-то изменении может забыть добавить что-то в исключения, и все полетит.
              2.1) И что? Вы гарантируете, что в Вашем коде никогда не обнаружится подобного бага? Чем?
              2.2) Бывает не только апач, особенно на высоконагруженной системе. Да и его можно сконфигурировать на регекспы, а не на расширения.
              • 0
                1) такое ощущение, что мы обсуждаем умственно отсталых
                2.1) например, я уже и не вспомню, когда мне последний раз попадался проект в котором заливаемые файлы не проходили бы доп. обработки — генерация превьюшек для графики, выборка тегов для mp3, сжатие для аудио и видео — все эти операции позволяют опознавать заливаемые файлы по содержимому. так же на больших объемах контент выносится на отдельный сервер безо всяких там php.
                но даже если я буду класть заливаемые файлы в папку, доступную по прямой ссылке, даже с сохранением оригинального названия файла, даже без минимальной проверки по имени и контенту, без какого-нибудь проксирования и выноса на другой сервер (ну а вдруг на меня пистолет наставят :) ) — даже в этом случае они не выполнятся — ибо п.2.2
                2.2) ну да, криво настроить можно все, что угодно. вопрос только — зачем?
  • 0
    Когда уже народ начнёт писать о том «как надо делать»?

    Я тоже могу написать пост в стиле «никогда не ставьте комментариев» (более того я таких советов могу штук 100 минимум дать) но кому это поможет? Ну начнёт какой нибудь идиот ставить комментарии в коде типа «вот тут я переменную инкрементирую» а толку? Польза будет?
  • 0
    Всегда используйте прямые пути к скриптам и файлам и никогда не используйте относительные пути. Это вам даст возможность в будущем перенести сайт с большим гемором!
  • 0
    Сама статья ещё куда ни шло, можно местами улыбнуться. Но комментарии где другие авторы тоже всячески пытаются сострить… Лучше молчите со своими детсадовскими шутками про mvc, тесты, комментарии. Уныло и убого, слов просто нет.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.