И я (уже писал выше). Ибо когда попробовал кодить в Netbeans на PHP и на Java, то оказалось, что статически типизированный язык даёт больше возможностей (гораздо больше) для IDE в плане помощи программисту. Да и скорость Java сильно радует, опять же, в сравнении с.
Ни в коем случае не надо путать такие аспекты типизации как строгость/нестрогость и статическая/динамическая типизация! В некотором смысле любой язык обладает нестрогой типизацией (вспомним неявное преобразование целых чисел в числа с плавающей точкой). У C# так вообще с первой версии есть такая штука как неявное преобразование типов (любых, до которых дотянутся кривые руки программиста). Движение в сторону «динамичности» — это больше для бесшовной интеграции с языками с динамической типизацией. Кстати, надо сказать, что там динамическая типизация есть ещё с первой версии: reflection никто не отменял. А вот в PHP элементы строгой типизации начали появляться ещё с тех пор, как появилась возможность задать тип параметра у функции/метода (тогда ещё класс, а не примитивный тип, кажется это появилось в 5 версии).
Что по мне, так ситуация неясна. Сегодня они добавили примитивный типы, завтра добавят возможность аннотировать (или уточнять) тип в любом месте, послезавтра добавят generics и получится Java или C#, только с кучей исторических костылей. Может, оно того не стоило? Может, сразу следовало везде пихать JSP и ASP.NET?
Рискую напороться на минуса. Мне вот всегда было непонятно, что же это за «PHP-way». Т.е. вот есть куча языков и считается, что у каждого свои преимущества и недостатки, и вообще, думать надо для специфического языка по-своему. Так вот: я никогда не улавливал чего-то специфического, что предлагает PHP. Ну, точнее один момент уловил — когда нужно что-то архи-, мегапростое, то проще писать небольшой скрипт на PHP, чем мучиться с настройкой Hibernate, написанием шаблонов, контроллеров, разворачиванием всего этого дело на Tomcat. Что же насчёт больших проектов — непонятно, где преимущество подхода PHP и в чём же именно он отличается в предлагаемых средствах от Java (и вообще, нафига ему динамическая типизация). Т.е., например, я прекрасно понимаю, зачем динамическая типизация в Python и почему ряд задач на нём решается на порядок выразительнее чем на Java. А в PHP как раз для «больших» приложений начали утаскивать чуть ли не один-в-один ООП из Java, причём, похоже, динамическая типизация обеспечивает там одно «преимущество» — отсутствие необходимости аннотации типов. Оно сомнительно на фоне того, что те же Scala или F# вполне себе статически типизированы, но при том не требуют аннотации типов. А вот то, что поддержка в IDE из-за этого никакая — это, конечно, просто ужасно.
Так что я думаю, нечего пинать явистов с претензиями «вы нас не понимаете». Как мне кажется, у PHP своя ниша образовалась исторически. А может, из-за низкого порога вхождения. Но никак не потому, что PHP вносит что-то принципиально новое в мышление человека, пишущего на нём, и что мир PHP сильно отличается от Java, C# или Python.
1. Не проставляйте ключи!
СУБД пишут умные люди. Некоторые из них даже получают за это деньги. Зачем подсказывать им, как устроены данные? Пускай догадываются сами из названий полей и самих данных. В крайнем случае, админы поправят профайлером.
Имеются в виду первичные и внешние ключи? Ну тогда при чём тут подсказка? И при чём тут профайлеры? Или MySQL настолько суров, что LAMP'овцы даже не слышали выражения «целостность данных»? А скорость запроса вообще зависит от многих вещей, в том числе от индексов, которые, замечу, далеко не во всех СУБД делаются неявно (например, мой любимый PostgreSQL не делает по умолчанию индексы на внешние ключи, ибо чревато как раз потерей производительности).
2. Используйте строковые PK вместо числовых!
А что? Некоторые СУБД поддерживают guid'ы нативно. И умеют автоматически генерить их. И Hibernate, например, умеет генерить guid'ы для полей БД. Иногда это бывает оправданно. Хотя да, использовать это налево и направо чревато.
А ты посмотри в сторону 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 надо будет поднимать не при старте сервера, а при _каждом_ запросе. И, замечу, всяческие акселераторы не спасают.
… что идеально подходило для хомячкомых домашних страничек с часами и гостевой книгой. Вот только «СУБД» без транзакций ни для чего серьёзного не годится, а за приложения без транзакций надо руки отрывать. Потом, когда эпоха домашних страничек прошла, MySQL начал потихоньку развиваться в правильном направлении. Вот только у PG к тому времени уже всё нужное было, и MySQL вышел за счёт привычки. Отставание MySQL очевидно и поныне.
Насчёт PostgreSQL. На SQL-рельсы он начал переезжать примерно во времена зарождения MySQL. А относительной стабильности добился и того позже.
Да что там последний год? Слон гораздо лучше MySQL. Единственное, почему MySQL оказался популярнее — он был раньше. Пока слон развернулся и более-менее подчистил баги, MySQL уже был облюбован хомячками для своих хоумпаг.
простите, случайно Enter нажался
Так вот, даже на таких «выразительных» языках объём кода в серьёзных проектах по-прежнему остаётся очень и очень немаленьким. Да, профессионал способен написать более выразительный код, но это отнюдь не означает, что объём кода стремится к нулю.
Ну а тезисом по поводу фреймворков ты меня даже позабавил. Ибо я сейчас к нему добавлю тезис «компилятор», и его смысл ничуть не изменится. А на самом деле «все эти фреймворки и библиотеки» нужны для того, чтобы не решать повторно уже решённые задачи. Прямо так и вижу, как труъ-профи пишет парсер XML вручную, при этом объём кода исчезающе мал…
По поводу IDE уже написал. IDE нужен ровно для того, чтобы увеличивать производительность программиста. И профессионал не будет писать в блокноте. Профессионал, во-первых, умеет грамотно пользоваться всеми фичами используемой IDE, а во-вторых, пишет код, который хорошо поддерживался бы со стороны IDE, т.е. свёл бы к минимуму использование всяческих кодогенераций, явных приведений типа в статически типизированных языках (хотя, тут даже не IDE, а компилятор), строкового описания различных сущностей в программе и т.п. и пользовался бы существующими механизмами языка.
Пустая демагогия. Объём кода не снижается за счёт увеличения «профессионализма». Объём кода уменьшается за счёт
1) увеличения выразительности языка
2) использования готовых фреймворков и библиотек
тем не менее, даже на «выразительных» языках вроде Python, Ruby или
А четвёртая стадия — это осознание того, что на второй стадии программист взял за основу правильные идеи, но выстроил на их базе карго-культ. Думаете, зачем нужны все эти паттерны и слои абстракции? Ради красивости? Красота как раз в простоте и лаконичности. А нужны они как раз ради того, чтобы повысить гибкость этой системы. Если же результат оказывался совершенно противоположным, это может означать только то, что паттерны применялись неправильно и использовались неверные абстракции. И, кстати, как я понял, на второй стадии получались большие методы (в противовес третьей стадии). А это ну никак нельзя назвать «красивым кодом»…
И ещё про кодогенерацию. В теории оно конечно хорошо. А вот на практике… Из чего генерится код? Из XML? Из собственного языка? В первом случае ещё можно худо-бедно подсунуть IDE схему. Во втором — придётся писать «в блокноте». А поддержка со стороны IDE в разы повышает скорость кодирования, и на порядки — скорость внесения изменений.
Мне вот интересно, неужели происходит попиксельная обработка изображения с помощью JS (а не используется какой-нибудь Canvas)? Тогда я вообще удивлён, что JS настолько быстр, что в течение секунды успевает полностью обработать картинку. Интересно, где можно посмотреть на примеры того, как JS попиксельно обрабатывает картинку?
Буду категоричным. Несмотря на то что, да, на меня после этого свалится куча минусов. Статья ужасна.
Если-бы я поставил $Result после проверки !$queryResource, то глазами пришлось-бы бегло перечитывать код в поисках типа этой переменной.
Совсем непонятно, почему. Лично я думаю, что объяснение здесь высосано из пальца. Впрочем, объяснение в исходной статье тоже хромает, но она хотя бы есть.
Поэтому, хороший программист первым делом избавится от излишнего кода, проделав простейший Рефакторинг каждого метода (особенно, когда они занимают 300 строчек), разбив его на более легкие методы и функции с ясными очевидными названиями.
А вот как показывает моя практика, не всегда это возможно делать. Да, я и сам стараюсь делать методы максимально компактными. Но иногда не выходит. Тут надо понимать, что нагородив методов, мы перейдём от спагетти в одном методе к спагетти из кучи непонятных private-методов. Да и не всегда методам удаётся дать внятное название, вот и получается набор методов вида DoMysteryousThing и DoSomeOtherMysteriousThing. Конечно, к ним можно подписать комментарии. Но! Почему бы тогда не написать всё в одном методе, разделив его этими самыми комментариями на логические блоки?
Возврат результата функции через ее параметр
А вот тут автор вообще приводит абсурдный пример. Нехорошая это практика возвращать массив или bool. Тем более, это не прокатит в статически типизированных языках. А следующий пример — это возврат к тёмным временам C (поморщился). Вообще, если так уж нужно избежать выбрасывания исключения, то идеальное решение — вернуть структуру вроде Error, конкретизированную типом результата метода.
Полностью классы я не привожу. Но уже становится ясным, по каким причинам стоит задуматься о том, каким методом пользоваться для изменения переменной. При всём при том, стоит задуматься о том, как ваш класс может использовать в многопоточных приложениях, или например, при работе с БД.
Мне не становится ясным ничуть. Вообще, своё мнение об уместности использования свойств я оставил в развёрнутом комментарии к исходной статье.
В функциональном программировании по хорошему счёту — разделяют на «атомарные» функции предварительной инициализации. Например — это реализовано в OpenGL. Но я приведу пример автора:
Вопрос к автору? А вы вообще осознаёте, что такое «функциональное программирование»? И при чём тогда OpenGL и «инициализация»?
А теперь о минусах подхода автора. Почему не стоит делать, как он говорит (в языках без поддержки именованных параметров):
Из приведённого ниже фрагмента кода вообще не ясно, почему не стоит делать, как он говорит. И, кстати, я бы этот код написал как-то так:
Да, как видите, не очень удобно. Зато не надо запоминать в какой последовательности надо передавать параметры. Хотя да, IDE зачастую в помощь. А вот читается код всё равно гораздо лучше. Разумеется, всё было бы ещё лучше, если бы были именованные параметры. Да, надо заметить, что обычно рисование происходит через некий «контекст», который хранится либо внутри самого объекта, через который производится рисование, либо передаётся параметром. Обычно этот контекст и содержит информацию о кистях, шрифтах, преобразованиях. Собственно, это то, про что автор хотел сказать в случае с OpenGL. Вот только к функциональному программированию это никак не относится. И с ООП, кстати, вполне себе уживается.
Дело не в функции. Посмотри, как сделано на C#. Select и Where не являются методами интерфейса IEnumerable. Они объявлены в статическом классе Enumerable. Благодаря extension methods можно записывать так, как я показал, а не что-то вроде:
return Enumerable.Where(Enumerable.Select(sequence, x => x * x), x => x % 2 == 1);
Это в некотором смысле аналог пункта 4 статьи.
Аналогично, в JS можно добавить методы map и filter в Array.prototype и так же пользоваться себе наздоровье точечной нотацией без увеличения уровня вложенности и дублирования названия helper-класса.
Haskell тут вообще не совсем уместен, так как он не ООП. Но вот и в нём есть средство (в виде операции $), которая позволяет избегать лишних скобок и записывать производимые операции последовательно, а не внутри друг друга.
Не совсем. Во-первых, monkey patching относится только к динамическим языкам. Я же привёл в примере C#, который статически типизирован (и решает проблему с помощью extension methods). Во-вторых, я говорил не про изменение кода, а лишь про наполнение существующего класса (или прототипа) новыми «общими» функциями. Так, например, гораздо изящнее реализуется то, что зовётся «обобщённым программированием».
кривыеруки программиста). Движение в сторону «динамичности» — это больше для бесшовной интеграции с языками с динамической типизацией. Кстати, надо сказать, что там динамическая типизация есть ещё с первой версии: reflection никто не отменял. А вот в PHP элементы строгой типизации начали появляться ещё с тех пор, как появилась возможность задать тип параметра у функции/метода (тогда ещё класс, а не примитивный тип, кажется это появилось в 5 версии).Что по мне, так ситуация неясна. Сегодня они добавили примитивный типы, завтра добавят возможность аннотировать (или уточнять) тип в любом месте, послезавтра добавят generics и получится Java или C#, только с кучей исторических костылей. Может, оно того не стоило? Может, сразу следовало везде пихать JSP и ASP.NET?
Так что я думаю, нечего пинать явистов с претензиями «вы нас не понимаете». Как мне кажется, у PHP своя ниша образовалась исторически. А может, из-за низкого порога вхождения. Но никак не потому, что PHP вносит что-то принципиально новое в мышление человека, пишущего на нём, и что мир PHP сильно отличается от Java, C# или Python.
Имеются в виду первичные и внешние ключи? Ну тогда при чём тут подсказка? И при чём тут профайлеры? Или MySQL настолько суров, что LAMP'овцы даже не слышали выражения «целостность данных»? А скорость запроса вообще зависит от многих вещей, в том числе от индексов, которые, замечу, далеко не во всех СУБД делаются неявно (например, мой любимый PostgreSQL не делает по умолчанию индексы на внешние ключи, ибо чревато как раз потерей производительности).
А что? Некоторые СУБД поддерживают guid'ы нативно. И умеют автоматически генерить их. И Hibernate, например, умеет генерить guid'ы для полей БД. Иногда это бывает оправданно. Хотя да, использовать это налево и направо чревато.
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 надо будет поднимать не при старте сервера, а при _каждом_ запросе. И, замечу, всяческие акселераторы не спасают.
Насчёт PostgreSQL. На SQL-рельсы он начал переезжать примерно во времена зарождения MySQL. А относительной стабильности добился и того позже.
Так вот, даже на таких «выразительных» языках объём кода в серьёзных проектах по-прежнему остаётся очень и очень немаленьким. Да, профессионал способен написать более выразительный код, но это отнюдь не означает, что объём кода стремится к нулю.
Ну а тезисом по поводу фреймворков ты меня даже позабавил. Ибо я сейчас к нему добавлю тезис «компилятор», и его смысл ничуть не изменится. А на самом деле «все эти фреймворки и библиотеки» нужны для того, чтобы не решать повторно уже решённые задачи. Прямо так и вижу, как труъ-профи пишет парсер XML вручную, при этом объём кода исчезающе мал…
По поводу IDE уже написал. IDE нужен ровно для того, чтобы увеличивать производительность программиста. И профессионал не будет писать в блокноте. Профессионал, во-первых, умеет грамотно пользоваться всеми фичами используемой IDE, а во-вторых, пишет код, который хорошо поддерживался бы со стороны IDE, т.е. свёл бы к минимуму использование всяческих кодогенераций, явных приведений типа в статически типизированных языках (хотя, тут даже не IDE, а компилятор), строкового описания различных сущностей в программе и т.п. и пользовался бы существующими механизмами языка.
1) увеличения выразительности языка
2) использования готовых фреймворков и библиотек
тем не менее, даже на «выразительных» языках вроде Python, Ruby или
И ещё про кодогенерацию. В теории оно конечно хорошо. А вот на практике… Из чего генерится код? Из XML? Из собственного языка? В первом случае ещё можно худо-бедно подсунуть IDE схему. Во втором — придётся писать «в блокноте». А поддержка со стороны IDE в разы повышает скорость кодирования, и на порядки — скорость внесения изменений.
Совсем непонятно, почему. Лично я думаю, что объяснение здесь высосано из пальца. Впрочем, объяснение в исходной статье тоже хромает, но она хотя бы есть.
А вот как показывает моя практика, не всегда это возможно делать. Да, я и сам стараюсь делать методы максимально компактными. Но иногда не выходит. Тут надо понимать, что нагородив методов, мы перейдём от спагетти в одном методе к спагетти из кучи непонятных private-методов. Да и не всегда методам удаётся дать внятное название, вот и получается набор методов вида DoMysteryousThing и DoSomeOtherMysteriousThing. Конечно, к ним можно подписать комментарии. Но! Почему бы тогда не написать всё в одном методе, разделив его этими самыми комментариями на логические блоки?
А вот тут автор вообще приводит абсурдный пример. Нехорошая это практика возвращать массив или bool. Тем более, это не прокатит в статически типизированных языках. А следующий пример — это возврат к тёмным временам C (поморщился). Вообще, если так уж нужно избежать выбрасывания исключения, то идеальное решение — вернуть структуру вроде Error, конкретизированную типом результата метода.
Мне не становится ясным ничуть. Вообще, своё мнение об уместности использования свойств я оставил в развёрнутом комментарии к исходной статье.
Вопрос к автору? А вы вообще осознаёте, что такое «функциональное программирование»? И при чём тогда OpenGL и «инициализация»?
Из приведённого ниже фрагмента кода вообще не ясно, почему не стоит делать, как он говорит. И, кстати, я бы этот код написал как-то так:
void DrawRectangle (RectangleInfo rectInfo) { var polyline = new Polyline(); polyline.Points = rectInfo.Rectangle.Corners.Select(pt => pt.ApplyTransformation(rectInfo.Transform)); polyline.Close = true; polyline.Pen = rectInfo.Pen; this.DrawPolyLine(polyline); }Да, как видите, не очень удобно. Зато не надо запоминать в какой последовательности надо передавать параметры. Хотя да, IDE зачастую в помощь. А вот читается код всё равно гораздо лучше. Разумеется, всё было бы ещё лучше, если бы были именованные параметры. Да, надо заметить, что обычно рисование происходит через некий «контекст», который хранится либо внутри самого объекта, через который производится рисование, либо передаётся параметром. Обычно этот контекст и содержит информацию о кистях, шрифтах, преобразованиях. Собственно, это то, про что автор хотел сказать в случае с OpenGL. Вот только к функциональному программированию это никак не относится. И с ООП, кстати, вполне себе уживается.
Это в некотором смысле аналог пункта 4 статьи.
Аналогично, в JS можно добавить методы map и filter в Array.prototype и так же пользоваться себе наздоровье точечной нотацией без увеличения уровня вложенности и дублирования названия helper-класса.
Haskell тут вообще не совсем уместен, так как он не ООП. Но вот и в нём есть средство (в виде операции $), которая позволяет избегать лишних скобок и записывать производимые операции последовательно, а не внутри друг друга.