Немецкий секс или перевод проекта с Delphi 1 на Delphi 3

1. Новое задание
Как-то подходит ко мне начальник и говорит:
- А вы проект с Delphi 1 на Delphi 3 перевести можете ?
- Как два байта переслать - говорю я. Но, вспомнив о ReportSmith и о перетаскивании отчетов с одной версии QuickReport на другую, я добавил: - ну если там будут отчеты, то это будет намного сложнее.
Прошло несколько недель. Меня вызывает директор фирмы и говорит:
- Есть заказ от немцев. Надо проект с Delphi 1 на Delphi 3 перевести. Ты руководишь проектом. Поставь их программу, глянь исходники, разберись и оцени трудоемкость. Для вас эта работа полезна. Посмотрите западный стиль программирования, поучитесь.
Дали мне задание, архивы с исходниками и инсталлятором. В задании было написано:
- перевести базу данных с Access -2 на Access -97;
- изменить исходные коды, так, что бы получить 32-bit EXE-файл на Delphi 3;
- оптимизировать исходные тексты, общие процедуры и функции повторяющиеся в разных модулях вынести в один;
- изменить подключение к базе данных – вместо ODBC использовать BDE native drivers.
Роюсь в старых компактах, нахожу Access-2 и Delphi 1 - ставлю. Затем распаковываю немецкий инсталлятор, а там несколько каталогов и куча всяких файлов, для их установки требуется какой-то WinINSTALL 5.1 (Network Application Installer for Windows (c) Copyright 1991-1997 by Seagate Software, Inc.). Спросил у людей – никто о нем и не слышал. Посмотрел, а файл описывающий действия инсталлятора в текстовом виде, да и поставил все это ручками по командам в этом файле: скопировал файлы, настроил пути в ini-файле, настроил ODBC и BDE.
После часов двух работы немецкое детище заработало. Оно представляло собой систему поверки оборудования и состояло из трех частей (программы для снятия показаний с оборудования нам переделывать не надо): из головной программы и двух программ по обработке данных полученных при тестировании оборудования. Отчетов не было. Головная программа копировала обработанные данные в базу на сети. Посмотрев задачу, на утро я дал заключение:
- Если не напрягаться, то на выполнение задания надо около месяца.
Посоветовавшись, немцам зарядили трудоемкость два месяца - денег больше и время на решение непредвиденных обстоятельств было бы.



2. Стиль программирования
Начав работу над кодом мы быстро ознакомились с их "стилем программирования":
1) Все формы находились в автокрейт (наверно для экономии ресурсов :-))
2) На нескольких формах проекта находились объекты TDatabase, которые дублировали друг друга (в них указаны одни и те же алиасы) и периодически открывались и закрывались
3) Сотни неиспользуемых переменных
4) В одной процедуре они несколько раз могли динамически создать один и тот же объект, провести с ним какие то операции, убить его... Например они частенько создавали TQuery и TTable
5) Для подсчета количества записей в таблице они динамически создавали объект TTable, открывали и получив RecordCount - высвобождали объект. Правда RecordCount они использовали редко, чаще можно было видеть:
  nli := 0;
  While not TempTable.EOF do
    begin
    nli := nli +1;
    Next;
   end;
Спрашивается, почему бы не выполнить запрос "SELECT COUNT(*)" ? Также они проверяли пуста ли таблица.
6) Метод Prepare у Query вызывался после каждого динамического задания текста запроса, даже когда запрос не имел параметров или вызывался один раз. Зачастую использовались такие конструкции:
  For i:=0 to k do
   begin
    TempQuery.SQL.Clear;
    TempQuery.SQL.Add('SELECT * FROM TABLE');
    TempQuery.SQL.Add('WHERE Z=:Z');
    TempQuery.Prepare;
    TempQuery.Params[0].asInteger := i;
    TempQuery.Open;
    ...
    TempQuery.Close;
   end;
7) Глаз резали конструкции:
  if A.Count > 0 Then
   btn_Delete.Enabled := True
  else
   btn_Delete.Enabled := False;
Почему их не заменить на более простую
  btn_Delete.Enabled := A.Count > 0 ?

или

  if (Row = 7) Or (Row = 6 )
    Then CanSelect := True
    else Canselect := False;
Почему их не заменить на более простую
  CanSelect := (Row = 7) or (Row = 6 );

или похожая

  if (bNumForm = True) Or (bTimeForm = True)
    Then Result := True
    else Result := False;
заменить на
    Result := bNumForm Or bTimeForm;

8) Про оптимизацию процедур:
Var
    nlCol : longint;
begin
  nlCol := grd_stat_istwerte.Col;
  if nlCol < 8 Then
    grd_stat_istwerte.LeftCol := 1;
  if nlCol >= 8 Then
    grd_stat_istwerte.LeftCol := nlCol -6;
End;

Можно заменить

