PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Описание: Как улучшить свой код или "Страна Быдлокодия"
EuGen Администратор
Отправлено: 01 Декабря, 2011 - 10:48:32
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Приветствую, коллеги.

Вместо вступления
Написание этой статьи вызвано большим интересом к теме программирования "как оно есть", имея ввиду именно создание программы, отвлеченно от программирования на PHP или других языках. Что же здесь имеется ввиду? То, что программирование - это вполне теоретизируемая область, обладающая рядом постулатов, правил, методов. И именно незнание этой теории, на мой взгляд, приводит к тому, что называется "быдлокодом" (Лично мне не нравится это название, поэтому здесь и в дальнейшем буду называть это просто "нестройный код")

Кратко о теории
Пересказать теорию я, наверное, не сумею, да и заняло бы это слишком много. Теория ведь бывает разная. И я, к примеру, изучал ее в течении нескольких лет в ВУЗе. Курсы, которые преподавались там - это Структуры Данных и Алгоритмы (СДА), Языки Программирования и Методы Трансляции (ЯПМТ), Компьютерная Графика (КГ), Интернет-Технологии (ИТ) и т.п. Как видите, пересказать все это довольно трудоемко. Поэтому расскажу лишь немного о самой теории, но не ее содержание.
Теория позволяет воспринимать процесс абстрактно, посредством сущностей и связей между ними, а так же побуждает к осознанию сущностей, которые Вы используете в конкретной программе. Приведу пример. Простой код, задача которого - сделать замену в тексте так, чтобы все первые буквы были заглавными. Вариант первый:
PHP:
скопировать код в буфер обмена
  1. $t=preg_split('/\s+/', $text, -1, PREG_SPLIT_NO_EMPTY);
  2. for($i=0; $i<count($t);$i++)
  3. {
  4.    $t[$i]=ucfirst($t[$i]);
  5. }
  6. $r=join(' ', $t);

Вариант второй:
PHP:
скопировать код в буфер обмена
  1. $sResult=join(' ',array_map('ucfirst', preg_split('/\s+/', $sText, -1, PREG_SPLIT_NO_EMPTY)));

Примеры приведены с тем, чтобы показать наличие сущностей. В первом примере их целых три. Это $t, $i и $r. Да-да, переменные - один из видов сущностей. Ведь создавая переменную, мы закладываем в неё некоторый смысл. И пусть $i используется только в цикле, а $t - временная. Обе имеют смысл, первая - как итератор цикла, вторая - как временное хранилище. $r в первом случае есть сущность-результат.
Теперь придем к понимаю, почему первый пример хуже второго. Хуже - с точки зрения теории программирования. Дело здесь не в том, что второй выглядит "красивее", имея всего лишь одну строчку кода. Если знать, почему так произошло, это будет лишь естественным следствием. А дело в простом. В первом примере у нас есть две лишних сущности. Это $t и $r. Почему лишних? Потому что, очевидно, ни итератор цикла, ни временное хранилище не имеют дальнейшего значения, их роль ограничена лишь этим участком. И, конечно, кроме практической цели у них нет строгого логического обоснования. Попросту говоря, они - просто переменные. Сущностью в первом примере является только $r - так как это - результат (с которым, конечно, предполагается что-то делать). И, скорее всего, данные пришли исходя из определенного алгоритма, а потому $r будет участвовать далее как сущность. Во втором же примере мы обходимся без лишних сущностей (есть только одна - собственно, результат), а потому эти два примера иллюстрируют одно из правил:
0. Избегать лишних сущностей в программе

Помимо сущностей есть еще и связи между ними. А так же более сложные сущности, чем, скажем, переменная. Здесь, конечно же, идет отсылка к ООП. Имею ввиду именно сам объектный подход - не его реализацию в конкретном языке, а именно теорию. Каждый раз я вижу, что, пытаясь постигнуть ООП, начинающие программисты безнадежно увязают в хитросплетениях его конкретной реализации в конкретном языке. А это - не есть ООП, так как ООП - это парадигма, теоретическое построение, если хотите. Поэтому нельзя вникнуть в него просто начав "писать код". Осознание должно быть на теоретическом уровне, абстрактном уровне мышления. Ровно поэтому при описании, обучению ООП часто можно видеть отвлеченные от программирования примеры ("Представим себе, что у нас есть сущность - фрукт, и ее экземпляры - банан, апельсин, груша, и у них есть свойства {...} и т.п."). Ведь если все мы вспомним, как в детстве нас учили числам - мы придем к тому же самому. Все помним, как считали яблоки в раннем детстве? Это может показаться смешным или странным, но именно тогда в нас всех закладывалось абстрактное восприятие чисел. Спросите сейчас себя - что такое "число семнадцать"? Вы не найдете точного ответа, так как это - абстракция, отвлеченно от реального применения (семнадцать яблок, семнадцать мгновений весны и т.п.) не имеющая конкретного смысла. Аналогично и ООП в программировании. Это - абстракция, это - теория. И разница в понимании/непонимании ее - на том же уровне, как понимание/непонимание абстракции чисел. Оттого и сложно ее постичь.

