{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## FizzBuzz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 仕様\n", "\n", "+ 3で割り切れる場合はFizzを出力する\n", "+ 5で割り切れる場合はBuzzを出力する\n", "+ 両方で割り切れる場合はFizzBuzzを出力する\n", "+ 上記以外の場合は数字を返す\n", "+ 指定された回数だけ繰り返し実行する\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 設計\n", "#### TODOリスト\n", "+ ~~Fizzを出力できるようにする~~\n", "+ ~~Buzzを出力できるようにする~~\n", "+ ~~FizzBuzzを出力できるようにする~~\n", "+ ~~数字を出力できるようにする~~\n", "+ ~~繰り返し実行できるようにする~~\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "........." ] } ], "source": [ "class FizzBuzz():\n", " @staticmethod\n", " def generate(count):\n", " value = count\n", "\n", " if value % 3 == 0 and value % 5 == 0:\n", " value = 'FizzBuzz'\n", " elif value % 3 == 0:\n", " value = 'Fizz'\n", " elif value % 5 == 0:\n", " value = 'Buzz'\n", "\n", " return value \n", "\n", " @staticmethod\n", " def iterate(count):\n", " array = []\n", "\n", " for n in range(count):\n", " array.append(FizzBuzz.generate(n + 1))\n", "\n", " return array\n", " \n", "import unittest\n", "\n", "\n", "class FizzBuzzTest(unittest.TestCase):\n", " def test_3ならばFizzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(3), 'Fizz')\n", "\n", " def test_6ならばFizzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(6), 'Fizz') \n", "\n", " def test_5ならばBuzzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(5), 'Buzz')\n", "\n", " def test_10ならばBuzzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(10), 'Buzz') \n", "\n", " def test_50ならばBuzzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(5), 'Buzz') \n", "\n", " def test_15ならばFizzBuzzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(15), 'FizzBuzz')\n", "\n", " def test_30ならばFizzBuzzを返す(self):\n", " self.assertEqual(FizzBuzz.generate(30), 'FizzBuzz') \n", "\n", " def test_1ならば1を返す(self):\n", " self.assertEqual(FizzBuzz.generate(1), 1)\n", "\n", " def test_101ならば101を返す(self):\n", " self.assertEqual(FizzBuzz.generate(101), 101) \n", "\n", " def test_5回実行されたならば配列を返す(self):\n", " self.assertEqual(FizzBuzz.iterate(5), [1, 2, 'Fizz', 4, 'Buzz'])\n", "\n", " def test_10回実行されたならば配列を返す(self):\n", " self.assertEqual(FizzBuzz.iterate(10), [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz'])\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['none'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 開発\n", "\n", "### イテレーション1\n", "仕様を満たすアプリケーションを**できるだけ早く試作する**ために**テストファーストプログラミング**を実施する。実施にあたってまず**TODOリスト**を作成する。\n", " \n", "**TODOリスト**を作成したら**インクリメンタルな設計**を実施する。実施するにあたってまず**単一責任の原則**に従い関心事を表すクラスを定義する。ここではFizzBuzzそのものを関心事として扱うことにする。\n", " \n", "**テストファースト**でFizzBuzzとテストの**クラスの定義式**を作成する。\n", " \n", "クラスを定義したので**テストメソッド**を作成に入る。まず**TODOリスト**を元にアウトラインを作成する。\n", " \n", "アウトラインをを作成したら**一歩を示すテスト**に取り掛かる、**TODOリスト**から失敗する**はじめのテスト**を作成する。テストコードは**アサートファースト**でレッドになることを確認したら仮実装でグリーンにする。**一つのプログラムには一つのことをうまくやらせる**ことを心がける。**アサーション**は期待値を先に書く。\n", " \n", "グリーンの状態になったら**仮実装を経て本実装へ**入る。**明白な実装**を行って最初の**TODOリスト**を片付ける。**条件分岐**と**演算子**を使って本実装を行う。**YAGNI**に従い今必要な機能だけを実装する。\n", " \n", "引き続き**TODOリスト**の2つ目に取り掛かる。**はじめのテスト**を失敗させる。失敗することを確認したら**明白な実装**によりテスト結果をグリーンにする。最初のコードに追記するだけでは意図した結果にならなかったので**式**を変更して結果をグリーンにした。**TODOリスト**の2つ目を完了にする。\n", " \n", "続いて、**TODOリスト**の3つ目に着手する。今回は複数の条件なので新たな**演算子**を使って実装する。実装に際してロジックの順番の間違いと判断条件の間違いとコピペによる間違いを犯していたが全てテストで気づくことができた。\n", " \n", "**TODOリスト**の割り算機能の最後のタスクに取り掛かる。今回のテストは前回のテストの派生系なので**三角測量**で実装する。まずは失敗するテストを追加する。**明白な実装**によりテストをグリーンにして**TODOリスト**の割り算機能のタスクを片付ける。テストのアウトラインがなくても意図は読み取れるようになったので**コメント**は削除する。\n", " \n", "続いて、**TODOリスト**の残りの実行機能に取り組む。まず**インクリメンタルな設計**によりクラスのインタフェースを設計する。**一つのプログラムには一つのことをうまくやらせる**ことを意識する。\n", " \n", "実行機能はまだ正しい実装が見えてこないので**仮実装を経て本実装へ**の前に**三角測量**を実施する。**ローカル変数**を初期化して**繰り返し**の制御構文で実行された最後の結果を返す実装をしたがテストにはまだパスしない。テストから**演算子**の間違いを発見しさらに仮実装の間違いがあることが判明したのでテストを修正してグリーンにする。\n", " \n", "仕様を確認したところ間違いがあったので修正してテストも修正してグリーンになることを確認した。また、仕様に明記されていない条件が判明したので**TODOリスト**に追加する。\n", " \n", "最初のイテレーションを完了させるにあたって**ふりかえり**を実施する。\n", "\n", "### ふりかえり\n", "#### Keep\n", " + **一つのプログラムには一つのことをうまくやらせる**基本定理に従い**単一責任の原則**に沿ったクラス設計をを実施した。\n", " + **できるだけ早く試作する**ために**インクリメンタルな設計**を**テストファーストプログラミング**と取り組むための**TODOリスト**を作成した。\n", " + 仕様に明記されていない項目を**TODOリスト**に反映した。\n", " + **TODOリスト**に従い**テストファースト**で**一歩を示すテスト**を作成した\n", " + まず**はじめのテスト**を**アサートファースト**で取り掛かり**ベイビーステップ**ですすめて行った。\n", " + 何を書くべきかわかっているときは、**明白な実装**を行い、わからないときには**仮実装**を行い、まだ正しい実装が見えてこないときには**三角測量**を行いながら**仮実装を経て本実装へ**と進めた。\n", "\n", "#### Problem\n", " + Pythonのモジュール読み込みの仕組みにはまる\n", "\n", "#### Try\n", " + Unittest\bを理解する\n", "\n", "### 参照\n", "+ [Pythonでunittestを実行する(初心者用)](https://qiita.com/takus69/items/cde279266b46daf9972d)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 1 }