I. ТЕХНИЧЕСКОЕ ЗАДАНИЕ (ТЗ)
I.I. ГЛАВНЫЕ ВОПРОСЫ:
ЧТО:
Некоммерческое ПО, компактное приложение для запуска на локальной машине.
ЦЕЛЬ:
А) Экономия времени за счет автоматизации процесса получения последней версии проекта.
Б) Обнаружение "развилок" версий файлов и предоставление возможности их быстрого ручного сопоставления и правки.
ПОЛЬЗОВАТЕЛЬ:
Человек, регулярно делающий резервные копии на разных носителях, а также работающий над проектом в нескольких местах (например, на работе и дома).
I.II. ПЕРЕЧЕНЬ ОБЯЗАТЕЛЬНОГО ФУНКЦИОНАЛА:
- Возможность задания путей к папкам для их сравнения
И там и там мы задает папку, относительно которой будут рассматриваться все файлы проекта.
- Фиксация версии для заданного пути (по всем файлам)
Происходит поиск всех файлов в указанной папке, вычисление контрольных сумм и занесение всех индивидуальных данных в служебный файл.
- Хранение истории версий и распознание более новой
Чтобы прослеживать историю изменения версий, необходимо только добавлять в служебный файл новые записи для обновленных файлов, оставляя все предыдущие. Тогда можно четко отследить цепочку, выбрать наиболее новый файл или вовремя заметить "развилку".
- Автоматическое пофайловое сравнение 2 копий проекта
Важное замечание: при сравнении сопоставляются только записи в соответствующих служебных файлах, т.е. версии должны быть зафиксированы и там и там до начала сравнения!
- Автоматическая замена старых файлов более новыми
При обнаружении более старого файла он перезаписывается свом более новым экземпляром. Причем это действует в оба направления: после завершения операции мы и там и там получим одинаковые версии проекта!
- Выдача списка файлов, с обнаруженными "развилками"
Такую ситуацию компьютер не сможет разрешить самостоятельно (да и опасно ему это доверять). Поэтому пусть лучше выдаст список "развилок", которые мы быстренько приведем в соответствие сами. Необходимо добится совпадения версий после такой коррекции.
- Сообщать об ошибках чтения-записи носителя
Бывает, что диски портятся, носители находятся в режиме защиты от записи, у файлов стоит атрибут READONLY. Надо обязательно информировать пользователя об успехе/неудаче синхронизации!
- В качестве 1 пути по умолчанию делать текущую папку
Очень удобно будет хранить наше ПО в папке с проектом. Тогда при запуске автоматически подставится первый путь, и нужно задать только второй!
I.III. ПЕРЕЧЕНЬ ДОПОЛНИТЕЛЬНОГО ФУНКЦИОНАЛА:
- Поддерживать режим запуска с консольными ключами
Все вышеперечисленное хорошо бы запускать через командную строку в полностью автоматическом режиме, чтобы сэкономить пользователю еще больше времени за счет использования BAT-файлов.
- Отображать индикатор прогресса синхронизации
Полезно, если в проекте много файлов, и процесс сопоставления или фиксации версий занимает существенное время.
- Возможность сразу же правлять файлы с "развилками"
Т.е. мы можем щелкнуть (дважды) на любую "развилку" из списка, и сразу откроются оба конфликтующие файла в Блокноте. Или же добавить возможность распознания по расширению.
- Запоминать пути сравнения и предлагать их на выбор
Что-то вроде выпадающего списка. Естественно при условии, что у нас не так много проектов и путей к ним, а то мы попросту заблудимся.
- Опция создания короткого синонима для каждого пути
В продолжение предыдущей мысли: удобнее работать не с длинными малоинформативными путями, а с короткими и емкими названиями, которые мы сами им и дадим. правда здесь понадобится дополнительные элементы интерфейса.
- Верификация проекта
Хорошо бы предусмотреть "защиту от дурака": первой строкой проекта в служебный файл добавляется уникальная строка, по которой потом программа сможет определить, что сравниваются именно копии, а не разные проекты!
- ... продолжение следует ...
...
I.IV. ПЕРЕЧЕНЬ НЕОБХОДИМЫХ ДАННЫХ:
01) FileName (имя файла, включая путь от указанной папки)
03) FileTime (когда было последнее изменение по системным часам)
04) ProgTime (внутреннее время при фиксации версии)
02) CRC32 (контрольная сумма файла - 4 байта)
02) FileSize (размер файла)
I.V. НАБРОСКИ ПОЛЬЗОВАТЕЛЬСКОГО ИНТЕРФЕЙСА:
Начнем со словестного описания:
Приложение будет содержать одну форму. Для выбора путей сравнения будут два EDITа или два COMBOBOXа с двумя кнопочками "Обзор" с правой стороны. Допускается как ручная вставка, так и выбор через открывающийся диалог.
Чтобы зафиксировать новую версию - кнопочка с пиктограммой где-то возле первого маршрута. Чуть не забыл про кнопку "Сравнить".
Для отображения списка "развилок" - объект типа LISTBOX. Рядом с ним кнопка "Убрать", которая удаляет выбранный элемент из списка (имеется ввиду, что "развилка" устранена вручную).
Еще необходимы три LABELа с поясняющими надписями над каждым из EDITов и LISTBOX. И еще один EDIT - для отображения текущей даты и времени (а при необходимости - их коррекции). Ну и конечно - кнопка Выход.
Прочие необходимые объекты предлагаю создавать и уничтожать автоматически внутри обработчиков событий.
Кстати, в оригинале было название "КАРАНДАШНЫЕ НАБРОСКИ ...", но т.к. у меня нет возможности представить их вам в таком виде, я просто сделаю скриншот получившегося интерфейса.
I.VI. ТАБЛИЦА ИМЕН ОБЪЕКТОВ:
Однажды я забыл бумажку с карандашными набросками интерфейса. А нужно было работать. Вот тогда-то этот раздел оказался весьма кстати!
Объект | Класс | Назначение |
ff | TForm | Единственная форма приложения. |
ooEDBrowseMain | TEdit | Путь к первой копии проекта (она считается основной - именно к ней применяется операция фиксации версии). |
ooBBBrowseMain | TBitBtn | Открывает диалог выбора папки с основной копией проекта. |
ooEDBrowseSecond | TEdit | Путь ко второй копии проекта (она тоже участвует в синхронизации, но не подлежит фиксации). |
ooBBBrowseSecond | TBitBtn | Открывает диалог выбора папки с дополнительной копией проекта. |
ooBBFix | TBitBtn | Фиксирует текущее состояние основной копии проекта, как новую версию (затрагивает только измененные файлы). |
ooBBCompare | TBitBtn | Запускает сравнение копий проекта, если заданы оба маршрута. |
ooLBCompare | TBitBtn | В него загружается список найденных файлов, различия в которых нельзя разрешить автоматически ("развилки"). |
ooBBEqual | TBitBtn | Удаляет "развилку" из списка, как уже исправленную вручную. |
ooTimer | TTimer | Срабатывает каждую минуту, обновляя индикатор времени. |
ooEDDataTime | TEdit | Отображает текущую дату и время. |
ooBBExit | TBitBtn | Выход из программы. |
|
xxLABrowseMain | TLabel | Поясняющая надпись. |
xxLABrowseSecond | TLabel | Поясняющая надпись. |
xxLADiffList | TLabel | Поясняющая надпись. |
Обратите внимание на префиксы имен. "oo" обозначает объект, к которому в программе будет хотя бы одно обращение ("xx" - ни одного). Далее следующие две буквы - сокращение от имени класса.
Сделано это специально, чтобы при программировании набрав имя формы и первые две буквы, сразу же выпадал список выбора соответствующих объектов. Кстати, именно из этого соображения форма называется "ff".
I.VII. ПРИВЯЗКА СОБЫТИЙ К МЕТОДАМ ОБЪЕКТОВ:
На этом этапе обычно выявляется потребность в дополнительных глобальных переменных и константах. Просто помечаем их по ходу, а потом допишем к уже выявленным в следующем разделе.
Объект | Событие | Действие |
ff |
.onCreate | Event001 | Начальная инициализация: определить текущую папку и поместить как основной маршрут; определить текущую дату/время и вывести в окне. |
.onResize | Event002 | Изменить размеры и позиции объектов для сохранения внешнего вида формы. |
.onClose | Event003 | Выход из программы |
ooBBExit |
.onClick | Close | Просто закрыть форму. |
ooBBBrowseMain |
.onClick | Event004 | Открыть диалог выбора папки и записать выбранный основной маршрут. |
ooBBBrowseSecond |
.onClick | Event005 | Открыть диалог выбора папки и записать выбранный дополнительный маршрут. |
ooBBFix |
.onClick | Event006 | Запустить сканирование директории основного маршрута и модификацию служебного файла. |
ooBBCompare |
.onClick | Event007 | Запустить сопоставление версий файлов в обоих копиях с модификацией до последней версии или занесением в список "развилок". |
ooLBCompare |
.onDblClick | Event008 | Открыть для правки обе копии выбранного файла (в Блокноте). |
ooBBEqual |
.onClick | Event009 | Удалить текущий пункт из списка, скорректировать служебные файлы обеих копий (и там и там станет текущая версия). |
ooTimer |
.onTimer | Event011* | Обновлять индикатор внутреннего времени программы с учетом поправки. |
Event010* – разумно ввести глобальную переменную vvTIME_DIFFERENCE для хранения разницы между системными часами и внутренним временем программы (по умолчанию равна нулю).
Event010* – разумно ввести глобальную переменную vvLAST_BY_TIMER для того, чтобы определить, вносил ли пользователь изменения во внутреннее время программы.
I.VIII. ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ И КОНСТАНТЫ:
Хотя некоторые "идеологи" учат, что любые глобальные данные – зло, это не совсем так. Практически любой программе необходим минимальный набор переменных и констант для упрощения взаимодействия модулей. Конечно, их можно передавать как параметры, и возвращать как результат обработки, но представьте, что вам придется делать описания избыточных параметров в каждой второй подпрограмме. Альтернатива – не делать их!
const
// Имя служебного файла
ccFILE_BASE = 'smartupd.txt';
// Имя временного файла
ccFILE_BAK = 'smartupd.bak';
var
// Разница между системным и внутренним временем
vvTIME_DIFFERENCE: Longint :=0;
// Прошлое изменение времени таймером
vvLAST_BY_TIMER: string;
Обратите внимание на префиксы! Опять-таки все ради ускорения автоподстановки имен. "vv" обозначает переменную, а "cc" - константу. Есть еще мысль ввести "tt" - тип данных и класс.
I.IX. ФОРМАТ ФАЙЛОВ БД (3НФ):
Теория нормализации БД гласит, что только третья нормальная форма (3НФ) избавлена от избыточности и дублирования информации в базе. Однако при реализации СУБД необходимо учитывать все факторы ситуации.
Так в нашем случае всего 4 хранимых поля, и количество файлов в проете не может принимать запредельных величин, поэтому нет смысла жертвовать простотой ради небольшой экономии размера служебного файла.
Реализуем всю базу в виде одной таблицы:
#1 FileName #1 FileTime #1 FixTime #1 CRC32 #1 FileSize
#1 file1.txt #1 12.01.2007 12:00:53 #1 23.02.2007 17:45 #1 432A0241 #1 1238
#1 file1.txt #1 12.01.2007 16:04:14 #1 25.02.2007 17:45 #1 D32A0241 #1 1773
#1 file1.txt #1 13.01.2007 10:26:02 #1 27.02.2007 17:45 #1 72A00F45 #1 2004
#1 file2.txt #1 12.01.2007 12:00:23 #1 23.02.2007 17:45 #1 932A4242 #1 6433
#1 file2.txt #1 12.01.2007 16:04:41 #1 27.02.2007 17:45 #1 5321E248 #1 12007
#1 NEW\1.txt #1 13.01.2007 10:26:35 #1 27.02.2007 17:45 #1 C3330249 #1 67865
#1 NEW\2.txt #1 13.01.2007 10:35:32 #1 27.02.2007 17:45 #1 87D6AF83 #1 244455
Символ #1 выбран в качестве разделителя полей, т.к. не может быть получен с клавиатуры. Первое поле содержит повторы, которые как раз и образуют цепочку версий. Кроме того, путь к файлу и его название могут быть переменной длины.
Не исключено, что потом мы немного поменяем отображение информации. Так, возможно LastModificate лучше будет хранить в виде Longint, а CRC32 - в десятичной системе!
К проекту >>
Список заданий по проекту >>
|