К примеру, когда разговор заходит о стиле оформления кода, обычно вы встречаете обсуждение нескольких стилей, какой из них удобнее, нагляднее и вообще "лучше" и "круче" в сферическом вакууме. Иногда можно встретить заметки в личных блогах, которые описывают стиль автора и чем он ему приглянулся. Другие читают это, вдохновляются и разрабатывают свой стиль: "я прочитал XYZ и выработал свой стиль: смесь этого с тем, добавив то, но вот здесь я делаю ABC, потому что DEF". "Нет такой вещи как 'правильный' стиль оформления - у каждого свои подходы". "Если так делает Embarcadero - это не значит, что это правильно: оформлять можно по-разному".
Звучит знакомо?
Я не помню, где я читал подобное обсуждение с разбором нескольких подобных стилей оформления кода, спором что лучше и т.д. Пока в итоге кто-то не озвучил разумную мысль: "Представляю, как бы нам всем было весело работать в одной команде".
Если вы немного подумаете, то отсюда следует такой вывод: в Delphi есть единственный правильный стандарт оформления кода, а все остальные - неверны.
Единственный верный стандарт
Этот стандарт - стандарт оформления кода от Borland/CodeGear/Embarcadero. То, в чём написаны исходники самой Delphi.
Позвольте мне пояснить, что в этом случае означает слово "правильный":
- Он не идеален.
- Вы можете предложить более читабельный вариант.
- Но это - единственный стиль оформления, который может претендовать на звание "стандарт".
Почему это так
Вы можете сказать: "но как же, вот я использую такое оформление - смотри, насколько оно лучше! Как этот ваш стиль может быть правильным, а мой - нет? Похожее оформление использует даже <человек-с-большим-именем>!".
Дело в том, что этот ваш стиль оформления не соблюдается никем, кроме вас (окей: и ещё пяти человек, которых вы вдохновили на него). Со стандартом оформления кода Delphi же знакомы все. Чувствуете разницу?
Посмотрите на это с другой стороны. Вот есть ANSI/ISO стандарт языка C++. Почему никому не приходит в голову его улучшить? Расширить - возможно, но не изменить/улучшить (похоже, расширение стандарта языка не имеет аналогии для стиля оформления кода). Почему? Потому что этим вы убиваете весь смысл стандарта! Его цель - быть единым и правильным. Вводя свой стандарт вы ничего не улучшаете. Вы просто вносите хаос, создавая ещё один стандарт (как стандартов может быть два?!). Джоэль Спольски хорошо сказал на эту тему.
Но это ещё не самое главное. Вот вы оформляете свой код так. Вася - сяк. А Петя - ещё как-то. И тут вам пришлось работать в одной команде, причём так, что каждый работает над всем кодом сразу, а не так, что каждый взял себе по куску и корпит над ним. Чтобы как-то скоординироваться, вы взяли стиль Васи, добавив к нему элементы от Пети и сказали: "так, народ, вот стандарт, которого вы все должны придерживаться" (иногда так делают в софтверных конторах: каждому приходящему работнику даётся описание стандарта оформления, которого придерживаются в фирме, и обязуют его следовать этим правилам; иногда так делают даже в университетах при сдаче работ).
Отлично, какое-то время вы работаете. Более или менее успешно, хотя Петя постоянно норовит скатится к своему оформлению (привычка-с!), и ему приходится срочно перелопачивать код перед commit-ом, чтобы не получить по шапке.
А потом за ваш проект берётся другая команда/контора, в которой принят другой стандарт оформления кода.
Опс.
Теперь они вынуждены переформатировать все исходники, или они превратятся в месиво стилей.
Другой пример: как насчёт автогенерируемого Delphi кода? Ведь он использует оформление, которое отличается от вашего. Будете тратить своё время на переписывание автосгенерированного кода или же оставите всё как есть, сохраняя смешение двух стилей (Delphi и вашего) в одном модуле? Как ни посмотри, и так и сяк - недостатки.
Как насчёт лёгкости чтения? Конечно, стиль оформления, на котором вы пишете, читается легче всего. Насколько легко вы воспримете стиль, в корне отличный от вашего? Я думаю, далеко не сразу. Как насчёт сразу двух-трёх разных стилей? Как на ваш стиль отреагируют ваши коллеги? Это положение особенно усугубляется, когда вы разрабатываете компонент, утилиту или библиотеку, которая будет доступна в исходных кодах вашим клиентам. Её увидит весь мир. Насколько они будут рады иметь дело с вашим доморощенным стилем?
С другой стороны, исходники Delphi читают все. Более того, у всех перед глазами фрагменты автосгенерированного кода. Поэтому ни у кого не возникнет особых затруднений с чтением кода, оформленного "как в Delphi". Разве это не здорово? Если вы пишете так, вы можете дать это любому человеку - и у него не будет проблем с восприятием этого кода. И он даже сможет писать так же. Новому работнику не надо будет учить новый для него стандарт: ведь со стилем Delphi он уже знаком.
Посмотрите на известные библиотеки и компоненты на Delphi. Откройте их код. Что вы увидите? Домашний стиль оформления автора кода? Или же стиль оформления кода Delphi?
(хинт для организаций: если вы хотите форсировать стиль оформления кода в своей конторе - не изобретайте "удобный" стандарт оформления: возьмите стандарт оформления кода Delphi!)
Вывод: если человек пишет, применяя свой личный стиль оформления, то либо это новичок, либо профессионал-одиночка, который никогда или очень мало работал в команде, либо человек, всю жизнь работающий в одной конторе с одним и тем же стилем оформления. Если же вам нужно взаимодействовать с другими людьми, командами, фирмами, то использование "своего" стиля - не самая лучшая идея.
Стандарт и привычка
"Но у меня привычка писать так! С чего бы я стал ломать свои привычки?!"
Знаете, я когда-то писал по-другому, ещё со времён Turbo Pascal. Begin я сдвигал в блок, а отступ у меня был в один пробел, а не в два, вот так:
procedure Proc; begin DoSomething; DoSomethingElse; if Condition then begin DoAnotherThing; DoAnotherThingMore; end; DoSomethingMore; end;Не суть важно, как возник этот стиль - я думаю, что у каждого когда-то был (или есть) такой "свой" персональный стиль оформления кода.
Так вот, после того, как я понатыкался ещё на кучу подобных "самоделкиных" стандартов (некоторые из которых были достаточно далеки от моего), я сказал себе: "всё, стоп, хватит с меня". И насильно заставил писать себя так:
procedure Proc; begin DoSomething; DoSomethingElse; if Condition then begin DoAnotherThing; DoAnotherThingMore; end; DoSomethingMore; end;А потом это вошло в привычку.
Зачем вообще нужно себя так ломать? Тут, конечно, решать вам, но я считаю, что бонусы следования стандарту Delphi стоят того, чтобы изменить свои привычки. Избавляйтесь от плохих привычек (свой стандарт), заводите хорошие (стандарт Delphi).
Но что же это за стандарт оформления кода Delphi?
Ну, вы все его видели - достаточно открыть любой стандартный модуль Delphi. Если вы хотите начать ему следовать, вы можете или изучать скучное формальное описание (на момент написания заметки, сайт немного в дауне) или же вы можете открыть модуль Delphi и писать "по аналогии". К сожалению, никакого официального Delphi Programming Code Style Guidelines я не нашёл.
Здесь надо понимать, что оформление кода в Delphi не является строго формализованным. Оно иногда меняется со временем, но очень незначительно. Поэтому мелкие детали могут оставаться на ваш выбор, но основные вещи - фиксированы.
Автоматическое форматирование
Ну, с появлением Code Formatter в Delphi 2010, стиль кода Delphi получает ещё бонусных очков.
Понятно, что вы можете не ломать свои привычки, а просто прогонять свой код через средство автоматического форматирования кода.
(вероятно, это будет неплохой идеей: форсированно прогонять исходники через авто-форматтер перед commit-ом кода)
Конечно, тут ваш выбор. Лично мне было проще один раз перейти к стандартному стилю, чем каждый раз гонять код через форматтер. Да и автоматическое форматирование может быть не идеальным, в некоторых местах получается красивее сделать руками. Иногда оно не способно обрабатывать некоторые ситуации (типа лишних скобок). Да и навряд ли вы станете делать переформатирование во всех случаях - к примеру, при выкладывании кода на форум.
Но тут, в общем-то, ваш выбор. Лично я - за смену привычек.
Хорошим компромиссом видится автоматическое форматирование базовых вещей, а затем доводка тонких моментов вручную.
А бывают ли ситуации, когда можно/нужно нарушать стандарт?
Да, иногда они бывают. Но очень редко и на это нужна хорошая и веская причина (понятно, что хорошая и веская причина для вас может не быть таковой для кого-то другого).
Я дам только один пример. Это субъективно, поэтому можете не начинать "это не стоит того!". Просто лучшего мне в голову сейчас не приходит.
В Delphi все модули в uses пишутся так:
uses Windows, SysUtils, Classes, Controls;Возможно, вы захотите нарушить это правило и писать так:
uses Windows, SysUtils, Classes, Controls;Почему? Сравнение изменений в модулях намного проще делается во втором случае, чем в первом. Во втором вы увидите новые и удалённые строки - это новые и удалённые модули. В первом - вы увидите изменения в строке. Чтобы понять, какие модули были добавлены, а какие удалены - понадобится время.
Но в любых случаях, как бы вам ни хотелось "улучшить" стандарт - семь раз подумайте и... откажитесь. Потому что тогда это не будет общим стандартом Delphi.
Только хорошо бы отличать стиль оформления кода от содержания модуля. Например, комментарий в начале модуля (копирайты, описание модуля, changelog и т.п.) не относится к стилю оформления, а является, скорее, более высоким уровнем (стиль кода - это как писать; указанный комментарий и аналогичные элементы - это что писать).
Во многих инструментах для работы с системами контроля версий есть события (хуки), позволяющие выполнить нужную команду перед коммитом. И это даёт возможность автоматически запускать автоформатирование кода перед каждым коммитом.
ОтветитьУдалитьА вообще согласен с идеей, но все uses файлы, кроме стандартных всё-равно пишу в столбик. Так намного проще просматривать изменения и, что немаловажно, писать комментарии с примечанием о причинах по которым этот модуль включён в секцию uses (например, для того, чтобы секция инициалазции выполнилась).
Труд программиста по законодательству РФ приравнивается к труду писателя.
ОтветитьУдалитьПисатели бывают разные, есть те кто умеет писать прозу, а есть и те, кто умеет писать стихи. Дополняя мысль хочу сказать, что высший идеал для Delphi программистов - писать Delphiстишья.
А насчет исключений - это уже зависит направленности произведения. Если в коде очень часто встречаются операторы if(а такое даже в исходниках редко встречается), имеет смысл прменять конструкцию вида
if Condition1
then begin
if Condition2
then begin
end
else begin
end
end
else begin
end
Особенно, если Condition подобно небольшому лирическому отступлению.
>>> Особенно, если Condition подобно небольшому лирическому отступлению
ОтветитьУдалитьОбычно такие условия имеет смысл выделять в отдельную функцию. Это, правда, уже не стиль оформления, а рефакторинг, но вещь тоже немаловажная.
В предыдущем посте плохо видны отступы, предполагалось что end будет вровень с begin, как и текст между begin и end...
ОтветитьУдалитьОбычно такие условия имеет смысл выделять в отдельную функцию
ОтветитьУдалитьЭто верно, но время затраченное на придумывание осмысленного названия такой процедуры(и степень осмысленности), не всегда соответствует сложности задачи. Что тоже, кстати, весьма немаловажно в программировании.
>К сожалению, никакого официального Delphi Programming Code Style Guidelines я не нашёл.
ОтветитьУдалитьМожет вот этот документ близок к официальному:)
Спасибо за ссылку!
ОтветитьУдалитьНашёл ещё более строгий вариант от JCL.
ОтветитьУдалитьА есть ли в Delphi 7 Code Formatter?
ОтветитьУдалитьВ Delphi 7 встроенного форметтера кода нет.
ОтветитьУдалитьНо это не мешает вам использовать любое стороннее решение.
Например, JEDI Code Formatter, DelForEx (видимо, сокращение от Delphi Formatting Expert) или любой другой вариант. Можете для начала посмотреть, нет ли такого инструмента в вашем любимом наборе экспертов.
А я вот прогоняю через форматер каждый раз как напишу процедуру или изменю её код - это уже привычка. Стандартное форматирование дает возможность находить код там, где его ожидаешь, а не там где Вася вчера подумал лучше для него.
ОтветитьУдалитьHовичок спросил у Мастера:
ОтветитьУдалить- Я видел программиста, который никогда не оформляет, не тестирует и не документирует программы. Hо все кто знает его считают его одним из лучших программистов в мире. Почему так?
Мастер ответил:
- Этот программист овладел Дао. Он больше не нуждается в оформлении; он не злится, когда система зависает, но принимает мироздание без раздражения. Он давно не нуждается в документации; он больше не беспокоится о том, что кто-то еще увидит его код. Он больше не нуждается в тестировании; каждая из его программ совершенна сама по себе, ясна и элегантна, ее назначение очевидно. Истинно вошел он в таинство Дао!
Стиль должен быть.
ОтветитьУдалитьА какой он будет - дело десятое.
Исходники от дельфи грешат дикими отступлениями. До момента внедрения FastMM исходник манагера памяти (вроде getmem.inc) "образец" стиля.
Еще можно grids.pas (от версии дельфи 7, например) - тоже хороший стиль: голову сломаешь, чтобы понять эти 6 тыщ строк.
Вернусь к тому, с чего начал - я думаю, что главное, чтобы стиль был, а конкретный образец стиля не столь важен - главное, чтобы команда и сам разработчик в этом стиле хорошо ориентировались.
>>> Исходники от дельфи грешат дикими отступлениями.
ОтветитьУдалитьПоздравляю, вы нашли баг:
"I want to reiterate that on the Borland web site, and on the CDs that we ship with our product, these standards are the law. We want to present our code in a unified and easy to read style, and enforcing the rules in this guide is the simplest way to achieve that end." - источник.
Мне не очень понятен тон ответа.
ОтветитьУдалитьЯ не нашел бага. Я за то, что сами разработчики Delphi не всегда следуют своему же стандарту.
Очень распространенное отклонение - надо ли после then писать с новой строки, если строка кода одна?
Вот для примера код из controls.pas для дельфи 2007.
function TWinControl.GetControlExtents: TRect;
var
I: Integer;
begin
Result := Rect(MaxInt, MaxInt, 0, 0);
for I := 0 to ControlCount - 1 do
with Controls[I] do
if Visible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle) then
begin
if Margins.ControlLeft < Result.Left then Result.Left := Margins.ControlLeft;
if Margins.ControlTop < Result.Top then Result.Top := Margins.ControlTop;
if Margins.ControlLeft + Margins.ControlWidth > Result.Right then
Result.Right := Margins.ControlLeft + Margins.ControlWidth;
if Margins.ControlTop + Margins.ControlHeight > Result.Bottom then
Result.Bottom := Margins.ControlTop + Margins.ControlHeight;
end;
end;
Хотя в стандарте, приведенном Вами они пишут
8.2.3 if statement
If statements should always appear on at least two lines.
Example:
// INCORRECT
if A < B then DoSomething;
// CORRECT
if A < B then
DoSomething;
Я хочу сказать, что в любом случае стандарт должен быть свой. Скорее всего, его надо основывать на стандарте разработчиков Delphi. Но можно и свой дописать.
Например, в JEDI стандарт предписывает писать begin и end даже для одной строки блока.
Имелось ввиду следующее: не в курсе как в Embarcadero, а в Borland со стилем было так: указанные по ссылке правила - это закон. И если вы нашли фрагмент кода, оформленный не по правилам, то это - баг. Ну не досмотрели, а не потому, что "они сами свой стандарт не соблюдают".
ОтветитьУдалитьК сожалению, нет никакого более нового варианта указанных правил.
Спасибо, любопытно!
ОтветитьУдалитьВ самом деле, стиль надо приближать к стандартному. Однако всё-таки иногда можно слегка от него отступить во имя удобства и красоты. Тот же упомянутый пример с then.
If error then Exit; - не очень-то хочется разбивать это на две строки!
или даже так
if error then begin long_line_to_report_to_log_about_error; result := -1; exit; end;
выстраивать это добро в столбик - страта строчек.
Единственное расширение стандарта, которое используется нашей командой разработки - это префиксы перед именами локальных и глобальных (когда они бывают, конечно) переменных и констант. Для локальных переменных используем префикс "v", для глобальных переменных - "l", для всех констант - "c". Это, кстати, стыкуется с соглашением в Delphi для параметров методов использовать префикс "a" (тоже используем всегда).
ОтветитьУдалитьДолго думали, насколько стоит нарушать стандарт таким образом. После экспериментов решили, что читаемость кода повышается настолько, что оправдывает несовместимость.
Конечно, префиксы не используются для односимвольных переменных (типа "i")
ОтветитьУдалитьВыскажу свое мнение.
ОтветитьУдалитьВо-первых, наличие стандарта (хоть какого-то) гораздо лучше, чем отсутствие оного.
Во-вторых, стандарт, кроме собственного существования должен преследовать или даже создаваться для выполнения конкретных целей.
Основная цель стандарта, кроме "всеобщей привычки", это - читаемость кода. Как следствие - его "красота". Если под "читаемостью кода" понимать возможность быстро понять, что же код выполняет и для чего конкретно нужны операторы и блоки кода, то читаемость кода определяется "законченностью мысли" в видимом на экране куске кода. Отсюда следует правило, что одна процедура (функция) не должна занимать более двух-трех "экранов". Размеры дисплеев растут, так что это требование со временем прогрессирует.
Так вот в существующем стандарте есть явное противоречие, которое заключается в том, что много строк занимают операторы, не несущие никакой смысловой нагрузки. Например:
01. if exp1 then
02. begin
03. doIt1;
04. end
05. else
06. if exp2 then
07. begin
08. doIt2;
09. end
10. else
11. begin
12. doIt0;
13. end;
01. if exp1 then begin
02. doIt1;
03. end else if exp2 then begin
04. doIt2;
05. end else begin
06. doIt0;
07. end;
В обоих случаях выполняется один и то же код, но количество строк отличается в два раза за счет строк не несущих смысла. Например в строках
09. end
10. else
11. begin
смысловую нагрузку несет только слово .
Применяя стандарт Delphi мы теряем читаемость.
Дополнением к стандарту второго случая нужно только добавить правило обязательного применения , тогда будет подразумеваться, что последним словом в строке оператора всегда будет , что совершенно не сложно добавить в Code Templates
А вот конструкцию,
0. // CORRECT
1. if Condition then
2. begin
3. DoThis;
4. end else
5. DoSomething;
допускаемую в стандарте, я бы вообще запретил как вредную, особенно, если DoSomething представляет из себя функцию API с порядка 20-ю параметрами, выстроенными в столбец.
>>> Применяя стандарт Delphi мы теряем читаемость.
ОтветитьУдалитьВы забываете, что "читаемость" - понятие субъективное, как и "красота". Что-то, хорошо воспринимаемое одним, будет плохо восприниматься другим.
К примеру, я ненавижу if ... then begin, потому что begin не будет на одной вертикальной позиции с end. Этот стиль затрудняет чтение кода для меня, потому что мне сложнее находить соответствия begin/end-ам.
все здорово, только всетаки хотелось бы узнать как отключить перевод строки после THEN? или такой возможности у них вообще не предусмотрено?
ОтветитьУдалитьЯ когда-то писал сайты в одну строку, а сейчас тоже как и вы делаю отступы. Так даже удобнее!
ОтветитьУдалитьРассмотрим ситуацию из жизни (такое может быть):
ОтветитьУдалитьВ софтверную компанию берут разработчика Delphi, который удовлетворяет компанию по всем параметрам (прошёл собеседование и разгромил своих конкурентов в «пух и прах»), а ему хочется работать именно в этой компании (к примеру ему нравится направление деятельности и возможности реализовать свой потенциал как разработчика ПО). Тем более ему там равных в разработке на Delphi нет, т.к. у него за плечами более крупные проекты.
Допустим стандарт написания кода у компании свой, сильно отличающейся от стандарта Delphi.
Разработчик когда начинает работать в этой компании и компания навязывает ему свой стандарт. Ему приходиться себя ломать. Продуктивность подает сильно и он не может реализовать свой потенциал (при том что он уже давно в ник в суть самой работы). Из месяца в месяц он ломает себя и энтузиазм уже не тот какой был до.
Моё мнение не придерживаются стандарта только те кто не хочет изменять своим приычкам.
Согласен с GunSmoker о ненависти к if ... then begin… Я не смог прочитать 1й вариант, а в2й с лёту.
Для меня всегда был пример оформление библиотеки VCL.
Перепутал. Код из 13 строк для меня более читабельный чем из 7.
ОтветитьУдалить> количество строк отличается в два раза за счет строк не несущих смысла
ОтветитьУдалитьСам ты, "не несущий смысла"! Эти строки как раз смысл и несут. Пусть не синтаксический, но они выполняют важную роль - помогают визуально определять границы блоков. и "if" всегда стоит в начале строки, а не абы где, где его не найти.
Чего б тебе в одну строку без пробелов не писать, раз так тебя заботят лишняя пара #13#10?
А я пишу вот так обычно:
ОтветитьУдалить`procedure Proc;
`begin
` DoSomething;
` DoSomethingElse;
` if Condition then begin
` DoAnotherThing;
` DoAnotherThingMore
` end else begin
` DoAnotherThing;
` DoAnotherThingMore
` end
` DoSomethingMore
`end;
Отступы в 2 пробела, если шрифт собьётся.
Отличия в том, что begin на одной строке с then/else/do, а также в отсутствии точки с запятой там, где это не нужно.
Смысл прост - легче читать. И на C/C++ также скобки ставил.
А насчёт точек с запятой - а зачем писать то, что НЕ нужно вообще? Инкрустация? Производитель Delphi, видать, сам не знает, что его компилятор игнорирует...
кто-то так пишет:
ОтветитьУдалитьfor i:=0 to foo.Count-1
do if condition
then if another_condition then
begin
или
with foobish.create
do try
barbish;
finally
Free;
end;
мотивируя тем, что "легче читать". Вопрос - кому легче ? :)