Как помочь в восприятии

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

- это именно правила "хорошего тона" в программировании, при создании имен сущностей. Хорошее имя переменной скажет вам, зачем она нужна, а хорошее имя функции - что она делает. Как видите, правила хорошего кода тоже возникли не на ровном месте и не только для удобства, а являются следствием теоретического обоснования. Чтобы была конкретика, приведу правила, которых придерживаюсь сам.
0. Неймспейсинг:

  1. Имена переменных. Используются префиксы, указывающие на тип переменной, обозначая таким образом множество допустимых над ней операций. Я использую префиксы:
    rg - для массивов
    b - для булевых данных
    i - для данных целочисленного типа
    f - для данных вещественного типа
    s - для данных строкового типа
    r - для данных типа ресурс или объект.
    m - для данных, тип которых заранее неизвестен (часто при лямбда-функциях, используемых при обработке массивов)
    fn - для callback-данных
  2. Имена функций.
    Используются как префиксы, так и словообразование. Например, функцию, возвращающую MAC-адрес по IP, я назову getMACbyIP. Традиционно функции я именую с маленькой буквы, помещая действие, которое выполняет функция, в начало ее названия и отделяя его строчным написанием.
  3. Имена классов. Всегда с заглавной буквы.
    Класс ассимилирует в себе свою принадлежность. Следствием этого является простота написания маршрутизации, используемой при автозагрузке классов (через __autoload)
  4. Имена методов.
    - все публичные методы объявляются с самого начала и следуют названиям функций.
    - все защищенные (protected) методы начинаются с
    подчеркивания, следуя названиям функций
    - все приватные (private) методы начинаются с
    двойного подчеркивания, следуя названиям функций

1. Объявление сущностей.
Здесь имеется ввиду, что все переменные инициализируются, прежде чем будут использованы.
2. Избегать приемов, затрудняющих чтение имени.
Для PHP это, прежде всего, неочевидный динамический вызов. Нельзя сказать, что он - плох, и в ряде случаев его использование позволяет решить задачу красиво и лаконично, но злоупотреблять переменными-функциями и переменными-методами не стоит.

Кажому - свое
Помимо того, что сущности должны быть четко определены, иметь обозначенный (или обозримый) круг связей и отношений с другими сущностями, они должны еще и нести именно тот набор ролей/функций, которые отвечают их логическому обоснованию.
Иными словами, каждый метод класса должен решать именно ту задачу, для которой создавался, и никак не заботиться о чем-либо еще, никак не брать на себя какие-либо другие функции. Снова рассмотрим пример. Допустим, у нас есть функция, добавляющая пользователя в БД. У пользователя есть логин и пароль. Первый пример:
PHP:
скопировать код в буфер обмена
  1. function newuser_add($login, $password, $link=null)
  2. {
  3.    if(!$login || !$password)
  4.    {
  5.       return false;
  6.    }
  7.    if(!mysql_query('INSERT INTO users (login, password) VALUES ("'.mysql_real_escape_string($login)."', '".mysql_real_escape_string($password).'")', $link))
  8.    {
  9.       exit('Failed!');
  10.    }
  11.    return mysql_insert_id($link);
  12. }

И второй пример:
PHP:
скопировать код в буфер обмена
  1.  
  2. function checkUser($rgUser)
  3. {
  4.    $bResult=true;
  5.    array_walk($rgUser, function($mValue) use (&$bResult)
  6.    {
  7.       $bResult = $bResult && ($mValue!=='');
  8.    });
  9.    return $bResult;
  10. }
  11. function addUser($rgUser, $rLink)
  12. {
  13.    if(!checkUser($rgUser))
  14.    {
  15.       throw new Exception("Couldn't add user due to incompleted data fields");
  16.    }
  17.    if(!mysql_query('INSERT INTO users (login, password) VALUES ("'.mysql_real_escape_string($rgUser['login'])."', '".mysql_real_escape_string($rgUser['password']).'")', $rLink))
  18.    {
  19.       throw new Exception("Couldn't add user due to mysql-returned error: ".mysql_error());
  20.    }
  21.    return mysql_insert_id($rLink);
  22. }

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

То есть каждый метода/функция должен заниматься строго своей работой. Замечу, кстати, что в продемонстрированном примере из теории мы увидели обоснование того, что функция должна возвращать результат одного типа, так как в противном случае смысл результата как сущности теряется.

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


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Мелкий Супермодератор
Отправлено: 01 Декабря, 2011 - 11:07:54
Post Id



Активный участник


Покинул форум
Сообщений всего: 11888
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 614 раз(а)




Замечу, что у функции newuser_add третий параметр NULL равен быть не может, т.к. будет вызывать ошибку mysql_query.
Функцию addUser тоже поправь - переменные $login и $password берутся из неоткуда, передан-то массив Подмигивание

Кстати, давно хотел спросить - почему массив - rg? От чего образован? Остальные-то понятно.


-----
PostgreSQL DBA
 
 Top
