Скромная дискуссия по мотивам моей вчерашней публикации на тему прогнозирования времени на разработку, в очередной раз пробудила во мне ощущение некоей неправильности на тему использования чисто умозрительного подхода к разбиению истории на задачи. На мой взгляд, когда мы пишем задачи в списке, даже когда мы используем объектную или функциональную терминологию, мы не вполне представляем себе все модули с кодом, которые нам потребуется разработать или доработать.
Тогда мне пришла в голову идея, после разбиения пользовательской истории на задачи, попробовать набросать черновики модульных тестов, для классов или методов, которые я упоминаю в задачах. Мне даже не нужно выдумывать пользовательскую историю, я могу взять одну из моей текущей работы. Например:
Как система, я хочу отправить на проверку KYC сервису персональные данные пользователя
И список задач к ней:
Реализовать получение персональных данных пользователя из локальной базы- Реализовать создание папки в KYC сервисе с указанием в метаданных папки персональных данных пользователя
- Реализовать создание запроса на проверку данных папки в KYC сервисе
- Реализовать сохранение информации о запросе на проверку персональных данных в локальной базе
Если за продолжительность одной итерации команды считать две недели, то один-два дня вполне можно потратить на ее планирование, но не в виде совещания с умозрительными рассуждениями и покером, а в основном в виде обычной программистской деятельности в виде написания тестов в некоем минимальном виде. С последующей оценкой времени на реализацию функциональности уже в полном масштабе.
В первом приближении выглядит как со всех сторон профит. Пишем код и не теряем времени на коллективные рассуждения. И строим оценки на основе хотя бы минимального количества кода, пощупав так сказать требования заказчика руками.
Поскольку для первой задачи из вышеозначенного списка у меня есть уже оттестированная рабочая реализация, то перехожу ко второй задаче и начинаю делать черновик теста для метода, выгружающего данные в KYC сервис:
describe('upload personal info', () => { const HttpFake = require('HttpFake'); const http = new HttpFake(); const store = require('../../src/store'); const handler = require('../../src/kyc/createFolder'); const rules = require('../../src/importRules'); const httpOptions = { hostname: 'http://kycservice', port: 80, path: '/api/folder', body: { meta_data: { firstName: 'Jack', lastName: 'Sparrow', birthDate: '06/01/1740' } }, method: 'POST', headers: { 'Content-Type': 'application/json' } }; const httpResponse = { statusCode: 200, body: { folder_id: '0x382974', meta_data: { firstName: 'Jack', lastName: 'Sparrow', birthDate: '06/01/1740' } }, headers: { 'Content-Type': 'application/json' } }; let context = null, handle = null; beforeEach(() => { context = { http, store, rules }; handle = handler.bind(context, ['folder']); const person = { firstName: 'Jack', lastName: 'Sparrow', birthDate: '06/01/1740' }; store.dispatch({ type: 'PERSON', person }); }); it('should assign store folder state value', () => { http.expect(httpOptions); http.returns(httpResponse); const assert = checkExportResult.bind(context, [done]); store.subscribe(assert); handle(); }); function checkExportResult(args){ const folder = store.getState().folder; if(folder === null) return; expect(folder.folder_id).toEqual('0x382974'); expect(folder.meta_data.firstName).toEqual('Jack'); expect(folder.meta_data.lastName).toEqual('Sparrow'); expect(folder.meta_data.birthDate).toEqual('06/01/1740'); const checkIsCompleted = args[0]; checkIsCompleted(); } });
Модульный тест второй задачи разложился аж в 100 строчек кода, и на его реализацию у меня ушло около часа времени. При этом первые пять строчек на некоторое время погрузили меня в размышления на тему "как бы мне реализовать имитацию отправки http запросов?", пока я не вспомнил что у меня уже есть некая псевдо-http реализация, имитирующая как раз отправку нужных мне POST запросов. Хорошо. Вот у меня есть тест. Стало ли мне понятнее сколько может потребоваться времени на реализацию нужной функциональности?
На самом деле да. Эта задача на мой взгляд очень похожа на задачу с запросом данных из базы, и я уже принял решение что одного рабочего дня мне вполне хватит чтобы реализовать в таком же подходе отправку POST запроса с сохранением результатов в контейнер состояния. А поскольку у меня уже есть успешный опыт с отдельной реализацией правил обработки данных в рамках выполнения запроса, то я решил что реализую новый набор правил, которые я буду использовать при отправке POST запросов.
Две последующие задачи из списка кажутся мне очень похожими, так что писать тесты для них прямо сейчас я не вижу особого смысла, потому что мозг уже принял в качестве оценки:
Реализовать получение персональных данных пользователя из локальной базы- Реализовать создание папки в KYC сервисе с указанием в метаданных папки персональных данных пользователя — 8ч
- Реализовать создание запроса на проверку данных папки в KYC сервисе — 8ч
- Реализовать сохранение информации о запросе на проверку персональных данных в локальной базе — 8ч
Ну и поскольку следующие пользовательские истории в списке у меня из этой же оперы, просто в POST запросах будет не JSON, а бинарные данные, то я автоматически принимаю что могу за двухнедельную итерацию реализовать три пользовательских истории.