begin
  if grd_stat_istwerte.Col < 8
    Then grd_stat_istwerte.LeftCol := 1
    else grd_stat_istwerte.LeftCol := grd_stat_istwerte.Col -6;
end;

9) Работа с таблицами была немного странной:
  if ta_SS.Active = False Then
    ta_SS.Open;
  if not (ta_SS.State = dsEdit) Then
    ta_SS.Edit;
  try
    ta_SS.Post;
  except
  end;
Почему бы сразу проверки состояние таблицы, если она редактировалась не вызвать метод Post ?
  if ta_SS.State = dsEdit then
    ta_SS.Post;

10) Если на различные события нужен был одинаковый обработчик, то его код повторялся (при необходимости много раз).



3. Что не взлюбил компилятор D3
Сразу при компиляции исходного текста полезли ошибки:
1. Переменные цикла изменялись внутри цикла:
  For i:=1 to k do
   begin
    ....
    i := x-1;
   end;
2. В операциях со строками использовалась хитрые операции:
 - операция ++
  messagetxt := 'Ihre '+IntToStr(i) ++ ' fertige';
 - операция := +
  messagetxt := + stText+'tot';
3. В связи с тем, что String теперь не 256 байт, а до двух гигабайт, то конструкции для определения длины строки Path[0] пришлось заменять на Length(Path) (Path - String)
4. Если функция была описана как
  function zformat(Var Text : String) : Boolean;
 то следующий код вызывал несовпадение типов:
  Var
   st : String[5];
  Begin
   ...
   if zformat(st) = True then
5. В конструкциях
  With TempQuery do
   begin
    ...
    FindFirst(file_path, faAnyFile, SearchRec); // поиск файла
    ...
   end;
компилятор ругался на неправильные параметры у FindFirst, т.к. воспринимал как метод у объекта (TempQuery.FindFirst), в таких местах пришлось править на SysUtils.FindFirst



4. Исправление ошибок
Ошибки лезли отовсюду. Вот несколько - самых распостраненных:
1. Зачастую переменные цикла использовались и после завершения цикла. Если в Delphi1 после выполнения цикла for i:=1 to k переменная i имела значение k, то в Delphi 3 переменная принимала значение k+1, что естественно приводило к неправильному функционированию программы в целом.
2. Если составной индекс в БД создан из трех полей, а в программе для поиска задавалось IndexFieldNames := 'id;vor' - два поля из индекса, то после вызова GotoKey ничего не находил. Пришлось создавать новые индексы.



5. Работа над ошибками
Завершив работу досрочно все упаковали и кинули немцам на тестирование. Через неделю пришел ответ: "Тестировать сейчас некогда, т.к. люди заняты в других проектах. Мы вам доверяем тестирование. Предлагаем вам снять копии экранов с 16-бит приложения и соответствующие им 32-битные картинки." Повозмущавшись, мы наснимали им чуть больше 50 мег картинок. Отослав их мы спокойно жили несколько недель. Затем пришел файл от немцев с описанием замечаний и ошибок. Ошибки были страшные:
- увеличить длину Label, т.к. надписи у них не помещаются;
- растянуть кнопки, чтобы надпись помещалась. Прикол был с кнопкой Cancel: задаем Kind равный bkCancel у нас надпись помещается, а у немцев под немецкой Delphi вместо "Cancel" выводится "Abrechen", которое не помещается на кнопке.
- зачастую для редактирования данных использовался StringGrid, положение и размер которого на диалоге рассчитываются в программе. Количество колонок, строк, их высота и длина тоже рассчитывались. После перехода на Delphi 3 гриды сдвинулись, текст перестал помещаться в ячейки, появились скролбары. Для каждого пришлось подбирать оптимальный размер на форме и коэффициенты для расчета высоты и длины ячеек.
- В шапке некоторых гридов был установлен стиль у шрифта fsBold, им это в 32-bit версии не понравилось - слишком жирный шрифт (в 16-bit было нормально).
- Для тог, чтобы немцы вводили четыре цифры года мы вставили ShortDateFormat:='dd.mm.yyyy'. Из-за этого кое где на диалогах появилась дата 0208.19.99 - результаты форматирования и старых шаблонов.



В результате один наш сотрудник на неделю ездил в Германию, для исправления ошибок. Как оказалось, ПО которое мы дорабатывали, писал самый толковый программист в их конторе.

Данная статья конечно не отражает уровень разработчиков ПО в неметчине, но заставляет задуматься. О подобных случаях частенько рассказывают знакомые, которые работают на западных заказчиков.

Copyright© 1999 Scrooge  Специально для Delphi Plus

2011123456789101112
2010123456789101112
2009123456789101112
2008123456789101112
2007123456789101112
2006123456789101112
2005123456789101112
2004123456789101112
2003123456789101112
2002123456789101112
2001123456789101112
2000123456789101112
1999123456789101112

Последние статьи
Литература