Delphi programming blog
Источник: http://teran.karelia.pro/articles/item_4511.html
 

2 года блогу: пишем понятный код

Опубликовано 14.03.2012 г. 18:58

2 года назад в этом блоге появилась первая заметка, и они до сих пор продолжают появляться. Видимо пока я связан с Delphi, то они и будут продолжать появляться. Год назад в блоге было 58 статей, теперь уже 107. Т.е в этом году их количество немного поубавилось, и составляет 49 штук. Это хоть и немного меньше, но зато с уверенностью можно сказать, что качество статей стало лучше.

В списке самых популярных тем в этом году - Direct 2D и RTTI. Если первое изучалось только ради интереса, то второе принесло и практическую пользу в работе. Сейчас в статьях наблюдается явный перерыв, связан от части с тем, что для блога создается новый сайт, что, конечно, требует времени. Ну а помимо того, что у нас день рождения, хотелось бы попутно задеть одну простую тему - качества кода. Качество можно рассматривать с нескольких позиций. Конечно же первое место наверное стоит отдать такой составляющей, как знание языка и умение грамотно его применять. Но не только это важно. Качественный код должен быть простым, ясным, и легким для понимая. Особенно остро такой вопрос встает при передаче кода от одного человека к другому, либо же просто, когда вы заглядываете в свой код по прошествии длительного времени. В этом ключе можно так же рассматривать несколько аспектов:
  1. Форматирование кода. Хороший код всегда должен быть хорошо структурирован, иметь отступы, пробелы, соблюдение регистра символов в наименованиях, группировать однотипные блоки (в регионы например) и т.п. В том числе иметь единый стиль в рамках всего проекта. Здесь впрочем может помочь встроенный форматтер кода, правда и он не идеален.
  2. Второе - понятность используемых имен. Если имена ваши переменных/методов/классов не говорят сами за себя, то разобраться в таком коде будет очень не просто, даже если он написан с глубоким знанием языка, и имеет отличное форматирование.
если первый нюанс быстро исправляется, то чтобы исправить второй нужно сначала действительно понять для чего нужен класс/метод и т.п. А зачастую такое непонимание приводит к дальнейшему усложнению. Главное, что должен позволять делать код (в смысле его понятности), он должен быть таким, чтобы его нужно было не разбирать, а читать. Именно читать, как инструкцию. А чем инструкция проще, чем легче ее читать. Иногда, если вы не особо владеете языком, на котором написан код, вам сложно его и читать, и использовать. Т.е вы понимаете конструкцию как бы по частям, и не видите всей картины целиком. И это конечно влияет на то что вы в пишите, или не замечаете недостатков. Как вы наверное знаете, со времен Delphi 2009 существует возможность использовать русский язык в коде для имен. Поэтому для интереса, давайте рассмотрим небольшой пример русскоязычного кода. Как и принято будем руководствоваться правилами именования, но переиначим их. В нашем случае префикс класса - К, записи З, член/поле/переменная класса П. Для начала введем базовый класс, всего с парой методов:
    КОбъект = class(TObject)
      public
        constructor Создать();
        procedure Освободить();
    end;
а теперь опишем какой-нибудь класс наследник, например, пользователь:
    КПользователь = class(КОбъект)
      strict private
        ПИмя : string;
        ППароль : string;
        ПАвторизован : boolean;
      public
        procedure ЗапроситьАвторизацию(имяПользователя, парольПользователя : string);

        property Имя : string read ПИмя;
        property Авторизован : boolean read ПАвторизован;
    end;

    ИОшибкаАвторизации = class(Exception)
      private
        ППричина : string;
      public
        property ПричинаОшибки : string read ППричина;
    end;
и вариант использования этого кода:
var п : КПользователь;

begin
    п := КПользователь.Создать();
    try
        try

            п.ЗапроситьАвторизацию('ter', '...');
            if п.Авторизован then
                 writeln('hello', п.имя)
            else writeln('не верно указааны имя или пароль');

        except
            on и: ИОшибкаАвторизации do
                writeln(и.ПричинаОшибки););
        end;
    finally
        п.Освободить();
    end;
end.
Теперь программа превращается не в какой то код, а в действительно инструкцию:
  1. Создать пользователя
  2. Запросить авторизацию пользователя
  3. Если пользователь авторизован то п.4.
  4. Поприветствовать пользователя по имени
  5. в исключительном случае, вывести причину ошибки
  6. освободить пользователя
Я вас естественно не призываю писать на русском языке (: ибо это жесть какая то (: Но чем часто грешат начинающие программисты, это написания кода наподобие следующего (грубо говоря)
if (x = true) then сделатьЭто
else СделатьТо;
//или
if (x > 0 ) then  параметрПоложителен := true
else параметрПоложителен := false
А когда мы начинаем именно _читать_ код, то видя что-то вида "Если пользователь авторизован равно истина", сразу обращаешь внимание: зачем мне "авторизован равно истина", если я могу просто написать "если пользователь авторизован то.." Либо "Если икс строго больше нуля то параметрПоложителен равно истина, иначе параметрПоложителен равно Ложь", сразу же превратится в "параметрПоложителен := (x > 0)". На этой оптимистично ноте, заканчиваем заметку (:

Комментарии

Skydweller
15.03.2012 в 10:41

Форматирование кода. Хороший код всегда должен быть хорошо структурирован, иметь отступы, пробелы, соблюдение регистра символов в наименованиях, группировать однотипные блоки (в регионы например) и т.п. В том числе иметь единый стиль в рамках всего проекта. Здесь впрочем может помочь встроенный форматтер кода, правда и он не идеален.
Второе – понятность используемых имен. Если имена ваши переменных/методов/классов не говорят сами за себя, то разобраться в таком коде будет очень не просто, даже если он написан с глубоким знанием языка, и имеет отличное форматирование.

А как же разделение ответственности?

try
try
...
except
...
end;
finally
...
end;

Подобные вложения читаемости тоже не способствуют ;)
ter
15.03.2012 в 11:08
разделение ответственности в смысле отделение логики/доступа к данным/GUI? это конечно да, но больше относится к знаниям языка и профессиональным навыкам. имхо.

ну вложения может и не способствуют читаемости, но других вариантов здесь нет (:
Skydweller
15.03.2012 в 20:33
разделение ответственности в смысле отделение логики/доступа к данным/GUI?

Нет. Под разделением ответственности я имел ввиду, что каждый метод/объект отвечает только за себя. К примеру, класс КПользователь должен реализовывать логику связанную с пользователем. Он не должен еще уметь записывать файлы, вести логи и т.п.
Кстати зачем метод КПользователь.ЗапроситьАвторизацию принимает параметры? Метод класса должен работать надо объектом его класса. Мне кажется можно было бы сделать так:
constructor Создать(имяПользователя, парольПользователя : string);
,
а
procedure ЗапроситьАвторизацию();
ter
15.03.2012 в 20:39
ну это относится чисто к архитектуре, что не являлось целью данной заметки.
утверждение про конструктор когда то верно когда то нет. зависит от конкретных задач.
Skydweller
15.03.2012 в 20:12
Нет и нет :)
delphinotes
16.03.2012 в 00:29
А я за то, чтобы конструктор содержал как можно меньше параметров... иначе, со временем, там может вырасти целый огород :с)

... Помню, я как-то игрался с именами переменных на кириллице... только меня хватило минут на 20 - постоянные переключения раскладки туда-сюда (ведь ключевые слова - они на английском) - это пытка, которую можно пожелать лишь врагу :с).

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

Вообще, на эту тему есть очень хорошая книга: "Мартин Р. - Чистый код", советую.
Skydweller
16.03.2012 в 00:54
А я за то, чтобы конструктор содержал как можно меньше параметров… иначе, со временем, там может вырасти целый огород :с)

Я проповедую идею того, что конструктор должен возвращать максимально готовый к работе объект. Конструктор, как функция с множеством входных параметров это не есть хорошо. С этим я согласен.
В реализации teran'a можно было вообще не заморачиваться на ООП, а сделать одну функцию ЗапроситьАвторизацию (статическую например), которая принимала бы логин-пароль и выдавала бы результат проверки. :)
Вообще, на эту тему есть очень хорошая книга: «Мартин Р. – Чистый код», советую.

Читал. Согласен, хороший мануал. Именно в ней я вычитал про разделение ответственности объектов. Teran, она у вас кстати в конторе имеется ;)
ter
16.03.2012 в 10:46
Чистый код я уже начал читать, когда как то тут на часок отключали электричество (:

Илюха, что ты привязался к этому примеру (: он далеко не из реальной жизни, а написал лишь для демонстрации русских названий, т.е понятности именования наименований и чтения кода.
Anonymous
17.03.2012 в 04:32
Я надеюсь, код с кирилицей показан только для примера? Ибо в реальных задачах это не тру.
- Имя
- e-mail*
- Сайт
вы можете использовать теги [i],[b],[code],[quote]
Дополнительно