Свободное/бесплатное & не IDE.
“Методы и средства” == методология и инструменты разработки ПО. Методологии (“процессы”) и инструменты разработки ПО сами по себе являются “товаром”, могут быть “модными” и “немодными” (“устаревшими”). Так или иначе, они не могут заменить здравый смысл, прагматизм, опыт, мотивацию. Но могут помочь формализовать задачу и способны выполнять коммуникативные функции.
CAD == computer-aided design == проектирование с помощью компьютера.
CAM == computer-aided modelling == моделирование с помощью компьютера.
CASE == computer-aided software engineering == разработка ПО с помощью компьютера.
Средства CASE:
О популярности визуальных средств моделирования (UML и т.п.): “bubbles don’t crash” (B. Meyer).
Уровни архитектуры информационной системы (последовательность “снизу-вверх”):
Их можно разделить на платформу (то, что используется, нижние уровни) и приложение (то, что разрабатывается).
Популярные языки программирования:
Дополнено.
“Масштаб” программ традиционно оценивается в количестве строк (LOC — lines of code, kLOC — тысяча строк). Данный показатель имеет практический смысл при фиксированном языке, наборе библиотек и стиле. Сверхмалые программы: до 500 строк.
Объектно-ориентированное программирование возникло как средство описания задач имитационного моделирования (в частности, средство имитационного моделирования — интерпретируемый язык Симула — стало основой ОО-черт ряда языков программирования, в первую очередь, C++). Затем стало популярно как “парадигма программирования” широкого спектра применения. Однако, не всегда уместно обращаться к ООП, особенно в случае небольших программ. Данный факт затрудняет изучение ООП на разумных примерах, т.к. примеры должны быть достаточно велики.
Впрочем, программы могут использовать ОО-библиотеки. ООП успешно применяется при создании библиотек, реализующих GUI.
Основа ООП — понятие объекта. Объект — единица объектной декомпозиции.
Декомпозиция — разбиение задачи или программы на части.
Декомпозиция может быть “пространственной” и “временной”.
“Временная” декомпозиция предполагает разбиение процесса решения задачи на подзадачи и процесса работы программы на последовательность действий (решений подзадач). Каждой подзадаче/действию в программе отвечает “процедура”, поэтому такую декомпозицию называют процедурной.
Цель декомпозиции состоит в разделении слишком большой программы на “управляемые” части, с каждой из которых можно работать относительно независимо, в том числе, можно поручить разработку разных частей разным людям.
“Пространственная декомпозиция” предполагает разбиение состояния программы (данных) на отдельные элементы.
Как правило, временная и пространственная декомпозиции сосуществуют в разных пропорциях и оформлении. Например, процедурная декомпозиция предполагает разбиение данных на переменные, включая локальные переменные процедур. Дальнейшее её развитие — модульная декомпозиция, выделение “сильно-связных” компонент (групп переменных, процедур и, возможно, пользовательских типов данных) в виде модулей, скрывающих часть состояния от других модулей (инкапсуляция состояния).
Модули естественным образом порождают разбиение компонент каждого модуля на две группы: доступную извне (интерфейс) и недоступную извне (реализация). Разработка интерфейса требует кооперации между модулями и разрабатывающими их людьми.
Объектная декомпозиция предполагает разделение состояния программы (данных), точнее “ответственности за состояние/данные”, между “объектами”. С технической точки зрения объекты очень похожи на модули — у них есть внешний интерфейс и внутренняя реализация, включающая данные, принадлежащие объекту, которые могут быть недоступны извне объекта (инкапсуляция). Отличие заключается в двух моментах: 1) объекты в программе часто являются отражением объектов в модели (и в реальном мире); 2) может быть множество объектов одной структуры (однотипных), может иметь смысл создание и уничтожение объектов во время работы программы, соответственно динамике данных и моделируемым процессам.
Объект “сам” управляет своим состоянием — данными программы (решаемой задачи), находящимися в его зоне ответственности.
Критика принципа инкапсуляции: полная инкапсуляция невозможна — объекты не “вещи в себе”, они должны использовать друг друга, для этого они должны “знать” друг о друге, ссылки на другие объекты — часть состояния объекта. На практике инкапсуляция отвечает за сокрытие “малозначимых” деталей и защиту корректности состояния (форсирование выполнения инвариантов — условий, которые должны быть всегда истинны для объекта, исходя из логики его работы).
Набор однотипных объектов выделяется в вид объектов, называемый в программировании классом. С точки зрения синтаксиса класс — тип данных (где данные — объекты класса), или множество всех возможных объектов одного (==этого) вида. С прагматической точки зрения класс — “чертёж” объекта. Главное, что определяет класс — как создаются и уничтожаются объекты (элементы жизненного цикла объектов), какие данные они содержат (атрибуты == “свойства”), какие действия с ними можно выполнять (методы).
Дальнейшее абстрагирование приводит нас к понятию рода объектов. Род задаёт некоторые свойства, которым должны удовлетворять объекты (или виды объектов). Отличие рода от вида легко пояснить на примере из реального мира: если конкретный стол — “объект”, “стол” — “вид”/“класс”, то “предмет мебели” — “род”. Не может существовать просто “предмет мебели”, он должен быть какого-либо вида.
В C++ понятие рода нашло отражение в виде концепции абстрактного класса, т.е. класса, определяющего не все заявленные действия, объекты которого нельзя создать. Однако, можно сказать, что некий другой класс, являются подтипом данного абстрактного класса (видом данного рода), реализует недостающие части и уже может служить рабочим “чертежом” для создания объектов.
Более “новые” языки программирования, такие как Java и C#, основывающиеся на объектной парадигме, проводят более чёткую черту, позволяющую отделить “виды” от “родов”, выделяя понятие интерфейса — описания набора действий, которые должен реализовывать (посредством соответствующего описания класса) любой объект, удовлетворяющий данному интерфейсу.
Несмотря на популярность отображения модели родо-видовых отношений в исходный код в виде классов и интерфейсов, объектно-ориентированное программирование и объектная декомпозиция не требует явного использования классов и интерфейсов. Может быть достаточно только объектов (“ООП без классов”). Пример: JavaScript. Объекты могут использоваться как прототипы для других объектов (“клонировать”, затем изменить набор свойств и методов). В этом случае технически объект является словарём, отображающим строки (названия свойств и методов) в значения.
Домен (domain) — предметная область, моделируемая часть реального (или воображаемого) мира.
Доменный объект (domain object, business object) — объект в программе, моделирующий объект в домене.
DTO (data transfer object) — объект, предназначенный для хранения или передачи данных. Если DTO имеет методы, то их роль сводится к обеспечению доступа к хранимым данным.
Объект-значение (value object) — значение алгебраического типа данных, который реализован средствами ОО-языка (операции через методы и т.п.). В ОО-языках объекты-значения могут выделяться с помощью специальных средств (например, struct в C#) и обладать особой семантикой (в C# размещение на стеке и передача по значению вместо размещения в управляемой куче и передачи по ссылке).
Механизм — объект или класс объектов, выполняющие вспомогательную роль и не имеющие отражения в домене. Обычно сюда относят сложные программные компоненты, например, контейнеры (динамические массивы, множества, словари, очереди и т.п.), строки, регулярные выражения (автоматы) и т.д.
Исторически выделялось четыре “принципа” ООП: единственность, инкапсуляция, наследование и полиморфизм. Инкапсуляция была рассмотрена выше.
Идентичность, уникальность или единственность (identity) — свойство (доменных) объектов. Каждый объект “уникален” и, строго говоря, “равен” только самому себе. Технически это выражается в том факте, что каждый объект в памяти имеет уникальный адрес.
Дополнено.
Значения (в противопоставлении объектам) в абстрактном смысле существуют независимо от своих представлений, например, число 3 не имеет место во времени и пространстве само по себе, однако может быть представлено состояниями физических объектов. Одно значение может иметь множество представлений в памяти компьютера, которые равны друг другу. Поэтому для “значений” (“объектов значений”) имеет смысл операция сравнения на равенство. Обычно равными считаются взаимозаменяемые значения. Операция копирование создаёт из одного представления новое представление, равное старому, т.е. представляющее то же самое значение. Обращение данного утверждения неверно: равные представления могут не быть копиями друг друга. Пример: рациональные числа, представленные парами целых: 1/2 == 2/4, но 2/4 и 1/2 не являются копиями друг друга.
Доменный объект является отражением некоего объекта в домене и, таким образом, является уникальным представлением самого себя.
SOLID — набор принципов разработки ОО-программ, предложенный Р.Мартином. Название является аббревиатурой первых слов названий включенных в этот набор принципов:
to be continued
Проблема “эллипс-круг”.
схема с множественным наследованием (“копир”), замена наследования на композицию повторное использование vs наследование реализация интерфейса vs наследование
SIP (separated interface principle) в C++ Std.Iostreams.
UML: диаграмма классов, отношения между классами (наследование, композиция, агрегация, использование, ассоциация)
Задача: составление расписания занятий, “ядро” –API– интерфейс
KISS (keep it simple and(,) stupid)
компоненты-чёрные ящики, развитие модульной декомпозиции в выделение отдельно собираемых библиотек (ABI, DLL), надстройка над другими программами или сервисами (web-API, REST, RPC)
“декомпозиция” коллектива: введение иерархии уменьшает затраты на коммуникацию
отделение интерпретатора от “конфигурации”, скрипты, DSL
функциональное программирование и функциональная декомпозиция
присваивание и прочие побочные эффекты –> транзакции, STM/HTM
процесс “сверху вниз” (анализ) и “снизу вверх” (синтез)
уровни: матричные операции, геометрические операции, множества достижимости, игровые задачи
Software
Целеполагание
— нужно ли адаптироваться к изменению/уточнению требований по ходу разработки (основной смысл методологии — если нужно?).
Анализ: отделение констант от переменных.
При устранении ошибок обычно более всего времени затрачивается на локализацию ошибки (т.е. обнаружение ошибочного кода или неверных предположений). Люди склонны искать ошибки в тех местах кода, которые кажутся им сложными, не до конца понятыми. Обычно ошибка находится не там, где её ищут в первую очередь. Поэтому важно применять различные средства как для как можно более раннего вскрытия самого факта существования ошибки, так и для как можно более точной локализации ошибки.
Верификация — формальное доказательство корректности программы. Обычно применяется к абстрагированным алгоритмам или протоколам.
Пример пред и постусловий (используется стандартный макрос assert).
// C++
// Вычисление квадратного корня
double sqrt(double x)
{
// Предусловие: x >= 0.
assert(x >= 0.);
// Код, вычисляющий квадратный корень (result).
// ...
// Постусловие: result >= 0.
assert(result >= 0.);
// Так как точное выполнение равенства result * result == x
// не всегда возможно, используем неравенство с заданной относительной погрешностью.
// Постусловие: abs(result * result - x) / x <= DBL_EPSILON
assert(std::abs(result * result - x) <= DBL_EPSILON * x);
return result;
}
Некоторые языки программирования (Eiffel, D) поддерживают инварианты классов, пред и постусловия явно, что облегчает документирование кода. (Инварианты и условия должны быть отражены в документации.)
Тестирование — исполнение сценариев работы с заранее известным желаемым поведением программы (или заранее известными результатами). Тест — сценарий тестирования.
Тесты можно считать частью документации — они предоставляют примеры рабочего кода и сценариев работы.
TDD — разработка через тестирование (test driven development). Подход к разработке, подразумевающий написание тестов до написания кода, который эти тесты тестируют.
// C++
class Application
{
private:
// Конструктор по умолчанию (должен быть определён).
Application();
// Запрещаем копирование объектов.
Application(Application&) = delete;
// ...
public:
// Получить ссылку на объект Application.
static Application& get_object()
{
// Объект создаётся при первом вызове функции get_object.
static Application app;
return app;
}
// ...
};
// C++
// Интерфейс прототипа.
class Cloneable
{
public:
virtual ~Cloneable() = default;
virtual Cloneable* clone() const = 0;
};
// Класс, реализующий интерфейс прототипа.
class Object: public Cloneable
{
public:
// Конструктор копирования (должен быть определён).
Object(const Object&);
// Операция "клонирования": "виртуальный конструктор копирования".
// Ковариантный возвращаемый тип.
Object* clone() const override
{
// Возвращает копию себя.
return new Object(*this);
}
// ...
};
(ковариантность/контравариантность)
Проблема мультиметода, реализация мультиметода с помощью шаблона Посетитель.
MVP, naked objects
UX/usability, анализ задач, “«интуитивная понятность» для разработчиков не является таковой для конечных пользователей” фокус-группы, асинхронность, минимизация задержек, визуализация “деятельности” (заставки, бегущие полоски и т.п.)
Шаблоны параллелизма
Процессы разработки (обзорно): Agile, MSF, RUP/OpenUP, Cleanroom.
Пример: автоматизации работы диспетчера аэропорта.
…
HTML-файл сгенерирован с помощью системы Pandoc.
Дата последнего обновления: 2016.11.13 (revision 10).
Кувшинов Д.Р. 2016