Последний Classic Season. В этой серии вы разберете несколько знакомых уже вам проектов, и будете рассматривать разные варианты их тестирования, а также мы поговорим о "C", и его нескольких фич, которые показались мне интересными.
Обзор скринкастов сезона 5
1. Collapsing Services Into Values
В серии What Goes in Active Records мы рассмотрели некоторые конструктивные ограничения для того, что происходит в моделях ActiveRecord. Иногда эти ограничения могут привести к извлечению очень маленьких классов, что часто бывает неудобно.
Этот скринкаст рассматривает один такой класс: одну строку сервис кода с тревожно длинным тестовым файлом. Создавая новый класс значений и затягивая интерфейс службы вокруг него, мы немного сокращаем тесты. Затем, свернув службу в новый класс значений, мы сокращаем их еще больше. У нас остались тесты, о которых легче рассуждать, и с новой абстракцией, подтвержденной кодом.
Наконец, хотя это не указано в скринкасте, тесты полностью изолированы от Rails после этого рефакторинга, тогда как исходные тесты интегрированы с ним. Новые тесты примерно в восемь раз быстрее (и будут оставаться быстрыми даже по мере роста приложения).
2. Splitting Active Record Models
Это продолжение предыдущего скринкаста, «Collapsing Services to Values». Мы преобразуем объект значения Subscription, который мы создали, в таблицу базы данных и модель ActiveRecord.
Хотя создание объекта значения в последнем скринкасте очистило систему, оно все равно оставило класс User с большим количеством знаний о подписках. Пользователь все еще содержал свои проверки, и в полной системе он имел бы знания о том, как создавать подписки от себя и обновлять себя из подписки. Когда мы извлекаем подписки в их собственную таблицу и модель, это знание полностью исчезает из Пользователя, хотя оно повторно поднимает вопрос, с которого мы начали: где логика?
3. Removing a Rubinius Feature
Rubinius - это реализация Ruby, известная тем, что она «написана на Ruby», хотя это не совсем так, поскольку у нее есть большая VM, написанная на C ++. Начнем с краткого изучения структуры Rubinius, ориентированной на загрузку системы объектов. Затем мы удалим функцию из нее, обновив все исходные файлы, ссылающиеся на эту функцию, а затем проверим изменение как путем запуска тестов, так и путем визуального контроля.
Примечание: В самом начале я промахиваю и говорю, что суперкласс класса - это класс. Это неверно: суперкласс класса - это модуль, а класс класса - это класс, который находится в соответствующей строке. Установку системы объектов трудно держать!
4. Python vs. Ruby Objects
Многие люди предполагают, что Python и Ruby имеют похожие объектные системы. Это похоже на то, что они имеют примерно такой же уровень динамической выразительности, но способ их достижения на самом деле совсем другой. Мы сравним две системы, сосредоточившись на одном очень фундаментальном делении между ними: Python имеет дело с атрибутами, но Ruby имеет дело с методами, причем каждый из них реализуется с точки зрения другого. Это приводит к некоторым характерным свойствам языка: согласованность Python и сосредоточенность на правильности и противоречивости Ruby для определения и вызова методов.
5. Where Correctness Is Enforced
Представляя наиболее наивное возможное приложение Rails, он, вероятно, проведет большую проверку данных на уровне контроллера. Разумеется, мы этого не делаем: мы подталкиваем ответственность за целостность данных до ActiveRecord через проверки. К сожалению, проверки ActiveRecord недостаточно хороши: есть несколько способов, которыми их можно обойти стороной, и эти способы в конечном итоге появятся во многих реальных приложениях. Этот скринкаст рассматривает эти механизмы обхода, проблемы, которые они создают, и как их решать, используя реальные ограничения базы данных.
6. Separating Arrangement and Work
Жесткая привязка, обозначающая имя одного класса внутри другого, является проблемой как для проектирования, так и для тестирования. Это упрощает настройку границ объектов, потому что статические имена должны быть изменены, а разные зависимости не могут быть заменены для этих жестко связанных точек. Это делает тестирование сложнее, потому что вы не можете протестировать один объект, не ссылаясь на другой. Инъекция зависимостей может помочь в этом, но это действительно особый случай более общего принципа: отделить расположение частей программы от работы, которую они на самом деле делают.
Этот скринкаст является примером разделения организации работы, но не путем инъекции зависимостей. Вместо этого мы выделяем поток данных между объектами из самих объектов, что в конечном итоге позволяет нам преобразовать в простую модель actor-based одним плавным переходом.
7. Primitive Obsession
Primitive Obsession - это использование примитивных значений - целых чисел, строк, массивов, хэшей и тд.. Вместо того, чтобы абстрагироваться, этот скринкаст является конкретным примером: мы изучаем класс Screencast класса Destroy All Software, а затем заменяем его по всей системе простым хэшем. В конце мы рассмотрим изменения, чтобы понять, что Primitive Obsession относится к дизайну.
8. Isolating by Separating Value
Этот скринкаст представляет собой метод написания изолированных тестов без использования заглушек или макетов. Мы будем явно разделять часть значения объекта - его переменные экземпляра - из части поведения - его методы. Затем, тестируя другие классы, мы можем интегрировать их только с частью значения, как это описано в методах доступа.
Мы избегаем опасности того, что mocks и stubs не синхронизируются с тестируемым кодом, поскольку мы интегрируемся с реальными методами доступа, которые будут существовать в конечном объекте. Мы также избегаем опасности случайного вызова сложных методов, которые не должны подвергаться испытанию: поскольку мы проверяем только часть данных объекта, нет риска интеграции.
9. Imperative to OO to Functional
Этот скринкаст демонстрирует рефакторинг через три с половиной парадигмы. Во-первых, мы видим код в императивной форме: код, который мутирует данные, с разделяемым кодом и данными. Затем мы объединяем некоторые данные и код, чтобы сформировать объект для получения объектно-ориентированного кода: код и данные смешаны с мутацией. Мы быстро рассмотрим вариант этого, где объекту разрешено иметь только чистые функции (без мутации или ввода-вывода). Наконец, мы удаляем объект, оставляя только функции, что дает нам более стандартное функциональное решение.
10. Debugging With Tests
Мы начнем с перевода отчета об ошибке в тест, обеспечивающего объективную проверку первого шага любого исправления, с которым мы сталкиваемся. Чтобы имитировать незнание системы, мы не будем смотреть на производственный код, пока не дойдем до самой нижней части стека. Чтобы имитировать сложную ошибку, в которой трассировка стека не указывает на полную тонкость взаимодействий, мы будем нажимать один шаг за раз, а не просто прыгать в самую глубокую часть стека. Когда мы перейдем к самому дефекту, мы сможем затем запустить те тесты, которые мы сгенерировали в обратном порядке, «popping stack» обратно в системное представление.
11. Test Cases vs. Examples
Перед BDD и инструментами вроде RSpec - тесты часто записывались в стиле «тестового случая»: они были сформулированы в терминах компьютера. Хорошо написанный RSpec обычно подходит к тестированию: вместо того, чтобы сосредоточиться на терминологии программного обеспечения, поведение человека видимо указано на английском языке, а примеры сопоставляют эти английские описания с терминологией программного обеспечения. В этом скринкасте мы реорганизуем часть тестового набора Hamster, переведя его из стиля тестового примера в примерный стиль. Для этого потребуется много компромиссов.
Примечание. В тесте мутации есть ошибка, которую я пропустил во время записи. Поскольку переменные «let» RSpec запоминаются, «пустое» значение вычисляется только один раз. Если бы он был мутирован, обе ссылки на «пустые» указывали бы на мутированное значение, победив тест. Как отметил Майрон Марстон, тест прошел бы даже класс Ruby's Array, который явно мутирует. К сожалению, ошибки, подобные этому, возможны при проверке теста путем разбиения самого теста, а не на разрыв производственного кода.
12. A Bit of C
Большая часть программного обеспечения, работающего на наших машинах, написана на C-операционная система, наши виртуальные машины и компиляторы, оболочка Unix и ее различные утилиты и наши редакторы. Этот скринкаст вкратце представляет проект, написанный на C, с уделением особого внимания его модульным испытаниям и способам, с помощью которых его дизайн похож на OO. Это не учебник по C-программированию, он требует значительного обучения. Но, как показано здесь, многие идеи и методы, используемые в более современных языках, действительно применимы непосредственно к программированию на C.
Примечание. В приведенном здесь коде есть видимая ошибка указателя («trie_create» неправильно обнуляет поле «values» вместо всего trie). Спасибо Лео Кассарани за это.
13. Analyzing Context Switches
При анализе поведения или производительности системы существует огромный спектр доступных инструментов: все, начиная с среднего значения нагрузки, которое доводит машину до одного номера DTrace и STrace, что может обеспечить очень мелкозернистую информацию. Мы кратко рассмотрим среднюю нагрузку и почему ее недостаточно. Затем мы рассмотрим один конкретный метод, который находится между двумя крайними значениями: команда / usr / bin / time, которая может сообщать много статистики о выполнении программы. Мы будем использовать ее для вычисления количества непроизвольных переключателей контекста в каждом из сценариев «Cucumber » «Destroy All Software's», что дает нам отправную точку для локализации аномалии в поведении системы.
Примечание. Некоторые вопросы были заданы в отношении точных сведений о среднем уровне загрузки. К сожалению, я не эксперт по внутренним ядрам Linux, поэтому я буду сопротивляться желанию исправить себя. Чтобы быть кратким: я, возможно, значительно завысил влияние IO на средний уровень загрузки. В любом случае - среднее значение нагрузки находится в одном пределе непрерывности инструментов анализа производительности, и как только вы пройдете первые несколько секунд анализа производительности, вам нужно будет копать глубже.
14. Actor Syntax From Scratch
В этом скринкасте мы используем замечательную гибкость Ruby для фактического воплощения синтаксиса Actor Syntax. Мы начинаем с теоретического синтаксиса, а затем переходим к рабочей системе: получаем ее для анализа; заставляем его работать; а затем заставляем его выполнять работу, которую мы хотим, чтобы он делал. Это подчеркивает гибкость Ruby, а также служит простым объяснением Actor model.
15. Running Tests Asynchronously
В большинстве демонстрационных скринкастах Destroy All Software тесты выполняются синхронно: процесс тестирования разветвляется из редактора и блокирует терминал. Этот скринкаст показывает еще один вариант: асинхронно запускать тесты в другом расколе. Во-первых, мы используем tmux, который является общим подходом. Затем мы делаем это с использованием примитивов Unix: named pipe для связи между двумя окнами и shell script для управления связью.
16. Test Recommendations
Этот скринкаст предоставляет список рекомендаций по тестированию. Некоторые из них были упомянуты попутно в других сценариях, но вся группа никогда не была представлена вместе. Во-первых, рекомендации по общей схеме тестирования: 1) отдельные тесты на единицу и интеграцию; 2) использование альтернативных конструкторов для упрощения создания тестовых объектов. Затем рекомендации по использованию теста удваиваются, например, заглушки и макеты: 3) назовите свои заглушки для отладки и ясности; 4) не заглушайте примитивы; 5) слушайте сложность установки теста, даже если это не сразу очевидно; и 6) ограничивать только те вещи, которым вы доверяете.
17. When Rails Is Right
Несколько Destroy All Software скринкастов показали способы «сражаться» с веб-фреймворками, такими как Rails, избегая его примитивов дизайна. Обычно они сосредоточены на использовании служебных объектов вместо контроллеров и моделей. Этот скринкаст демонстрирует рефакторинг, где примитивы Rails действительно обеспечивают лучший дизайн. Мы начинаем с двух контроллеров, реорганизуя их, чтобы переместить поведение. В конце концов, контроллеры только делегируют и переводят на и из HTTP.
Примечание. В методе «Account.create_with_schema» есть ошибка: он должен принимать параметры учетной записи с контроллера. К счастью, это не влияет на содержание скринкаста.
18. A Day in The Life
Как последний скринкаст Destroy All Software (по крайней мере, на данный момент), он странный. Он охватывает несколько скриптов командной строки, которые никогда не появлялись в других скринкастах, а затем показывает, что за последние два года работы по созданию скринкастов и разговоров выглядели с моей точки зрения: инструменты, организация, редактирование и тд. Спасибо всем, кто подписались на протяжении последних двух лет! Это было реально круто.