Показаны сообщения с ярлыком ПМО ИУС. Показать все сообщения
Показаны сообщения с ярлыком ПМО ИУС. Показать все сообщения

суббота, 3 августа 2013 г.

ПМО ИУС — Разное

Здесь две разные, последние темы, которые не вошли в предыдущие.

Разные 10 лет

За все время преподавания очень многие вещи изменялись от одной противоположности к другой. Кроме того, мною проводилось ряд экспериментов на поиск какой-либо более эффективной модели.

Первый из разных процессов — это то, как представления о том, как все должно быть, сталкивалось с реальностью. Когда я учился, то я не представлял и не знал, что творится после зачетной недели. В моих представлениях — все должно быть подготовлено и сдано (сам так учился). Но с другой стороны — каждый год (каждый год!) на потоке находилось несколько студентов, которые просто исчезали ещё до зачетной недели, а когда на сессии уже прошел 2-й экзамен, появлялись с фразой «поставьте нам зачет, а то нас выгонят». Т.е. как будто этого достаточно, а сдавать лабораторные и изучать что-то не надо. Ещё одна точка зрения с другой стороны «зачем вы нас заставляете все это учить, если оно нам не интересно?».

В связи с этим за все время все изложение и построение предмета изменялось от фокуcа на всех (должен быть какой-то минимум, он должен быть сделан и сдан, правила одинаковые для всех) к фокусу на отдельных студентах, когда информация дается как есть, без каких-либо жестких требований и указаний, а за первые занятия выделяются те студенты, которые проявляют интерес или являются по крайней мере сознательными. Таких на потоке получалось порядка 10-20%, а на лабораторных где-то 2-3 на группу-подгруппу. Соответственно на занятиях я уделял уже большую часть времени в общении с ними, а остальная часть потока проходила по линии наименьшего сопротивления мимо ПМО ИУС.

В начале для сдачи финального зачета была собрана достаточно жесткая для двоешников и списывателей схема. Во-первых, объявлялось, что своими конспектами можно пользоваться на зачёте несколько минут. Т.е. конспект должен быть свой и это может значительно помочь — формировалась обратная связь что конспект нужно писать. На зачете конспектом можно пользоваться, но только 1 раз (Read Only, без переписывания) — идея взята у Буя М.. Факт наличия своего проверялся совпаданием почерка в ответе на зачет и почерка конспекта. Во-вторых, схема зачета взята с приемных тестов абитуриентов. 10 человек сдают, больше никого, все вещи лежат отдельно, на столе у каждого только билет, бумага и ручка. Малое кол-во людей легко контролируется. В-третьих, принимается только то, что написано. Потому как устно что-то доказывать бесполезно. В-четвертых, время на зачет полчаса, что быстро. Плюс условие — по вопросам и задаче должно быть что-то написано, не обязательно все правильно, не обязательно много, но если человек разбирался и готовился, он должен хоть что-то написать. Т.е. требования были здесь низкие. Именно эта форма зачета сразу стала страшной для всех — т.е. когда все было сделано против списываний, а порог прохождения минимизирован, но по всем темам.

Несколько лет назад я изменил ситуацию. Жесткий зачет был снят, а для каждого студента выдавалась отдельная тема заранее, которую нужно было подготовить на зачет. Тема — вне курса, но в ней нужно было разобраться самостоятельно. Далее каждый приходил со своей темой, рассказывал 2 минуты, один вопрос на понимание, если ок, то все. Иначе — домой разбираться с вопросом и следующая попытка только на следующий день и вопрос будет новый. Фокус был на понимание, на умение оперировать разбираемой сущностью.

Ещё в самом начале я отмечал посещение на каждой паре всех студентов. Сначала это было по журналам, потом группами. Потому, что декан требовал отмечать и вообще отмечать — это правильно. Но в дальнейшем я полностью забил на отмечание (но об этом никому не говорил). На вопрос декана «вы отмечаете?» говорил «старосты отмечают». В начале (тотальное отмечание) посещали все, и выбор между вариантами преподавания был либо все пишем в тишине, либо говорим, ни никто меня не слышит. В последние годы получался другой эффект. Первые лекции тихие потому что они первые, а в дальнейшем студенты сами понимают, что не отмечают, и кому не интересно или те, кто не сознательные, на пару просто не приходят. Где-то к 3-4 лекции из ~120 человек оставалось ~30, из которых слушала только половина, чего мне было достаточно. Пока не зашел декан, поругал тех, кто отсутствует и пообещал выговор старостам, которые тоже отсутствовали (;

Мое положение изменялось и отличалось от других преподавателей тем, что с 2006-2007 года я начал работать в «Интервэйле». Это означало, что в первые годы мне декан прямым текстом говорил, что «либо вы выпускаете N-х студентов, либо мы вам перестаем платить зарплату», а на факультет приходили кандидатуры мне на замену. После этого рубежа что-то изменилось — пугать увольнением стало бесполезно и даже череповато, но и с другой стороны, времени и сил бороться с системой у меня уже было меньше, постепенно приближаясь к нулю. Ситуация такая, что верхи не могут, а низы не хотят. Университет не может отчислять студентов, потому что каждый студент — это $ в казну ВУЗа (минус платник, а минус бюджет означает что один из платников станет бюджетником), и этот блок стоит на уровне ректора. Хотя думаю ещё один блок стоит выше — так как «каждый гражданин РБ имеет право на высшее образование». Кроме того, уменьшение числа студентов на факультете означает, что у декана заберут зама и дадут нагрузку на кафедре. Второе: грубо говоря, студентам невозможно оценить качество материала и уровень преподавания по определению (образно говоря это ключевые последние технологии или русские народные сказки) — содержание курса мог сократить раза в 2, никто бы ничего не заметил. Кроме того, по моему впечатлению, студенты приходят учиться в ВУЗ как в школу — посещение и движение по линии наименьшего сопротивления. Третье: сотрудникам ВЦ все равно, как идет обучение, главное чтобы на них это никак не отражалось. 90% софта, который ставился на ВЦ для ПМО ИУС, ставился лично мной во всех аудиториях. Любое обновление — бумагу, только летом, ставь сам, и делай в выходные в свое личное время. Четвертое: Социального заказа со стороны «Интервэйла» или любых других организаций ни разу не слышал, хотя можно было часть содержимого курса перенаправить в конкретно ориентированную сторону. Последнее: качество содержания курса имело значение только для двух людей — преподавателя (как ответственность за то, что преподается) и зав. кафедры (потому что потом необученные студенты приходят писать диплом и лучше, чтобы они что-то знали).

В качестве экспериментов проводилось ряд вещей, при чем делалось практически каждый год что-то новое, что изменяло отношение к курсу как студентов, так и меня. Например в один из гг. по завершению лекции я задавал 2-3 вопроса всей аудитории, и за правильные ответы давались баллы. Это происходило на последних минутах. Цель — чтобы саму лекцию слушали внимательнее. На практике две проблемы — студенты продолжали списывать ответы друг от друга (хотя за малое время делать это было сложно). Вторая — малая обратная связь по баллам и смыслу.

Пару лет мы пытались использовать систему тестирования, когда сдача л.р. проходила методом ответов на определенный тест (5 вопросов случайных, 4 правильно — сдано). От этой практики отказался, так как студенты на занятиях гоняли тесты, тратили время на это вместо того, чтобы программировать и разбираться в предмете, а также учились отвечать на вопросы, а не понимать их смысл.

С точки зрения написания лабораторных работ и отбработки практических навыков также было несколько разных форм реализаций. Сначала — теория и готовые примеры. Как результат — студенты теряли значительную часть теории (так как она напрямую не связана конкретными действиями с практикой), а примеры копировали и немного изменяя под себя. как показала практика, копипаст не способствует обучению, — он очень близок к тому, когда за студента делает кто-то, или к тому, когда необходимо самому сделать re-engineering (понять почему в примере сделано именно так и что означают эти конструкции). Следующим шагом было предоставление видео по л.р., когда можно видеть как собирается работа и смотреть комментарии к действиям. Это оказалось гораздо эффективнее, однако тут две проблемы — с видео надо переписывать (много времени и мало смысла), плюс видео надо смотреть (его нельзя быстро просмотреть или быстро найти что-то). Последним самым эффективным вариантом было изложение примера step-by-step. Лаборатоная работа разбивалась на пару десятков шагов, каждый из которых описывался словами (что делаем, почему, особенности) и примером текстового кода, который изменялся, и каждая итерация должна была быть осмысленной и компилируемой в итоге. Т.е. на каждом шаге можно было понимать и усваивать малый кусочек материала, сразу видеть результат работы и в случае ошибок быстро их найти.

Система выдачи автоматов также постоянно изменялась. Это был проходной балл (предел), определенное кол-во работ, сданных вовремя, верхняя треть списка и др.. Автоматы хороши в случае, когда надо стимулировать массы, но в последнем варианте я сосредотачивался на отдельных людях, и вся система стимулирования всех просто отключилась. У меня в последние годы вообще пропало желание кого-то что-то заставлять делать или учить. Если есть желание — добро пожаловать, всегда и всего помногу. Иначе смысла нет.

Смайлики

И в завершение веселая тема, которую я называл смайлики. В общем случае это тема про систему оценок и выставления баллов студентам за их достижения в процессе работы в курсе ПМО ИУС.

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

Пример последней из таблицы рекордов: общая(+группы) и запасная ссылки.

По завершению каждого занятия преподаватель заходил на сервер через web-интерфейс и отмечал птицами кто что сдал (работа и отчет). Если работа сдавалась вовремя, то система давала одно кол-во баллов, если не во-время, то поменьше. Кроме того, преподаватель отмечал тех, кто отсутствовал на паре; тех, кто отрабатывал занятия; тех, кто был инициативным (по мнению преподавателя), и тех кто плохо себя проявил (опоздал на занятие например). На основании этой информации формировалось все остальное. Система контролировала выдачу заданий (не более 2-х несданных работ в одни руки), строила таблицы рекордов, формировала список автоматов и рассчитывала оценки контрольных сроков.

Инициативность студентов влияло на баллы не так чтобы очень значительно, но при этом это было дробное число, которое вычислялось каждый раз исходя из кол-ва инициативных сегодня студентов и выставленных минусов по хитрой формуле. Это дало возможность сделать разбежку по баллам и всех расставить на разные места.

Каждый студент имел какое-то количество баллов в любой момент времени. Исходя из этого количества рассчитывалось его положение в таблице рекордов.

Данное положение изменялось, и это изменение за последнюю неделю показывалось рядом стоящими стрелками ( ). Т.е. если поднялся на 5 мест вверх, то стрелка вверх и число 5.

Далее рядом с каждым из них были смайлики. Это прописанные картинки, которые распределяются исходя из числа баллов равномерно от 2-го места к последнему, первое всегда один и тот же победитель. Смайлики были найдены ещё в 2003-м году, и тогда студенты ещё нас спрашивали, де их нашли (тогда найти было трудно). Кроме того, часть смайликов собственноручно нарисовал Андрей Логвиненко, так как они были слишком жестокими по отношению к девушкам либо не смотрелись женственно. Таким образом, у нас было две линейки смайликов — женские и мужские.

Не знаю как в последние годы, но в первые годы смайлики и таблица рекордов однозначно давали ощутимый позитивный эффект. Их параллельно начал использовать Харлап С.Н., но смайлики вручную вставлялись в Excel, а у нас было все автоматически.

Контрольный срок считался по формуле, а цвета плюсов и минусов определяли успешность сдачи и вовремя была сдача или нет.

Кроме всего этого, имелась система наград, которая включала много разных отличительных значков:

Черная метка — выдается тем, у кого самый худший вариант в группе. Мы долго думали как отображать награду, Андрей даже предлагал сапоги, но все таки остановились на метке. Значок баллов не дает, переходящий приз.
Кубок самому лучшему в специализации на потоке (микропроцессорщики, телемеханики, связисты — три таких кубка.). Баллов не дает, переходящий приз.
Награда за то, что все лабораторные выполнены, а отчеты сданы. +5 если все вовремя, +3 если хотя бы одна не вовремя.
Лучший студент на потоке, переходящий приз, баллов не дает.
Лучшая студентка на потоке, переходящий приз, баллов не дает.
Утешительный приз. Первый из тех, кто остался вообще без звезд или наград. Баллов не дает, переходящий приз.
Первооткрыватель лабораторных работ. Приз получает тот, кто первый выполняет лабораторную работу, но при этом не более одной в руки (такую звезду если уже получил, то больше за первооткрывательство не дадут). +3 балла.
Double, triple, tetris, … приз за сдачу нескольких работ в один день (дубль — две в день). +1/+2/+3/… баллов.
Приз за сданные 1, 6, 10, 13, 28, 100, 153, 200, 256, 300, 370, 371, 400, 407, 496, 500, 555, 600, 666, 700, 800, 900, 1000, 1024 работы. Система помнит, в каком порядке работы сдаются на потоке, и если это работа номер как в списке, то выдается приз. +2 балла.
Выдается тем, кто набрал больше всего баллов в соответствующем месяце. Баллов не дает.
Блуждающая звезда (планета, переходящая). Первый вариант — за активность. Первые 10 студентов, имеющие самую большую активность, получали эти звезды. Первые 5 — +3 балла, вторые 5 — +2 балла.
Второй тип планеты — выдается за массовую сдачу л.р.. Система вычисляет день, когда было сдано больше всего работ, и всем, кто сдавал в этот день, выдает награду. +2 балла.

Таблицы рекордов сохранившихся годов: 2003-2004, 2004-2005, 2005-2006, 2006, 2007, 2010, 2011, 2013.

На этой позитивной ноте думаю можно закончить. Спасибо всем, кто прочитал цикл про ПМО ИУС. Надеюсь все это писалось не зря.


пятница, 2 августа 2013 г.

ПМО ИУС — Структуры данных и STL

В то время, когда я учился, нам в рамках ни одной из дисциплин структур данных (и соответственно STL) никто не давал. Во время становления курса Андрей Логвиненко вписал в программу одну лабораторную по ассоциативным контейнерам STL, но до неё практически никто не доживал.

У меня в то время уже набрался отдельный приличный опыт кодирования различных структур данных (от простого стека до сложных B-tree деревьев различных разновидностей, как динамические так и статически реализации), поэтому структуры данных были оформлены как отдельная тема. Она оказалась хорошей подготовкой к теме STL, так как структуры данных сами по себе абстрактны и не зависят от языка реализации, а STL в значительной степени реализует большое число структур данных.

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

Удержание фокуса

Каждая структура данных — это объект какого-то общего класса, который описывает данный тип структур данных. Интерфейс полностью инкапсулирует внутреннее состояние структуры.

Конкретная структура данных используется и проектируется под конкретные типы действий над данными. То есть, исходя из того набора операций и требований, которые мы предъявляем множеству однотипных элементов, выбирается тип структуры данных.

Сам тип структуры данных может быть спроектирован самостоятельно в случае необходимости. Готовые протестированные структуры данных хорошо, свои велосипеды — в случае необходимости.

Подробности

Структуры данных и STL слайды.

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

Одну структуру данных мы уже знаем — массив. У нас в массиве всегда хранятся элементы одного типа, доступ в С++ через оператор [] по индексу, внешний пользователь использует массив не думая о том, как и где он хранится. Хотя пользователь может рассчитывать, что элементы в массиве хранятся последовательно и доступ к ним по индексу очень быстр (например в Perl массивы хранятся не последовательно, а организованы через хэш). Элементы могут быть любого, но одного типа. Взаимодействие с ними жестко определено интерфейсом. Внешний пользователь может создавать столько массивов, сколько ему захочется, и практически для любых типов (тип должен иметь фиксированный размер или гарантию того, что по размеру не выйдет за установленный предел).

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

Стек. Имеет операции вставки и извлечения, параметры глубины и максимального размера. Обычно в памяти структура данных сама хранит указатель HEAD, чаще всего указывающий на элемент, который должен быть вставлен в последствии. Описание операций вставки и извлечения. LIFO. Две разных реализации стека — статическая и динамическая. В первом случае через массив, который мы создаем заблаговременно и работаем по нему посредством указателей. Второй случай — каждый элемент структуры данных хранит рядом с собой указатели на соседние элементы. Певый случай быстр, не требует дополнительной памяти на указатели, но съедает заданное число памяти согласно первой инициализации и имеет ограничение на размер, в то время как динамическая реализация ограничена только всей оперативной памятью.

Примеры стеков — ханойская башня (3 стека). Стек может быть использован в ряде других, не так очевидных задач, — организация сохранения данных в памяти при работе подпрограмм; пример рекурсивного разбора выражений.

Очередь. Аналогично — есть HEAD и TAIL, можно вставлять в один хвост, а извлекать только из другого. FIFO. Аналогично реализуется статически и динамически.

Списки. Как двусторонние стеки или двусторонние очереди. С каждым из хвостов можно делать операции извлечения и вставки.

Двусторонне-связанные списки. Картинка динамической реализации. Аналогично односторонне-связанные. Преимущества и недостатки.

Упорядоченные списки — делают определенные действия, чтобы сохранять упорядоченность на каждом выполнении операции.

Кольцевые списки.

Как организуется структура данных — основные правила.

Мы рассматривали линейные структуры данных. Для каждой из них характерно то, что все элементы хранятся линейно, в жестко заданной последовательности. Такое деление частично условно, так как в большинстве структур данных задается условие, что можно перебрать все элементы структуры данных в прямом или обратном порядке.

Дерево как структура данных. Каждый элемент имеет родителя и потомков. В общем случае дерево начинается с корня, каждый элемент можно отнести к какому-то уровню, связи внутри дерева не пересекаются.

Бинарное дерево — количество потомков не более 2. Это имеет свои преимущества. Например в данном случае дерево отсортировано и можно простыми операциями сравнения найти нужный элемент, ища из корня.

Сбалансированное дерево — такое дерево, в котором все кроме одного последнего уровня обязательно заполнены. Такое дерево позволяет осуществить гарантированный поиск за log2(N) операций.

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

Виды проходов деревьев (pre-order, in-order, post-order, level-order).

Множества. Могут быть реализованы по-разному, как статически, так и динамически, так и через другие структуры данных. В множестве элемент встречается только один раз или не встречается вообще, а операции для него определяются из математического определения множества.

Мультимножество.

Карта (отображение, map). Мультикарта (multimap).

Хэш. Сначала разбор понятия хэш функции (функция, возвращающая элемент, который имеет конечное число состояний). Данное число состояний в хэше ассоциируется с хэш-таблицей.

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

Понятий коллизий. Коллизии это плохо. как избежать коллизий (хорошая хэш-функция и изменение размеров хэш-таблицы).

Куча (heap). Выглядит как бинарное дерево, но в нем всегда в каждой тройке нижние элементы меньше верхнего, и справа всегда меньше чем слева. Такая организация позволяет нам создать приоритетную очередь, в которой скорость вставки и извлечения высока (log N), в обычных приоритетных очередях каждый раз нужно либо искать место вставки или пересортировать. Разбор операций вставки и извлечения и почему так происходит.

Пример экзотической структуры данных — sparse array и варианта его реализации.

STL. Сначала — пример задачи, где нужно выполнять однотипные действия над разными типами данных. Если нет специального механизма, то это приводит к тому, что имеем большое число повторяющегося кода. Его сложнее читать, сложнее сопровождать, сложнее использовать. В случае с использования шаблонов можно сделать по-другому, из-за чего сокращается объем и сложность, и кроме того, появляется гибкость, так как мы можем использовать этот код для ряда других типов, о которых в данный момент ещё даже не подозреваем.

STL. Базовые (но это не все) элементы — контейнеры, итераторы, алгоритмы.

Контейнеры — это фактически те структуры данных, которые мы рассматривали ранее, но на языке С++, и они уже готовы к применению. Итераторы — специальные объекты для доступа к элементам структуры данных, близкая аналогия — указатели. Алгоритмы — готовый набор функциональных действий, позволяющий получить что-то полезное.

Каждый контейнер представляет собой упорядоченную последовательность элементов. Т.е. все элементы можно выстроить в одну цепочку друг за другом. Если мы хотим перебрать все элементы контейнера (распечатать их, найти какой-то и др.), что является типичной операцией, то это делается через итерационный перебор. Пример перебора. Понятие end-of-sequence (элемент за последним, но не последний).

Vector. Это — массив, но только в отличие от него мы можем изменять его размер во время выполнения программы. Сам вектор имеет всегда какой-то запас по размеру в памяти, и поэтому мы можем его расширять быстро.

Если этот запас заканчивается, то вектор перемещает себя в другой участок памяти, где резервирует больший объем памяти, копирует себя туда, и работа продолжается.

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

List. В STL — динамический двусвязный список со всеми вытекающими. Удаление и добавление элементов в список. Пример.

Образование контейнеров из list'a в STL: стек, очередь и приоритетная очередь сделаны на основании list'a.

Deque.

Множества и мультимножества как деревья в STL.

Карты и мультикарты в STL. Пример.

Разбор характеристик контейнеров — какие особенности у каждого из них, когда какой следует применять.

Типичные методы контейнеров, характерные для всех.

Разбор алгоритмов STL. Алгоритмов много. Они безопасны, проверены и быстры. Работают как с контейнерами, так и с массивами. Нужно знать.


четверг, 1 августа 2013 г.

ПМО ИУС — Исключения

В то время, когда я учился, исключения уже как отдельное понятие существовали, но в нашем курсе они отсутствовали, а на практике в той среде, которую мы использовали (Borland C++ 3.11) они были, но реализация была ужасна — как с точки зрения производительности, так и с точки зрения количества подводных камней особенностей компилятора и как следствие, безопасности и удобства использования.

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

Кроме общего изучения механизмов исключений были сформулированы два дополнительных акцента: создание собственных классов исключений (опционно с задействованием std::exception), задействование исключений других библиотек (VCL C++Builder, другие библиотеки также могут использовать стратегию обработки исключительных ситуаций через исключения, и это мы понимаем и используем).

Удержание фокуса

Полный цикл как работает исключение — бросок; формирование объекта описывающего исключительную ситуацию; раскручивание стека; условие перехвата или не перехвата; обработка исключительной ситуации (передача информации в контекст catch, функциональная обработка; перехват только одного; выход из режима обработки исключительной ситуации).

Смысловое и функциональное значение своих классов исключений.

Подробности

Слайды.

Изначальное преподнесение проблемы — без описания чего либо с точки зрения исключений. В настоящее время понятие исключительной ситуации укоренилось и так и называется, раньше, до изобретения и распространения исключений проблема также существовала, но встречал её под названием «ошибочная ситуация», и для вынесения понятия исключения как слова из контекста использовал его.

Итак, ошибочная ситуация. Суть стартует с простейшего примера — необходимо написать функцию деления двух чисел A на B. Пример функции:

int
func( int a, int b )
{
    return a / b;
}

В данной функции, как и в любой другой, имеется две разных роли людей, участвующих в разработке. Один человек является пользователем функции, второй — её разработчиком. Между ними имеется соглашение с точки зрения интерфейса — пользователь обязан передать два параметра, разработчик должен посчитать и вернуть результат вычисления в виде числа.

С точки зрения обязательств все понятно. Однако здесь может получится так, что параметр B равен 0. В этом случае разработчик находится в затруднительном положении — он может понять и проанализировать, что B=0 (через if например), но этот случай не может быть обработан, так как возвращаемый функцией результат как число будет неверным. Если такое происходит (мы понимаем, что сами разрулить ситуацию не можем из-за особенностей функции или состояния системы, но делать что-то надо), то это называется ошибочной ситуацией.

Таких ситуаций может быть много: нам передали имя файла на обработку, а доступа к файлу нет; пытаемся подключится к БД, а в ответ непонятная ошибка; выполняем некоторое системное действие, а оно отрабатывает слишком долго. Основной задачей в разруливании ситуации является передача внешнему пользователю информации о том, что что-то произошло, по возможности с каким-либо описанием.

Для решения проблемы традиционно используется 4 метода, каждый из которых имеет свои преимущества и недостатки (сначала просто список как это работает, потом думаем что хорошего а что плохого в каждом из методов, а потом только раскрываются ответы):

Останов программы.
Останов в надежде, что придет человек и все решит. Человек действительно может все решить, но на это может потребоваться много времени. Резкий останов позволяет быстро диагностировать факт проблемы (останов не заметить крайне сложно) и заняться её устранением (fail-fast), но например в системах реального времени, от которых многое зависит (ПО на борту самолета), прийти и разобраться будет поздно. Кроме того, может получится так, что проблема на самом деле проста, и решить её можно программной логикой.
Вернуть что-то, как будто ничего не произошло.
Самый страшный способ. Внешний пользователь не сможет узнать, что система работает некорректно, соответственно ошибку сложнее будет обнаружить, из-за чего мы будем думать, что все в порядке, а на самом деле все плохо. Однако в крайне редких случаях, например когда нет другого способа, а система должна работать, это может применяться, но при этом надо отдавать себе отчет и пытаться сделать все возможное для диагностики (страшная запись в лог) и попытки решения проблемы.
Вернуть код ошибки (некоторое.
Традиционный способ обработки ошибочных ситуаций, встречающийся во многих системах нижнего уровня. Может быть обработан широкий спектр ошибок (с добавлением кодов в документацию). Однако у него есть ряд недостатков. Во-первых, не всегда можно вернуть код ошибки (как например в нашей функции делания A на B, нет ни одного зарезервированного значения для возврата кода ошибки). Во-вторых, в случае большого числа кодов ошибок и большой вложенности функций становится сложно все это сопровождать. Фактически каждая функция должна быть проверена на возвращаемое значение (вы часто проверяете возвращаемое значение printf?), и зачастую то не делается. А если делается, то код резко разрастается, и при этом логика обработки ошибок смешивается с бизнес-логикой приложения.
Вызвать некоторую общую функцию, которая решит все проблемы.
Общая функция — это логическая обработка, которая потенциально может все. Однако здесь есть ряд проблем: не каждую ошибочную ситуацию можно обработать; в больших системах такая функция начинает на себя брать все, а это ведет её разрастанию и глобализации (зависимость в случае сохранения внутреннего состояния функции; многопоточность и пр., очень похожее на синглтон и глобальные переменные), что череповато; не всегда есть возможность вызова такого рода функции из всех контекстов.

Как видим варианты решения есть, их много, и у каждого из них свои особенности.

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

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

Рассмотрение аналогичного примера, только уже с использованием механизма исключений.

Разбор синтаксиса исключений.

Общая логика работы приложения при бросках исключений (создание объекта, описывающего исключительную ситуацию; бросок и перевод системы в состояние обработки исключительной ситуации; поиск блока, который может решить проблему; раскручивание стека; перехват или не перехват (останов); обработка исключительной ситуации и переход в обычный режим работы).

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

Собственные классы исключений и их иерархии. Выбор блока обработки исключительной ситуации в случае иерархии исключений.

Повторная генерация (отсутствие копии и сохранение оригинала).

Исключения std::exception, их рекомендация к использованию, почему они не обязательные как в других языках (исторически), уже готовые стандартные, наследование от них.

Исключения C++ Builder как пример исключений со сторонних библиотек. Другие библиотеки также могут использовать исключения и соответственно их функции бросать их.

Пример создания собственного класса исключений и как это можно использовать.


среда, 31 июля 2013 г.

ПМО ИУС — Rapid Application Development

Включение изучения среды RAD было обусловлено рядом причин: другой (GUI) интерфейс, второй тип проекта в курсе (не только консоль, т.е. два проекта используют одну библиотеку для понимания подключения разрабатываемых библиотек), мультяшность (эмоциональность другой среды, т.к. изначально консоль это тривиально и скучно), другая парадигма в построении приложения (консоль это одна стартовая нить, здесь же одна нить, которая выполняется на разных методах в случае наступления событий). Кроме того, среда RAD ранее в Delphi и сейчас в Builder'e имеет низкий порог вхождения, что позволяет её внедрять в массы.

В рамках данной темы две работы — одна на базовый интерфейс и компоненты VCL вообще, а вторая на понимание событий в RAD (чтобы можно было делать динамичное, например захватывать мышой и тягать объект по экрану).

RAD также хотелось запускать как можно раньше, сразу же после завершения тем ООП. Это обсуловлено было тем, что во-первых, эта тема эмоциональная и контрастная, во-вторых, существенно разбавляет консоль и в-третьих, делает переключение на второй проект (не консольный, а GUI-шный, который в дальнейшем развивается). Кроме того, после прохождения RAD тема по исключениям делается немногим более насыщенной, так как подхватываются не только пользовательские и стандартные исключения, но и исключения VCL.

Результат выполнения работы получался зачастую веселым и занимательным. В зависимости от задания требовалось изобразить графически в помощью методов Canvas (рисование простейших элементов — линии, эллипсы, прямоугольники, …) состояния разрабатываемого объекта класса,и далее этот объект становится в следующей работе динамическим. Это были и обезьяны, ползающие по пальмам за орехами, и змей горыныч в пару десятков голов с глазами следящими за мышкой, и спутник взлетающий на орбиту по параболе и др..

Удержание фокуса

Использование классов библиотек как есть, без изменений.

Продвинутые студенты использовали полиморфизм, работая через указатели. Т.е. объект в зависимости от типа подстановки вел себя различным образом.

Выделение отдельных функций для рисования-стирания объекта.

Подробности

Слайды.

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

Свойства, методы и события показываются на сборке приложения на пальцах. Свойство — практически то же самое, что и поле, но в RAD к нему добавлено ряд особенностей, например реакция на изменения состояния. Метод — то же самое что и метод функции. Событие — ассоциация метода и некоторого условия, при наступлении которого вызывается метод (нажатие кнопки, периодическое событие от таймера, внешний вызов, изменения состояния свойства и т.д..).

Разбор по классификации компонентов VCL (стандартные, оригинальные, графические и невидимые). Пострение иерархии классов VCL — на каждом уровне иерархии появляются новые свойства. Сначала это просто объекты, которые имеют имя как идентификатор и зарегистрированы в системе, а далее на них навешиваются комплексы различных методов и свойств зависимости от подгруппы, в которой классы реализуются). Простым спискам не обязательно быть отдельными компонентами, а менюшки можно объединить под одной крышей, только вызывать и отображать по-разному. Активные компоненты требуют дополнтельных ресурсов, поэтому эта группа функций лежит отдельно и подключается только для тех, кто может принимать фокус или реагировать на щелчки. …

Состав проекта важен для понимания — временные файлы и как они строятся и их не нужно ставить под контроль, файлы формы, которые нужно ставить под контроль.

Базовые классы — AnsiString он же String, свой внутренний велосипед стрингов внутри VCL и на нем построены все стринги, которые используются в VCL.

Различные типы свойств — простые типы, выбор из нескольких, множества, сложные со своими редакторами, массивы свойств, вложенные свойства. Их всех можно найти в Object Inspector'e.

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

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

Представление цвета в Canvas. RGB. Canvas как большой двумерный массив пикселов.

Пользовательские диалоги, призванные облегчить взаимодействие с пользователем. Типичные диалоги уже разработаны и ими можно пользоваться (получить от пользователя согласие на действие, передать пользователю сообещение, выбрать файл для записи на диск и др..). Диалоги есть в виде функций (вызвал, словил ответ и забыл), а есть и компоненты (взял компонент, настроил, использовал, перенастроил, ещё раз и т.д.).

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


вторник, 30 июля 2013 г.

ПМО ИУС — ООП — Наследование и полиморфизм

Наследование уже изучалось после прохождения 3-й работы и усваивания Google Test Framework. Таким образом, первые основные три темы, которые должны были введены быть в курс как можно быстрее для того, чтобы в каждой из работ потом повторятся — проведены.

Вместе с наследованием изучалась перегрузка операторов. Полиморфизм без наследования изучать сложно, а перегрузка операторов потом пригождается при изучении STL.

На этом этапе нет виртуальных функций и абстрактных классов. Просто идет добавление нового класса-наследника о существующего и к нему должна быть добавлена новая функциональность.

При перегрузке операторов обязательно использование унарного и бинароного операторов и демонстрация работы с ними.

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

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

У нас уже есть два класса из предыдущей работы и теперь нужно построить что-то больше напоминающее иерархию — один базовый класс и два наследника. Только на этот раз базовый класс должен стать абстрактным, как минимум одна из ключевых функций стать чисто виртуальной, а реализация уйти в наследника. Во втором наследнике появляется новая реализация согласно заданию.

Все это проверяется в Google Test. Как и следовало ожидать, так как функция переносится в наследник, то все тесты ломаются, так как базовый класс уже создать нельзя в силу его абстрактности. В связи с этим чинятся тесты (что полезно — что-то изменилось, нужно привести в порядок тесты). И далее тестируется в том числе и новая функция.

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

Фокус держится на контроле тестирования и на адекватности понимания полиморфизма. Т.е. важно понимать то, что можно работать с многими разными типами не вникая в более низкие детали реализации.

Подробности

Слайды, слайды.

Общее понятие самого простого наследования — есть базовый (супер-) класс, и наследник (под-) класс. Во время наследования по умолчанию все свойства базового класса передаются наследнику, т.е. все, что умеет и все что есть в базовом классе становится достоянием наследника.

Наследование может быть в несколько уровней. Кроме того, оно может быть множественное и очень разное.

При сборке иерархии наследования прежде всего ориентируются на тех типах с точки зрения абстрагирования, которые были нами выделены. Если мы можем объединить по какому-либо существенному признаку несколько объектов, то может быть целесообразным эту общее собрать в одном базовом классе. С точки зрения абстрагирования это могут быть как данные, так и код. (примеры для иерархий) Выполняя объединение получается так, что это дает нам возможность не переписывать общие части в каждом из наследников, а использовать одну и ту же функциональность несколько раз, при этом держа её под определенной абстракцией с конкретными границами. Кроме того, мы можем оперировать элементами более высокого уровня (например мы можем посчитать периметр для любой двумерной фигуры, или объем для любой трехмерной).

Как это делается в С++. Демонстрация повторного использования кода и данных.

Изменение доступа при наследовании в C++. По умолчанию делаем public.

Размещение данных в памяти и как может произойти срезка.

Синтаксис конструирования объектов иерархии. Порядок вызова конструкторов и деструкторов.

Доступ к одноименным функциям в рамках одной иеррархии наследования.

Множественное наследование (как так получается, контроль одного базового класса компилятором С++).

Перегрузка функций в С++. Одно имя, разный интерфейс. Выбор интерфейса исходя из контекста. Преимущества такого подхода по сравнению с зоопарком разноименных функций.

Перегрузка операторов. Оператор — та же функция, которая вызывается, только синтаксис немного другой. Бинарные и унарные операторы.


понедельник, 29 июля 2013 г.

ПМО ИУС — ООП — Инкапсуляция и модульность

Инкапсуляция хорошо по интуитивному смыслу дружит с модульностью, поэтому благоразумно давать их вместе — первое как контроль состояния объекта и защита от внешних воздействий, и модульность как уменьшение сложности методом распиливания на независимые части. В рамках первой — это перевод всех данных под private раз и навсегда до конца курса, в рамках второй — разделение класса на пару файлов hpp/cpp и вынесение их в отдельное место, отличное от главной программы, которая уже подключает их через include.

Несмотря на то, что инкапсуляция является стандартной и необходимой практикой в ООП, она вынесена в отдельный детерминированный шаг для того, чтобы: разделить прямой доступ к полям и доступ через методы на уровне написания кода; в первой работе сосредоточиться на абстрагировании, не пытаясь делать много вещей сразу; во второй уже работать с обкатанными понятиями первой л.р. (часть из них должна немного осесть в более долговременную память); сосредоточиться на понимании состояний объекта и его защите.

С точки зрения работы функционал практически не добавляется — только с точки зрения поведения классов необходимо добавить действия по сохранению объекта в корректном состоянии (чтобы Дюймовочка не плыла участки в минус 5 метров, иначе поведение объекта или его состояние может стать некорректным) — это делается как раз вместе с инкапсуляцией. Кроме того, идет разделение и вынос hpp/cpp, что тоже не меняет функционал.

В данной работе сопутствующей темой является оформление кода — по завершению работы код уже должен соответствовать правилам оформления и собрана документация с помощью Doxygen.

Разбиение hpp/cpp является подготовительным шагом к следующей работе, где классы выносятся как отдельная библиотека и там тестируются. Т.е. сначала сплошной cpp с классом и main(), далее main() + файлы hpp/cpp, и далее уже main подключает через svn:externals hpp/cpp. Малые шаги лучше чем все сразу.

Фокус на обязательности инкапсуляции и обязательности всех правил оформления кода.

Класс должен заниматься только тем, что от него требуется — никаких побочных печатей внутри логики. Все печати вне класса.

Сразу прописывыаем защиту от повторной компиляции — чтобы она стояла везде.

Подробности

Слайды.

Разделение реализации и пользователя класса. Это два разных человека, между которыми имеется некоторое соглашение о взаимодействии (интерфейс). Реализация может жить отдельно, выполняя условия интерфейса, пользователь класса может работать с классом, не думая о реализации. Профит — уменьшение сложности и возможность работы людьми независимо друг от друга. Но нужны ресурсы на содержание интерфейса.

Подобное соглашение есть для простых структур данных. По большому счету вы не знаете, как в памяти хранятся int'ы, float'ы и пр. базовые типы. Однако вы знаете, что есть набор операций, которые можно над ними выполнять (интерфейс) и работаете уже оперируя ими, а сами переменные — удобные абстракции соответствующего типа.

Как это делается в C++. Что это дает (защита, разделение).

Типичная сборка проекта в C++ с точки зрения файлов (пары hpp/cpp, которые независимы и подключаемы при необходимости).

Защита от повторного подключения в С++ (как выглядит и зачем).

Доступ к полям класса (public/private/protected). Что такое наследование пока что не знаем, просто помечаем на будущее. Как это выглядит в C++.

Getter'ы и Setter'ы.

Пример изменения реализации — изменяем private и логику функций, однако интерфейс не изменяется.


воскресенье, 28 июля 2013 г.

ПМО ИУС — ООП — Абстрагирование и типизация

Изначально мне и нам преподносили ООП с теоретическом стиле Буча — программные системы становятся все сложнее, понятие сложности, с этим надо что-то делать, … К этому всему эволюция программных парадигм (формулы, алгоритмы, подпрограммы, модули, …). Как показывала практика, понимание и усвоение с такой подачи шло очень слабо. По моему мнению, это происходило из-за ряда причин: приличный кусок теории, не связанной с практикой (просто большой объем такой информации воспринять и переварить сложно); отсутствие у студентов опыта написания и понимания сложных систем; новизна большого числа понятий, которые появлялись на практически пустом месте.

Такой подход по моему мнению, конечно классический, но через данный барьер проходили не многие (мало кто в конце 2003-2004 года мог толком сказать чем класс отличается от объекта), а ещё хорошо помню с какими потерями в свое время мне пришлось изучать ООП самому. Хотелось чтобы это не оставалась как система выживания (типа кто хочет, тот научится), а минимизировать порог вхождения для понимания основных сущностей в ООП.

Для решения данных проблем было предпринято ряд действий. Во-первых, все ООП было аккуратно распилено на 6 разных частей (абстрагирование, типизация, модульность, наследование, иерархия, полиморфизм). Каждая часть — это отдельный пункт, с которым надо отдельно разобраться, а разбор проходил в виде отдельной лекционной части, не залезая в другие. Аналогичное деление происходило в лабораторных — когда в каждой из них акцент ставился на определенные моменты. Во-вторых, вся история появления ООП была выброшена из потенциальных конспектов и преподнесение делалось как есть (как создать класс, что такое объект, как можно эти оперировать, какие преимущества и недостатки). В-третьих, психологически практически полностью выброшен пугающий подтекст (сложность, большие системы, …), т.е. да, ООП может показаться и оказаться сложным, но ничего сложного в нем нет. В-четвертых, в материале были выброшены все малые детали, а акцент был только на больших сущностях, которые прокручивались по нескольку раз на разных лекциях (важно первое приближение, а детали уже в случае частных вопросов). В-пятых, материал не только как есть, но вокруг него ряд вопросов-ответов (почему так; зачем; что это дает; как это сделать; вот аналогичный в жизни пример, но не на языке С++; когда применять а когда воздержаться;…).

В результате такого применения ядро предоставляемого материала лучше усваивалось в массе, частности уже особо прогрессивные студенты спрашивали и осваивали сами, а детали обсуждались в случае частных проблем. Другими словами, мастерство — это до блеска отточенная база. Акцент ставился на базу, она должна быть освоена и отточена, остальное по желаниям и возможностям.

Абстрагирование и типизация

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

Мы с раннего детства умеем абстрагировать, но не знаем, что это так называется (; Если у нас есть корзинка фруктов и мы хотим узнать сколько там яблок, то для этого нам нужно провести абстрагирование. У нас есть задача (посчитать количество яблок), мы представляем что такое яблоко (можем его отличить от другого предмета в корзинке), умеем считать (ответ — число). Мы выбираем только те сущности и свойства реального мира, которые важны в нашей задаче. Нам важны только яблоки, и только их число. Нас не интересуют груши и грибы, нам не интересны спелые ли яблоки или червивые, нам важны только яблоки и только их число. Выделение нужных свойств из всего разнообразия — есть готовое абстрагирование.

Первая из лабораторных ориентирована в самом начале (после первых шагов в SVN) на абстрагирование. Раньше такой ориентации не было. Если посмотреть на примеры выполнения первых ООП-работ 2003-2005 гг. (которые пришли мне в наследство), то можно заметить, что процесса ООП-абстрагирования нет вообще, а в мыслях об ООП рождается впечатление, что это такой хитрый способ сборки функций в одном месте и рядом лежащих данных, а с таким высказываемым студентами впечатлением на л.р. я сталкивался постоянно. Когда сейчас смотрю на эти примеры, то понимаю, что это выглядит как будто ООП (классы, объекты), но это не ООП, а процедурное программирование, обернутое в классы и объекты.

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

  1. Кот Васька регулярно охотится на воробьёв в своём дворе. При чём после удачной охоты запирает воробьёв в клетку до конца сезона.

    Во двор каждый день прилетают новые воробьи, и кот Васька знает, сколько каждый день прилетит новых. Старые же воробьи из двора не улетают.

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

  2. Дюймовочка плывёт на кувшинке и спасается от жабы. Согласно первоисточнику, течение было очень сильным (M м/с) и поэтому жаба отставала и не смогла догнать. Согласно законам физики, течение действует одинаково как на Дюймовочку, так и на жабу. Но, о чём умалчивает первоисточник, жабу слишком жёстко заносило на поворотах. Поэтому Дюймовочка двигалась с постоянной скоростью M м/с, а жаба ускорялась с ускорением X м/с^2 и на поворотах её скорость падала до нуля. Подлинной истории неизвестно, догнала жаба Дюймовочку или нет, но известны длины участков реки, а также то, что жаба стартовала со скоростью 0 м/с.

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

  3. Когда варкается, хливкие шорьки превращаются в мюмзиков. При чём за один такой день - одно превращение. Если не варкается, то количество мюмзиков увеличивается на 2. В зависимости от погоды каждый день варкается или нет.

    Спроектировать класс превращений, для которого определить методы прихода некого числа мюмзиков и метод прихода некого числа шорьков, а также метод прохождения дня когда варкается, и метод прохождения дня когда не варкается.

В начале практически у всех студентов происходит некоторый шок непонимания того, что с этим делать. В общем случае это естественный процесс, который мы тоже каждый раз переживаем, когда сами сталкиваемся с разбором чего-то нового.

Первые шаги в работе — проведение абстрагирования. Необходимо исходя из задания выделить необходимые для решения сущности (данные и код, поля и методы). Этот процесс происходит не у всех и не сразу, что тоже вполне естественно,и также естественно то, что большинству студентов требуется помощь — что и имеет место, когда мы начинаем лично разбирать задачу — что происходит, какие объекты, в каких они могут быть состояниях, что для нас важно а что не важно и т.д. (это вполне естественно потому, что способность к проведению абстрагирования с точки зрения ООП приобретается только с опытом, а у студентов пока что опыта нет). Таким образом в результате абстрагирования собирается класс, позволяющий решить задачу. Из одного и того же задания класс не всегда получается одинаковый (может быть даже пара классов, типы полей студент выбирает сам исходя из своих соображений, …).

Следующие шаги — каркас уже готов (поля и интерфейсы методов), собирается функциональность и проверяется её работа. В этой работе нет никакой инкапсуляции (все в public), обязательна демонстрация доступа к полям и методам класса напрямую (чтение, запись, вызов). Кроме того, необходима сборка конструктора по умолчанию и конструктора с параметрами, задающего полное начальное состояние объекта, и, соответственно, проверка их работы. Все в одном cpp-файле, ничего лишнего (так как ещё тут есть SVN, консольная среда Builder считается новой).

Таким образом, акцент идет на абстрагировании и типизации (создание своего типа, первые шаги; другие элементы типизации позже), а фокус держится прежде всего на базовыя понятиях класса/объекта, объединения кода и данных, а также их применения.

Подробности

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

Если не вдаваться в подробности, то ООП-программа в отличие от процедурной, состоит из множества объектов, каждый из которых представляет собой объединение кода и данных, и при этом объекты взаимодействуют друг с другом. Но это первое приближение, которое в дальнейшем станет более понятным.

С точки зрения отношения объектов друг относительно друга они чаще всего не являются независимыми, а используются как иерархии абстракций (пара примеров когда общая абстракиция выносится наверх а детали идут вниз).

Объект — это код (действия) плюс данные (поля). Если мы возьмем абстрагированную лампочку, то она будет иметь какое-то нам важное состояние (поля) и над ней можно будет делать какие-то нам важные действия (код).

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

Создавать каждый раз новый объект с нуля неудобно. Чаще всего получается так, что мы имеем много лампочек с похожим поведением, но при этом каждая из них имеет свое состояние. В связи с этим удобно сделать некоторый шаблон, по которому штамповать лампочки. Так вот, таким шаблоном является класс, а объект — это уже конкретная лампочка.

Близкой аналогией является тип и переменная. Тип он один, и согласно типу вы можете создавать переменные. Каждая переменная уникальная и имеет свое личное состояние. При этом она всегда принадлежит какому-то типу. Таким образом, тип это такой шаблон, с помощью которого можно создавать переменные. Т.е. тип — это класс, а переменная — объект.

Синтаксис в С++ для типов/переменных и классов/объектов аналогичен. Также можно создавать указатели определенного класса на объекты, массивы объектов определенного класса, присваивать один другому и др..

Само определение ООП звучит так (база объекты, объект является экземпляром какого-то класса, есть иерархия).

Этапы ООП — абстрагирование (изучили), проектирование (сборка классов-объектов и взаимоотношений между ними) и программирование.

Пример иерархии классов и каков в ней смысл (общее объединяется и выносится наверх; это общее может быть как код, так и данные).

Примеры того, как это может быть в С++ (лучше в Real-Time с нуля) — просто пустой класс, добавление 1-2 полей, запись-чтение, добавление функций (методов), вызов функции, работа в контексте класса, две формы записи тела метода (внутри класса и вне), функции-помощники класса (объекты можно передавать как параметры).

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

Специальная функция перед уничтожением объекта — деструктор.


суббота, 27 июля 2013 г.

ПМО ИУС — Разработка через тестирование

Ещё в первые годы для нас очевидной была необходимость навыков тестирования лабораторных работ, в том числе не только просто что-то написать, но и посмотреть на это со стороны и попробовать сломать. Кроме того, такое мышление больше помогает к созданию какой-либо спецификации и пониманию всего проекта в целом.

На начальных стадиях было провозглашено что-то рода «необходимо полное функциональное тестирование». Данное требование сходу практически никто не понимал, а для понятия приходилось объяснять непосредственно при личном общении. Соответственно выход был от всего этого очень слабый.

Второй причиной появления данного отдела и направления являлась необходимость привязки части теории к практике, так как просто рассказ о водопаде, V-модели и спирали давал мало чего в плане понимания и знаний, а введение TDD непосредственно в курс давало наглядное представление как TDD работает и тем самым его можно было сравнивать с другими системами.

Причинами появления именно Google Test являлись: наличие зоопарка фреймворков для юнит-тестинга (о чем жаловались сами гуглеры — каждая собака желает иметь свой велосипед) и выбор межплатформенного и документированного из них; изучение ещё одного инструмента; точное попадание в С++ и лаконичность инструмента; потенциал развития и поддержки фреймворка, а также его совместимость с основной IDE (Buidler). Google Test стал совместимым только с XE2, поэтому Google Test появился в курсе только в 2012 году.

Следует отметить, что изучение новых и различных инструментов являлось одним и больших фокусов всего курса. Т.е. важным пониманием является то, что многое сделано до нас, и что этим многим надо уметь пользоваться, понимать что есть много полезных вещей и не только самим языком программирования жив инженер. В частности, од этот фокус попадали Doxygen и SVN. На заре ещё думали прикрутить JIRA'у, но руки не дошли.

Использование методологии TDD начиналось в третьей лабораторной работе. Этой теме была посвящена вся работа без каких-либо ООП дополнений, так как объем оказался слишком большим для рядового студента — большое количество осмысленных телодвижений как по сборке фреймворка и самому тестированию, так и по смене парадигмы в виде подключения внешней библиотеки классов, а не работой напрямую (см. 3-ю л.р. на графике).

Удержание фокуса

Тестирование проводится для всех функций, конструкторов и методов классов. Покрывается белый ящик по всем веткам поведения.

Обязательно сначала идет разработка класса и его тестирование, и только потом переключение из другого проекта (консоль или GUI) на новый собранный тег (которое через externals).

Сам Google Test подключается тоже как externals, в проекте достаточно было прописать пути и за-include-ть фреймворк.

Подробности

Слайды.

Старт и приближение к TDD начинался с рассмотрения моделей разработки ПО. Водопад — сам каскад водопада, необходимость этапов и правила отката, область применения (детерминированные с точки зрения технического задания системы). Если правила меняются, то использовать водопад сложно.

Диаметрально противоположная модель — спираль. Пример использования спирали (первый цикл, прототип, тест, обратная связь с заказчиком, уточнение требований, проектирование, разработка, … цикл). Каждый виток спирали — малый водопад. Итерации быстрые, ориентированные на изменяющиеся требования. Необходимость выхода на первый прототип. Условия применения спиральной модели — изменяющиеся требования, быстрое развитие ПО, необходимость экспериментирования, …

Между ними — V-образная модель. Как делается гибрид, в чем он выигрывает (соответствие каждой цикловой V отдельному процессу), преимущества и недостатки.

Только сейчас идет переход к TDD. Общая постановка TDD, как по алгоритму он применяется (классика TDD).

Следующий шаг — Google Test. Как инструмент, облегчающий автоматизацию процессов, происходящих в TDD. Да, можно сделать все вручную, но уже есть готовое помогающее решение и мы его будем изучать.

Получение Google Test и его подключение к проекту, рассказ на пальцах.

Простейший тест консольного приложения. Одиночный тест, EXPECT, ASSERT, EQ/NE/…, TRUE/FALSE, ….

Группы в Google Test. Зачем и что это такое. Порядок запуска тестов (или беспорядок (; ).

Выполнение теста как функции — любые дополнительные действия на С++.

Fixture-tests. Инициализация и завершение. Использование методов в служебных целях (контроль времени теста например).

Использование готовых Fixture.


пятница, 26 июля 2013 г.

ПМО ИУС — Оформление кода

Оформление кода начал внедрять ещё Андрей Логвиненко, но с этого времени прошел ряд изменений.

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

В связи с этим пришел к тому, что изначально подача шла из другой, но знакомой области — оформление информации вообще, а в частности текстов и веб-страниц. Каждый из них имеет свои особенности и стандарты, и среди всего код не исключение, а в зависимости от предметной области выбирается то оформление, которое наиболее облегчает взаимодействие пользователя с информацией.

Кроме того, по стандартам оформления в мире до сих пор чаще встречается нотации, похожие на венгерскую. Невооруженным глазом Lower Case найти было сложно, и часто возникали вопросы что это вообще такое, разве такое используют и зачем вы нас так. В связи с чем в лекционном курсе после рассмотрения общих вопросов оформления чего-угодно шел переход к разбору Венгерской нотации, начиная с истории возникновения, продолжая через принципы выбора идентификаторов и заканчивая Camel Case. После этого констатировался факт, что есть Lower Case, мы будем работать в нем, и сразу же начинался разбор сравнения Lower Case и классической венгерки.

С точки зрения правил со временем от того, что было, осталась только основа — все редко используемые вещи даже не упоминались (потому что никто не использует в курсе например указатели на функции), некоторые произвольные шаги были сведены к одному (возможность выбора Egyptian brackets убрана в пользу на одном уровне вложенности, так как принять один жесткий вариант проще, чем наблюдать за винегретом и трудностью принятия решений). Кроме того, часть оформления была вынесена вне рамок первой лекции, а особенности сущностей, о которых не знали, упоминались позже по мере появления материала (например префикс «m_» появлялся и описывался только во время появления в лекциях первого класса с полем).

Doxygen, также как и оформление, был обязателен со второй л.р..

Первая лабораторная была о SVN и первые шаги ООП (абстрагирование и понятие классов и объектов). Такой выбор потому, что больше двух тем на одну работу нанизывать не рекомендуется (исходя из практики). SVN потому что все лучше сразу делать как проект с нуля и под его контролем. Вторая лабораторная уже фокусируется на инкапсуляции в ООП как логический шаг и продолжение первой, а инкапсуляция отлично сочетается с оформлением кода — уже есть пример неоформленного кода, который нужно оформить, появляется несколько файлов и структура функций и данных для оформления и документирования, а также для автоматической документации Doxygen. Оформление кода также желательно ставить как можно раньше, но ранее SVN его не поставишь, потому только вторая.

Удержание фокуса

Необходимость приведения оформления при каждой сдаче л.р.. Большинство постепенно при таком контроле привыкало делать сразу так, как надо. Данные исправления были волнами — сначала заметили одно (например форматирование) — исправляем. Закончили — идем дальше (нижний регистр, пробелы, предел по длине, …).

Необходимость комментариев каждой сущности (класс, объект, поле класса, функция, возвращаемые и передаваемые параметры, броски исключений). Обязательность сборки Doxygen, все необходимые комментарии должны быть были подхвачены.

Студенты вне графика (в обе стороны) — рафинирование комментариев (удаление бесполезных, акцент на задаче, пред-условиях и пост-условиях, а не на конкретной реализации, указание информации для внешнего пользователя, а не про себя, лаконичность, …).

Подробности

В этой теме начало также издалека — пробуем прочитать обычный текст без оформления. Да, при некоторой сноровке это можно сделать, но работать с таким текстом неудобно. Если просто расставить пробелы, то становится легче (что можно сравнить) — мы легче воспринимаем слова как отдельные сущности. Да, раньше в летописях была экономия на пробелах, но сейчас пробелы не столь дороги. Следующий шаг — сравнение с более полным оформлением (знаки препинания, регистр). Все это дело придумано неспроста — для тех, кто будет читать текст.

Текстов разных много. Например при оформлении газетных страниц в отличие от книг текст разбивается на колонки. Это связано прежде всего с тем, что газетный текст (который по стилистике легок) менее утомителен при чтении в колонке, так как глазам не нужно перебегать большое расстояние по горизонтали. Это как пример того, что в каждой предметной области есть свои особенности форматирования, и программный код — не исключение.

Далее общая постановка задачи — зачем. Мы сразу же после написания первых строчек кода занимаемся его сопровождением, и оформление начинает работать на нас. Через месяц это мы — это уже другие мы, и спотрим на код другими глазами. Облегчить жизнь себе — хорошее и приятное дело.

Облегчение с помощью оформления уменьшает затраты на взаимодействие с кодом, что ведет к увеличению производительности, минимизации ошибок и всеобщему счастью.

Если команда использует одни и те же правила, то общение идет на одном языке. Если используется один язык в команде, это улучшает коммуникацию, способность поддержать код если коллеги нет, способность использовать внутренние библиотеки и все остальное.

Две концепции написания комментариев. Первая — сначала пишутся комментарии (то что хотим сделать на человеческом языке), потом код (то же самое, но на языке машины). Это позволяет лучше сформулировать и минимизировать ошибки преобразования за один шаг. Вторая (только с приобретенным опытом) — сначала пишется малый кусок кода (функция), такой, который можно удержать в оперативной памяти. Далее этот блок описывается в виде инвариантов, пред- и пост- условий, особенностей выполнения, комментариев для облегчения последующего понимания. После — оперативную память можно очищать, так как комментарии написаны. Но только когда научитесь думать на C++.

Венгерская нотация придумана давно и живет в недрах MS. Так как это было давно, то было важно наличие типа в имени. Типов может быть много, и в больших проектах это тяжело поддерживается и входит из-под контроля. Кроме того, с повышением структуризации кода, применением IDE и проверки типа на уровне компилятора необходимость указания типа резко падает, в связи с этим в высокоуровневых языках типизация такого рода происходит реже.

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

Сравнение c Lower Case. В последней отсутствует тип (облегчение работы с кодом), все буквы в нижнем регистре (облегчение восприятия и отсутствие неоднозначностей и ошибок при двух регистрах).

Использование префиксов и постфиксов в Lower Case по широкополосным служебным целям. Например указание типа «_t» ускоряет принятие решения при создании переменной по умолчанию, а также отличает принципиальное качество тип и переменная.

Зачем системы автоматической документации — выполнив несколько несложных правил мы можем связать код и комментарии, получив от этого плюшки. В том числе, передать код специальной программе, которая обработает её и предоставит некоторый документ, по которому удобно будет проводить поиск и навигацию.

Мы работаем с Doxygen, и по нему сразу оформляем все комментарии. Пример генерации документации на глазах (демонстрация того, что это просто и быстро, а также то, что получается на выходе и какая связь с кодом).

Систем автоматического генерирования документации много, Doxygen одна из них.


четверг, 25 июля 2013 г.

ПМО ИУС — Системы контроля версий

Исторически все развивалось так, что системы контроля версий были добавлены в курс ~ в 2008-м году, когда ещё не было Git'ов, Mercurial'ов и пр., а SVN занимал 90% рынка новых стартующих проектов. Subversion уже длительное время использовался в «Интервэйле» (как минимум с 2004 года) и этот опыт напрямую переносился. Кроме того, система организации каталогов проектов и подключения библиотек была взята в определяющем так, как это было организовано в компании.

По теме была запланирована одна лекция, которая обычно длилась 1-1.5 пары. Это была первая тема, так как все, что делалось в дальнейшем, делалось под контролем SVN.

SVN-сервер находился на кафедральном сервере и студенты имели доступ к нему из любой точки ВУЗа. Каждый из учащихся получал свой репозиторий, с которым он работал в течение семестра. На лабораторных в подавляющем числе случаев использовался интерфейс TortoiseSVN.

Удержание фокуса

Каждая лабораторная должна быть в конце зафиксирована в репозитории в виде тега и это проверялось при сдаче. Приучаем к отработке всего цикла — checkout, правки одной малой задачи, commit с описанием что было сделано. Для многих действий нужно было делать все в первых работ step-by-step, что, зачем, как.

checkout на локальные машины, а не на внешние сервера. Много копий (локальных и в репозитории) это плохо — то что закоммичено, того не вырубишь топором — переход на новую идеологию хранения исходников.

Установка под контроль сразу же после появления исходных файлов. За контроль EXE/OBJ/… давать по рукам и заставлять снимать из под контроля.

Подробности

Слайды.

Со временем пришел к тому, что изложение понятий систем контроля версий нужно начинать издалека. Это не что-то страшное, а близкое, только на другом языке.

Сначала рассмотрение понятия проекта — нечто с определенной целью в виде некоторой активности в течение времени. Подготовка к вечеринке, выполнение курсового, поход на рыбалку, регулярная уборка в доме — все это проекты (будущий проект в svn).

Каждый проект с чего-то начинается и имеет последовательность действий. Каждое малое действие может быть выделено и описано отдельно (будущие ревизии и их описание в svn).

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

С точки зрения контроля проекта во времени у нас могут возникать вопросы: в каком состоянии был проект в момент X? кто сделал действие Y? что изменялось в проекте за месяц Z? что надо сделать, чтобы отменить изменения за позапрошлую неделю? Данные проблемы надо как-то решать, и решение зависит от организации контроля проекта во времени (будущие типичные задачи при работе в svn).

Как мы можем контролировать проект во времени? Завести блокнот, создать ряд каталогов на диске, держать в голове, … у каждого способа есть свои достоинства и недостатки (блокнот копировать сложно но он надежный, компьютер доступен не всегда, но он быстр, в голове можно и забыть, но это всегда под рукой).

Так что такое системы контроля версий? Это вспомогательные инструменты, помогающие автоматизировать описанный выше процесс, тем самым уменьшить количество ошибок, предоставить удобные функции и др..

С точки зрения автоматизации уже имеются всем знакомые системы контроля версий, которые помогают нам в этом. Undo/Redo в где угодно (хоть в MS Word), страница в википедии (показываем в онлайне историю правок с датами, комментариями, возможностями сравнения и отката, …). Таких ресурсов много — история изменений одного файла в Dropbox, изменения страниц в pbworks.

И только теперь на сцену выходит Subversion и начинаются слайды.

Понятие архитектуры клиент-сервер. Хранилище одно, оно надежное и доступное отовсюду. Клиентов много, они общаются с хранилищем и сами себе буратины.

Две модели версионирования (блокировка-изменение-разблокировка и копирование-изменение-слияние). Преимущества и недоставки обеих моделей (бинарные файлы и текстовые, возможность слияния, ручное слияние, администраторские проблемы (админ ушел в отпуск, а блокировка осталась)).

Понятие ревизий в Subverison. Ревизии атомарные, инкрементируются только при успешном commit'e. Каждая ревизия — в идеале одна отдельная задача.

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

Фиксация изменений (commit). Инициирует клиент, дает описание изменений. Все хорошо — фиксируется, плохо — не фиксируется (требуется ручное вмешательство при слиянии, проблемы подключения, …). Описание изменений ассоциируется с ревизией и потом может быть использовано.

Обновление (update). Использование когда возможны внешние правки (например работа в команде).

Откат локальных изменений (revert). Команда отрабатывает локально, без подключения к серверу. Локально всегда хранится копия с последнего checkout'a или update'a, чтобы система знала, что было исправлено локально, и чтобы можно было таким образом откатить изменения.

Понятие контроля файлов в WC. SVN должен знать, что ему контролировать, т.е. каждый файл на диске находится под контролем SVN или нет. Если мы сами создаем файл, то SVN о нем ничего не знает, и при необходимости мы должны ему сказать. Под контроль ставятся только исходные, но не производные (EXE, OBJ, …) файлы. Команды установки код контроль и снятия из-под контроля. Копирование и перемещение в SVN — не создает нагрузку на сервер.

Структура хранилища с точки зрения классики SVN — trunk, tags, branches. Что такое trunk, зачем нужны теги (фиксация стабильной версии, передача конкретной версии заказчику, выделение версии для конкретных работ, …). Понятие branches — выделение отельных веток и слияние (один программист пилит новую функциональность, второй правит баги, и оба друг другу не мешают; отдельные ветки для подпроектов и подзадач, когда требуется дальнейшее развитие).

Описание полного типичного рабочего цикла (checkout, updaten commit).

Свойства в SVN, на примере svn:externals. Подключение внешних ресурсов через externals (иначе не получится), экономия места, переключение externals на другую версию.

По обстоятельствам — демонстрация создания svn-сервера и типичных действий над hello world.


среда, 24 июля 2013 г.

ПМО ИУС — Содержание курса


Планирую сделать некоторое описание содержания курса на последний из семестров с выкладками того, почему было сделано так и какие имели место особенности. Букв получается много, поэтому распилено на несколько сообщений. Сначала — общее содержание.
Системы контроля версий
Изучение систем контроля версий в общем, практическое изучение Subversion на всем протяжении курса.
Оформление программного кода, системы автоматической генерации документации.
Общие вопросы оформления (зачем, когда, как), практическое изучение на всех лабораторных кроме одной, + также все под Doxygen.
Разработка через тестирование (Test Driven Development)
Спектр от водопада до спирали, использование Google Test с полным функциональным тестированием на всех лабораторных, кроме 2-х.
Объектно-ориентированное программирование
Последовательно, теоретически и практически, с периодическим повторением — абстрагирование, типизация, модульность, инкапсуляция, наследование, полиморфизм.
Rapid Application Development
GUI интерфейс на практической основе C++ Builder, изучение базовой событийной системы в Builder (который выглядит как однопоточный Reactor).
Исключения
Традиционные способы обработки исключительных ситуаций (игнор, останов, общая функция, возврат кода ошибки), исключения как инструмент, создание своих классов исключений и исключения сторонних библиотек на примере std::exception и исключениях среды C++ Builder.
Структуры данных
Разбор понятия структур данных. Линейные структуры данных: массив, стек, очередь, списки (разные). Деревья, бинарные, балансировка деревьев, способы обхода. Куча (heap). Динамическая и статическая реализация (линейных, деревьев, кучи). Хэш. Пример экзотической структуры данных — Sparse Array с инициализацией элементов только по требованию. (здесь без лабораторных)
STL
Основные понятия библиотеки: контейнеры, итераторы, алгоритмы (только). Разбор vector, list, stack, queue, priority_queue, deque, map, multimap, set, multiset, heap. Несколько алгоритмов.
Потоки ввода-вывода
Общие понятия потоков, иерархия потоковых классов std::, буферизация, функции потоков и манипуляторы, ошибки потоков и файловые потоки.

Развитие проекта под Subversion в лабораторных (кликабельно):


суббота, 20 июля 2013 г.

ПМО ИУС — Автоматизация и разработка IT-инфраструктуры

В процессе работы над курсом был собран ряд инструментов автоматизации, позволяющих облегчить, упростить и улучшить весь процесс обучения, а также расширить его возможности.

Начальные условия

Прежде всего следует напомнить о том, какой мир был в то время. Так, в 2003-2005-м году Интернет не был таким доступным как сейчас — только dial-up за по нынешним меркам бешеные деньги со скоростью 2кб/с и постоянными обрывами связи. Возможности использования готовой SQL-БД резко ограничены как в силу отсутствия подходящих пакетов, так и потенциальной необходимостью переездов между серверами с соответствующим бюрократическим сопротивлением. HTML был максимум XHTML'ом, набирающим обороты. JavaScript максимум что делал, это проверял поля формы на правильность количества букв полей с диагностикой только через alert. Из web-языков царствовал PHP, его планомерно покусывал Perl, Java существовала в виде экзотических апплетов.

Что касается организационной части, то в этом плане картина для нас уже выглядела древней. Абсолютное большинство операций по выдаче заданий, контролю выполнения, предоставления информации в удобном виде, какой-либо автоматической обработки — не существовало. Преподаватели давали нам лабораторные в методичках, а индивидуальные задания в отдельных бумажных листочках. Многообразие вариантов представлялось собой максимум вариант номер N, иногда один из 2-4-х прямым текстом, иногда таблица, в которой студент номер N выбирает набор параметров в N-й строчке таблицы. Кроме этого, было много бумажной работы — мы многие отчеты либо писали вручную, либо печатали на одном на всю группу принтере, потом эти тонны бумаги куда-то надо было сдавать. Если обратить внимание, то на все это уходила уйма времени.

В течение последних лет в группах до сих пор постоянно на первых занятиях были студенты, которые приносили тетрадки для лабораторных работ (чтобы туда писать), и ещё много кто переписывал задания себе куда-то. Очень часто приходилось объяснять, что сервер доступен из любой точки БелГУТа, задания никуда не пропадут, можно быстро будет собрать отчет и вся бюрократия в электронном виде. На основании этого делаю вывод, что скорее всего со степенью автоматизации в ВУЗе все так же плохо, а студенты во время учебы зачастую занимаются переписыванием и перепечатыванием.

Когда информация о процессе выполнения работ собирается в одном месте, то появляются возможности делать над ней что-либо. Например, если мы смотрим в бумажный журнал, то можем посмотреть, сколько отличников а сколько двоешников в этой или этой группе, сколько было пропусков, сколько народу выполнило курс, провести какие-либо сравнения и т.д.. С точки зрения такой коллекции информации максимум что было, это преподавательский журнал. Единственный пример который мы видели другого плана — у Харлапа С.Н. в курсе ПМО МПС вся информация собиралась в Excel-табличке, которую потом можно было через FTP в R/O посмотреть. Но даже в таком варианте чувствовались плюсы — файл по сети можно забрать и посмотреть из сети, данные самые последние, можно смотреть всем и подумать над происходящим всем (преподавателю, студенту, декану, …).

Первый сезон

В первый год задания формировались в doc-файлах и раздавались по вариантам. То же самое что до, только в e-виде, что было естественно, так как больше времени уделялось содержанию, чем остальному.

В это время Сергей Зобов выбивает и создает наш сервер кафедры, обеспечив стабильную и от-администрированную рабочую станцию, на которой размещается ряд ресурсов. Сначала это были странички, но по мере степень наполненности и сложность исполнения возрастала. Но в любом случае у нас появилась аппаратно-программная платформа, на которую можно было ориентироваться.

Было понятно, что если что-то делать в качестве предоставления информации, то нужно это делать на вебе. В то время веб эволюционировал быстро (что сейчас происходит не знаю), — браузеры и платформы были разными и жили каждый своей жизнью, кроме того, какие из новых фич станут стандартными было не понятно. Ко всему прочему война браузеров была и у нас в Университете — на ВЦ на старых машинах жил IE, на новых жестко прописанная админами Opera непредсказуемой версии, в аудиториях нашей кафедры была демократия и возможность выбора, а в оставшейся части ВУЗа — самый настоящий заповедник гоблинов. Поэтому те вещи, которые делались в первый год были пилотно-экспериментальными и мы быстро пришли к идеям пуленепробиваемого веб-дизайна (минималистичность самых стабильных фич, работающих везде независимо от всего).

Программный инструментарий также был не ясен (ввиду малого опыта в вебе). И на начальном этапе, например, эта табличка генерировалась с помощью EXE-программы на Pascal'e, данные для генерации вводили преподаватели (как набор флагов сдал-не сдал) методом редактирования файла удаленно с доступом по FTP. Кроме того, форма подачи несколько раз изменялась.

Приблизительно в это время я создаю сайт Гомельского Айкидо (все полностью, клиент-сервер, частично дизайн, форма подачи материала, … согласуя только содержимое и дизайн с руководителем объединения; до настоящего времени сайт функционирует на этой системе). Сайт несколько раз переписывался, начиная от набора страниц и заканчивая внутренним движком с файловой БД, полным разделением «данные→форма представления→оформление на устройстве» (на языке веб-разработки можно описать как «только полезная информация→HTML→HTML+CSS», наверно есть какой-то известный паттерн по этому поводу (; ), со своими внутренними велосипедами (свои счетчики, лента новостей, под-движки для фото-галерей, функциональности для статей, подсистема для создания меню и др..). В какой-то момент времени я взял то, что было сделано для сайта и фактически сделал форк на отдельную ветку.

Сейчас смотрю на сохраненные данные и исторически вижу, что уже во втором сезоне работы со студентами у нас было сделано многое для сервера ПМО ИУС и автоматизации процесса — переход всего на веб клиент-сервер нашего интРАнета.

Технические подробности

Основные функциональные вещи обеспечивала серверная часть, собранная на Perl'е. Выбор обусловился тем, что совсем рядом существовало две системы, написанные Максимом Кузьмичем тоже на Perl'e (система для автоматизации проведения олимпиад по программированию и система автоматизации тестирования студентов).

В качестве самого нижнего уровня для сайта и системы сервера ПМО ИУС использовалась мною написанная файловая БД. Такой выбор был сделан потому, что файловая БД менее независима от хостинга, не требует дополнительных ресурсов, легко перемещаема и редактируема с ориентиром на то, что будет справляться со своими задачами при небольших нагрузках. Не знаю как сейчас, но в то время с SQL-серверами были проблемы (на том же хостинге они стоили приличных денег).

Файловая БД позволяла создавать сущности в виде реляционных таблиц, в которых все данные представлялись в виде строк (потому что на Perl'ах все есть строка и типизация приводилась в конечном счете к ней). При этом имелась обязательное наличие PK (2NF) и было собрано ряд функций (такие как поиск поля, замена поля, получение содержимого таблицы в скрипт, сохранение изменений, кэширование таблиц находящихся в работе, работа в R/O не требующая синхронизации одновременно запущенных скриптов). Запускаемые скрипты при этом уже работали с непробиваемым слоем, под которым находились данные на диске.

Рядом с файловой БД находилась система по автоматизации предоставления материалов на сайте. Данная система использовала информацию из БД как опорную, по запросам пользователя выдавала уже веб-содержимое, обеспечивала поддержку взаимодействия с клиентом (cookie, регистрации и пр.) и как любая уважающая себя CMS, занималась управлением ресурсами сайта (общая система с хранением страниц, изображений, ссылок, менюшек, опций и пр., + функциональность к этому).

Данного собранного каркаса оказалось достаточно, чтобы за год взлететь и обеспечить базовую организацию всей информации курса (когда две большие разницы — информация в e-виде и способна быть извлечена и обработана программно, или она в чем-то, что читаемо только человеком). Далее на основании этого все данные, относящиеся к рабочему процессу (литература, задания, результаты, темы зачетов, контрольные сроки и т.п.) переместилось на сервер. В качестве примера автоматической обработки — генерация различных форм отчетов (таблиц рекордов, контрольных сроков и др.).

Архитектура и развитие

Глядя сейчас на историю могу сказать, что с точки зрения архитектуры сложилось все удачно. Угадалось то, что архитектура как таковая была очень минималистичной, т.е. не было жестких функциональных правил, а базовые сущности (что в БД, что в веб-движке) были простыми и легко поддающимися под любые запросы. Особенность последующих лет заключалась в том, что все, что над таблицами данных (интерфейс пользователя, веб-представление, формы генераторов, системы обработки запросов от студентов и преподавателей и др.), несколько раз переписывалось по причине того, что «No project manager plan survives contact with the development». Как только мы внедряли какой-либо вариант системы, то через месяц становилось понятно, что в ней есть существенные недостатки, которые выявлялись только после внедрения, когда конечные пользователи пробовали с этим что-то делать, а мы за этим наблюдали.

Если для типичных действий получается так, что делается 5 кликов по разным точкам, и понимаешь, что это можно-лучше сделать за 1-2, то это лучше исправлять. Если 5 из 10 человек регулярно не находят что-то, то с этим надо что-то делать. Если при каком-либо действии делаются ошибки, то надо организовать действие так, чтобы пользователь их делал намного реже, а лучше чтобы это контролировала автоматика.

Примечание к предыдущему абзацу — как организовывать этот процесс, важность конечного пользователя и зачем все это надо (я встречал всего пару человек, которые действительно как-то это понимают, и это — не программисты вообще) лучше всего видел в курсе Human Computer Interaction, рекомендую, достаточно посмотреть видео-лекции).

Прошло где-то 3 итерации, при которых существенно переписывалось почти все. Каждая из итераций — один семестр-год, так как когда процесс запущен, то что-то менять череповато. За один цикл обучения собирался список и в дальнейшем пересборка под новые изменения. Какая бы не была верхнеслойная архитектура, она отправлялась в мусорку. Важной и стабильной оказалась только самая нижняя часть системы — её универсальность, адаптивность, простота исполнения и прозрачность.

Финализация

Общий эволюционный процесс вышеописанного фактически остановился где-то в 2007-2008. Пилить систему было куда и зачем — фиксация удобной архитектуры, создание системы не только для себя но и для других (это отдельный большой кусок работы), куча фич вида отослать новые задания студентов на e-mail. Но в это время состав программистов курса на кафедре сокращается втрое, соответственно падает сила обратной связи и разнообразие опыта. Кроме того я сам перехожу на full-time в «Интервэйл» и ресурсы остаются только на поддержание системы.

К слову говоря, в свое время сайтовый фреймворк был переведен с Perl+FileBD на Java+SQL, но опять же, развитие потеряло свое поступательное движение.


воскресенье, 14 июля 2013 г.

ПМО ИУС — Развитие и общая тематика

О последующем периоде до настоящего времени писать проще, так как ведение курса и ответственность за него перешла на меня.

2005-2007

В это время Сергей Зобов переходит на другую дисциплину, а к ПМО ИУС официально подключается Максим Кузьмич, так как он в это время был в магистратуре. Где-то в течение этого времени периода плюс минус год всем курсом занимаемся мы втроем — я, Максим и Андрей Логвиненко. Отличительной особенностью этого времени является то, что все мы уже являлись программистами со значимым опытом, и при этом стиль работы каждого из нас определялась индивидуально — мы только обменивались идеями, согласовывали материалы лекций и темы лабораторных, а форма организации, индивидуальные задания и многое другое уже решалось каждым по-своему. И хочу сказать, она была существенно разной.

2008-2013

Не затрагивая изменения внутренностей курса, в первом году (плюс минус) покидают кафедру Максим Кузьмич и Андрей Логвиненко. Как результат из программистов остаюсь только я, и вести в таком ключе становится сложнее, так как такого рода курс требует серьезной подготовки. Система отношений в преподавательском составе дисциплины меняется из тройки независимых к чему-то более похожему на маленькую иерархию. Нагрузку на весь поток я взять не в состоянии, как результат за мной остаются лекции и 1-2 подгруппы микропроцессорщиков (это треть факультета, более ориентированного на микроэлектронику), остальными занимаются те, на кого удобнее на кафедре распределить нагрузку. Олимпиадное движение в это время затухает и расстворяется за отсутствием кого-либо, этим занимающегося. Над курсом я проводил ещё эксперименты и попытки улучшения, а также изменения содержимого для движения в ногу со временем, но стало понятно, что ресурсы уже не те.

Тематические изменения

В первом же году (2005) стали очевидными несколько проблем, которые стали понятны только к концу семестра. Первая из них — оставшийся материал и лабораторные по алгоритмам, которые коррелировали с тем, что мы знали и изучали на олимпиадном программировании. Так 3-я л.р. представляла собой работу с рекурсией, и как показала практика, для большинства студентов это оказалось слишком серьезным барьером. Без посторонней помощи его не преодолевал фактически никто, а для совместного решения необходима была кропотливая индивидуальная работа. Такая же история с графами, до которых дошли единицы. Поэтому их прохождение шло с существенными временными и моральными потерями, так как осваивание абстрактных вещей давалась с трудом. В связи с этим после первого же года были исключены все лабораторные работы с алгоритмами в пользу облегчения курса и большего уклона к ООП. Параллельно у нас был неофициальный кружок (в то время его организацией, автоматизацией, сервером, заданиями и прочим занимался Максим Кузьмич), который как раз посещали те, кто готовился к олимпиадам, и соответственно те способные студенты, которые потенциально хорошо могли освоить алгоритмизацию, при желании делали это там.

Вторая проблема заключалась в том, что лекции были больше теоретическими, о программной инженерии вообще, и поэтому слабо коррелировали с лабораторным курсом. Года 3 это существенно ощущалось и лекционный материал каждый год перерабатывался, более менее устаканившись к 2008-2009.

Существенным изменением, повлиявшим на весь курс, явился принцип общего проекта, который я различными способами старался усилить все время. Смысл его заключался в том, что цепочка лабораторных работ представляла собой единое целое, как проект, который постоянно нужно дорабатывать. Только первая лабораторная работа делалась с нуля, остальные — это изменения из предыдущей. Такой принцип работал сразу в нескольких положительных моментах. Во-первых, многие действия можно было вынести как повторяющие, и это усиливало закрепление материала. Например, со второй лабораторной все работы должны были быть оформлены строго по правилам оформления и собрана документация Doxygen. На каждой сдаче это строго контролировалось, поэтому студенту приходилось в случае лени переформатировать всю работу, писать комментарии и пересобирать Doxygen, и часто это приводило к пониманию того, что лучше оформлять правильно все сразу. После внедрения Subversion каждая лабораторная — отдельный commit, выделение тега, что тоже приводило к закреплению навыка. После внедрения Google Test — каждый раз написать тесты для новой функциональности, проверить, и только потом пускать класс в рабочую среду.

Следующее изменение — объединение нескольких тем в одну лабораторную работу. Л.р. становилась больше по объему, но при этом уменьшалось само количество лабораторных работ. Это раза в 2 снизило издержки по сдаче-приему-бюрократизации процесса (интересно, но эта идея была впервые озвучена деканом в процессе разбора полетов).

В один момент времени студент не мог работать больше, чем над двумя лабораторными работами, и это контролировалось автоматической системой выдачи заданий. Сначала были открыты только 1 и 2 работа, 3-я закрыта. Если студент сдавал полностью 1ю или 2ю, то открывалась 3я. И т.д. (идея взята с курса коллеги по кафедре Бориса Френкеля). Правило было жестким, и, таким образом, если студент ничего не сдавал весь семестр, то он не мог попытаться принести и сдать сразу все л.р.. Это все понимали, и оно давало ощутимый эффект.

В общем случае предыдущее нововведение являлось частью принципа, который когда-то нам озвучил Сергей Харлап, заключавшийся в максимальном переносе работы студента конца семестра (сессии, зачетной недели) в основное время. Смысл этого был в том, что невозможно чему-либо существенному научиться в короткие сроки. Что-то сделать (именно что-то, на что-то отдаленно напоминающее), списать, выучить на день, но не научиться. Элементы данного принципа внедрялись на всех уровнях. Например хорошим примером являлся Иван Матылицкий, который сдал все работы где-то за 1-1.5 месяца и был освобожден от посещения занятий. Остальная группа смотрит на это и понимает, что это возможно, и что это принципиально отличается от того, чтобы просиживать занятия.

По темам добавились абстрагирование, полиморфизм, инкапсуляция, среда RAD (построение GUI интерфейса), STL (алгоритмы и структуры данных), вернулись исключения. Первые 3-4 года существовал XML+HTML+CSS (общие принципы на 1.5 лекции и 1 л.р., разбор понятий validation, well-formed; XML; CSS; DTD). Была попытка внедрения л.р. по шаблонам (templates в C++), но оказалась неудачной в силу неусваивоемости и тотальной списываемости. Весь курс был обернут под SVN, Doxygen, Google Test, а также переведен на несколько проектов (несколько branches/tags с подключением через externals, об этом подробнее позже).

Изначально как основную среду мы использовали C++ Buidler. Основная причина — низкий порог вхождения для неподготовленных людей. Жестко недекларировалось (хотите приносите в VS, хотите хоть в Qt), но за все время все, кто хотел принести в чем-то другом, так этого и не сделали. Стартовали мы с C++ Builder 6.0, потом был 2007, 2009, и последний переход на XE2 — это был первый из билдеров, на котором скомпилировался Google Test, так как эмбакадеровцы меньше стали заниматься самодеятельностью и приблизились вплотную к VC.