EuGen Администратор
Отправлено: 01 Декабря, 2011 - 11:09:01
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Да, верно. Как понимаете, пишу без проверки. Исправлено.

rg - это от register

Касаемо newuser_add - так и задумано. Чтобы продемонстрировать, что неверно определенный тип данных может разрушить логику исполнения.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
DeepVarvar Супермодератор
Отправлено: 01 Декабря, 2011 - 12:12:26
Post Id



Активный участник


Покинул форум
Сообщений всего: 10378
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




EuGen пишет:
0. Избегать лишних сущностей в программе
Кажется к этому есть соответствующее очень старое слово "бамминг", т.е. сокращение программы и возможное или даже явное увеличение производительности.

Кстати хотел спросить верно ли я делаю когда слежу даже за кол-вом ссылок на объекты, а именно, если не нужен клон или копия объекта, то и ссылка на "фабрике" одна.
Видел как-то код где в конструктор всех объектов передавлась ссылка на "папу", в итоге на протяжении приложения плодилось 20 и более ссылок на него...
 
 Top
EuGen Администратор
Отправлено: 01 Декабря, 2011 - 12:16:07
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




DeepVarvar пишет:
Кажется к этому есть соответствующее очень старое слово "бамминг"

Задача - не сократить код предельно. Например, в случае с добавлением пользователя в этой статье, напротив, была выделена еще одна сущность, то есть по факту код стал длиннее.
Задача в том, чтобы не существовало лишнего, а то, что есть - не было перегружено ненужными вещами.
Следить за ссылками не вредно никогда, но превращать это в нечто маниакальное тоже не стоит.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
DeepVarvar Супермодератор
Отправлено: 01 Декабря, 2011 - 12:18:23
Post Id



Активный участник


Покинул форум
Сообщений всего: 10378
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Да, согласен, я не совсем в точку, когда был придуман "бамминг", ООП еще не было в помине.
И действительно, второй пример указывает именно на ООП подход.
(Добавление)
А что скажете насчет ссылок в моем вопросе?
 
 Top
EuGen Администратор
Отправлено: 01 Декабря, 2011 - 12:21:19
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




DeepVarvar пишет:
второй пример указывает именно на ООП подход.

Примерно такой и расчет. Однако, заметьте, там нет ни классов, ни объектов. Суть как раз в том, чтобы реализовывать парадигму ООП, это можно сделать и в таком простом примере.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
DlTA
Отправлено: 01 Декабря, 2011 - 12:24:39
Post Id



Постоянный участник


Покинул форум
Сообщений всего: 2914
Дата рег-ции: Окт. 2010  


Помог: 53 раз(а)




EuGen, я не знаю чем ты обромляешь
Спойлер (Отобразить)

можешь так больше не делать, у меня от этого появляется горизонтальная прокрутка, пипец как не удобно
 
 Top
EuGen Администратор
Отправлено: 01 Декабря, 2011 - 12:44:29
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




DlTA
Изменил форматирование, благодарю за замечание.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
DlTA
Отправлено: 01 Декабря, 2011 - 12:53:46
Post Id



Постоянный участник


Покинул форум
Сообщений всего: 2914
Дата рег-ции: Окт. 2010  


Помог: 53 раз(а)




спасибо
 
 Top
Bio man
Отправлено: 23 Февраля, 2012 - 16:03:27
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2752
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




как понять
EuGen пишет:
fn - для callback-данных
?
можно на примере показать что такое callback данные?

(Отредактировано автором: 23 Февраля, 2012 - 18:46:13)

 
 Top
Bio man
Отправлено: 23 Февраля, 2012 - 18:46:26
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2752
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




up
 
 Top
caballero
Отправлено: 23 Февраля, 2012 - 19:26:14
Post Id


Активный участник


Покинул форум
Сообщений всего: 6001
Дата рег-ции: Сент. 2011  
Откуда: Харьков


Помог: 126 раз(а)




Цитата:
Используются префиксы, указывающие на тип переменной, обозначая таким образом множество допустимых над ней операций.

"Венгерская" нотация в нетипизированном PHP - однако.

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


-----
Бесплатная система складского учета с открытым кодом https://zippy[dot]com[dot]ua/zstore
 
 Top
Bio man
Отправлено: 23 Февраля, 2012 - 21:58:35
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2752
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




так что такое callback данные?
 
 Top
EuGen Администратор
Отправлено: 23 Февраля, 2012 - 22:30:44
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Bio man
Навскидку:
PHP:
скопировать код в буфер обмена
  1. $fnTrimBrackets=function($sData)
  2. {
  3.    return trim($sData, '()[]{}');
  4. };
  5. //some code..
  6. $rgData=array_map($fnTrimBrackets, $rgData);
  7. //some code..

caballero
Личное дело каждого какой стиль выбрать. Выше - лишь рекомендации. А префиксы как раз и направлены на то, чтобы внести ясность, так как эта самая ясность отсутствует - нет строгой типизации.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 1 (гостей: 1, зарегистрированных: 0)
« Обсуждение статей »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB