Первый раз когда я заговорил о юзабилити кода на меня посмотрели косо, когда же я начал объяснять, то встретил понимание у коллег по цеху. Теперь попробую и вам донести до чего я тут дошел с жизнью такой.
«Usability кода» звучит хорошо, название притягивает, еще мне нравится «эргономика кода», тоже отлично
Ну что же, в понятие юзабилити кода я вкладываю несколько вещей:
- Соблюдение стандартов кодирования
- Отсутствие избыточности в коде и комментариях
- Предсказуемость кода
- Поддержка читаемости кода на уровне «понятно и чайнику»
- Время необходимое для изучение кода до уровня «понимаю где баг глядя на скриншот»
- Скорость разработки при повторном использовании кода и соблюдении принятых норм и стандартов
Думаю, стоит по чуть-чуть остановиться на каждом.
Стандарты кодирования
Тут обсуждать нечего, ты либо их соблюдаешь (хотя бы свои, но лучше принятые в своей среде), либо ты тут временно, и никому не будешь нужен.
Избыточность кода
Иногда, гоняясь за красотой ООП мы приходим к очень громоздким решениям:
$file = Application::getInstance()->getRequest()->getFiles()->get($filename);
По сути — думаю каждому понятно что делает данная строчка кода, но почему же не заменить ее на простую функцию? Чего боитесь?
$file = getRequestFile($filename); // процедурное программирование отстой, бла-бла-бла $file = Request::getFile($filename); // выучи еще патерны // ...
Баланс на грани
Бытует мнение, что комментировать хорошо читаемый код не стоит, и так всем всё понятно, но мне в это слабо верится, так что я тут несколько тезисов написал:
- Отсутствие комментариев в коде — плохо
- Правильное именование переменных в коде — хорошо
- Много комментариев с прогнозом погоды — плохо
Что же хорошо? Вот тут вроде бы баланс удалось соблюсти:
/** * Check-in user location to DB * * <code>Location::checkinUser($User, 2.123654, 0.456321)</code> * * @param User $User * @param float $lat latitude * @param float $long longitude * @return bool */ function checkinUser(User $User, $lat, $long) { return Db::insert("checkin", array( 'userId' => $User->id, 'lat' => $lat, 'long' => $long )); }
В данном примере постарался уместить все, что нужно: однозначные имена методов и переменных, минимум комментариев, которых хватает для создания документации по проекту, да подсказок в IDE (что немаловажно!).
Быть провидцем
Если вам приходится работать с незнакомым кодом и мысли «я бы на месте предыдущего разработчика сделал это так-то» совпадают с реальность — поздравляю, у вас совместимость с предыдущим автором, и вы сможете легко работать с текущим кодом. Так что пишите код «предсказуемо», и это не только соблюдение правил использования глаголов в именах методов, но и простая, читаемая структуру кода.
Читаемость кода
Чего хочу я от читаемого кода? Это чтобы любой разработчик «со словариком» мог прочитать любой участок вашего кода. Я могу не знать JAVA, Python, или еще с десяток языков, но у меня есть знание о PHP и JavaScript, я и должен взяв на вооружение что-то типа «RoR для чайников» в качестве словарика и начать работать в проекте спустя день (ну уж лучше «Rails for PHP Developers», но это придирки).
Не должно быть магии по шпаргалкам — «достать объект не знаю где, вызвать метод не знаю как»:
// привет ZF public function errorAction() { // магия тут $errors = $this->_getParam('error_handler'); // а тут правдоподобно $this->getResponse()->setHttpResponseCode(404); // ни шатко, ни валко, но все в курсе $this->view->message = 'Page not found'; }
В идеале, читаемость кода должна быть на уровне псевдокода.
Еще есть такая болезнь — когда из шаблонов проектирования знаешь лишь singleton, конечно же это плохо, но вот юзабельность кода, если оный применять с умом, очень даже ничего:
// тут без комментариев понятно что происходит $id = Application::getRequest()->getParam('id'); // и тут $User = UserManager::getById($id);
Где баг?
MVC очень правильный патерн для web приложения, он удобен и всё такое прочее — имхо, вполне юзабельный. Но вот беда, в большом приложении контроллеров много, и по этой причине появилась тенденция объединять их в модули (что вполне логично), а сами контроллеры бить на экшены (что возможно избыточно). Таким образом контроллер стал составным, и знаком нам по многим фреймворкам — модуль/контроллер/экшен. Всё хорошо, и URL к такому контроллеру выглядит адекватно и читается легко, но пришли требования, и нам приходится писать правила-роуты, и теперь URL запрошенной страницы стал совсем неоднозначным для нас. Следовательно надо просмотреть все эти роуты, которые, возможно, расфасованы по модулям, иль еще куда, да елки ж палки…
К чему я тут это всё рассказываю? Да к тому, что чем больше действий мне надо выполнить для локализации ошибки в приложении, тем меньше мне такой код нравится. Вижу баг, знаю до файла и даже строчки где искать — отличный результат.
Время — деньги
Время потраченное непосредственно на сам кодинг оценивают в 30%, но это при проектировании «до запятой», но как-то усидчивости у нас не хватает, не наш метод. По этой причине стоит писать удобный код:
// можем же, мляяяять $bootstrap = $application->getBootstrap(); $bootstrap->bootstrap('db'); $dbAdapter = $bootstrap->getResource('db'); $dbAdapter->getConnection()->exec($dataSql); // но как-то сподручнее $application->getDb()->exec($dataSql);
Если расширение функционала приводит к копи-пасту — WTF man?
Вместо выводов
Если бы разработчики фреймворков думали не о красоте ООП, а о эргономике кода, то таких популярных и удобных фреймворков как jQuery было бы больше :)
P.S. В обязательном порядке, продумать юзабилити кода необходимо всем, кто собирается разрабатывать иль модифицировать очередной фреймворк, ведь удобный инструмент всегда найдет своего мастера.
P.P.S. По теме нашел лишь одну статью — Introducing Code Usability, возможно кто подскажет еще?
P.P.P.S. Поругал ZF, похвалил jQuery — OK
спасибо за статью.
function checkinUser(User $User, $lat, $long)
почему не соблюдается code style? или это такой code style?
Вы про CamelCase или о чем?
да
Да, это лично моё отклонение от нормы
По этому поводу целая библия написана – Code Complete МакКоннелла. У него белой нитью идёт идея об управлении сложностью.
Ссылку на перевод “книги” можно?
Хм, я в бумажном виде читал – “Совершенный код” в русском варианте.
А примеры по эргономике ZF в вашей практике можно увидеть?)
P.S. Незнаю по чему, но MooTools мне больше нравится, как раз из-за более ООП стиля в программировании.
Кстати, в ZF 2.0 вообще очень жестокое раздереление на модули, если в ZF 1.* общие модели еще можно выделить в application/models, то в ZF 2.0 все на namespace, разделение на модули и да же js и css призывают хранить в папке с конкретным модулем и собирать воедино сборщиком кода.
Хотя остается вариант выделять общее в library, но ни счетаю что это очень красиво.
Присмотрись к Yii – они какраз не стали мудрить ООП ради ООП, а использовали его столько, сколько надо. В итоге всё довольно просто, логично и достаточно не многословно :)
было бы отлично прочитать как вы видите фреймворк который максимально возможно подходит вам для работы. не сферический в вакууме, а именно такой который удобно пользовать постоянно
какие требования к структуре, чего там обязательно должно быть, а чего нет и т. п.
Рекомендую по теме книгу издательства O’Reilly авторов Dustin Boswell и Trevor Foucher “The Art of Readable Code”. Можно найти в сети в pdf
Є досить хороша книжка – “Clean Code”, рекомендую почитати.
Не сочти за холивар. Но добиться читаемости кода до того уровня чтобы его не нужно было комментировать php не позволит, а вообще такое вполне возможно для примера
ruby
@users = User.all
ruby
Checkin.new(params[:checkin])
ruby
user_signed_in?
ruby
class User
attr_accessor :name, :surname
end
ruby
match ‘user/:username’ => “user#info”
Не сочту, но и привычные конструкции для RoR тоже неахти читаются разработчиками других языков ;)
Хотя местами Ruby бесспорно хорош.
ruby & ROR – это для гомиков! и что это за хрень?:
ruby
user_signed_in?
– в php:
if ($user_signed_in){}
это хелпер devise пакета, который генерит код контроллеров, вьюшки, хелперы и роуты для регистрации, авторизации, конфирмации на мыло, восстановление пароля, запомнить меня 2умя коммандами с консоли :)