Techniques in Program Development
プログラム開発の技術
Test-Driven Development, Version Control, etc
テスト駆動開発・バージョン管理・etc

Synge Todo / 藤堂眞治
Department of Phys., UTokyo / 東京大学大学院理学系研究科

Agenda• Part I: Test-Driven Development / テスト駆動開発• What's TDD？ / テスト駆動開発とは？
• TDD Demonstration / テスト駆動開発の実演• Part II: Version Control / バージョン管理• What's VCS？ / バージョン管理システムとは？
• Branch ＆ Merge / ブランチとマージ• Using GitHub / GitHubの利用• Continuous Integration (CI) / 継続的インテグレーション• Sample Code Repository• https://github.com/wistaria/tdd-tutorial

2

Prerequisites• Prerequisites / 前提とする基礎知識• Basic UNIX shell operations / 基本的なUNIXシェル操作• UNIX入門 https://github.com/cmsi/malive-tutorial/blob/master/

introduction/shell.md• Basic Programming in C++, Python, and/or Julia / C++やPython、Julia

によるプログラミングの基礎

3

Part I: Test-Driven Development / テスト駆動開発

What's TDD？ / テスト駆動開発とは？

What's Test-Driven Development?
• Test-driven development (TDD) / テスト駆動開発• Red: Write a failing automated test before you write any code / コードを書く前に失敗する自動テストコードを必ず書く• Green: Write just enough code to pass the test / テストをパスする最低限のコードを書く• Refactor: Remove duplication / 重複を除去する

https://hashstrix.com/post/what-is-test-driven-development-tdd/

5

Traditional Program Development• Traditional Program Development / 従来型のプログラム開発• Write speci

cations / 仕様書を書く• Write code / コードを書く• Perform tests / テストを行う• Debugging / デバッグする• Write documentation / マニュアルを書く• Release / リリース

• Problems / 問題点• Speci

cations change during the course of development / 開発の途中で仕様が変わる• Can not know if all of the speci

cations have been tested / 仕様の全てがテストできているか分からない• Can not know if bugs still exist / バグが残っているかどうか分からない• Can not know if it's completed / 完成したかどうかが分からない

fi

fi

fi

6

Debugging is twice as hard as writing the code in the rst place.
Therefore, if you write the code as cleverly as possible, you are, byde nition, not smart enough to debug it.
デバッグは、最初の段階でコードを書くより２倍は難しい。ゆえに、可能な限り賢いコー
ドを書いたとしたら、そのコードにバグがあったとき、あなたがそれをデバッグできるほどの賢くないのは明白である

fi

fi— Brian W. Kernighan

Test-Driven Development• TDD =• Technology to develop "clean code that works" effortlessly / 「動作する

きれいなコード」をストレスなしに開発する技術• Advantages of TDD / TDDの利点• Small time/cost to

x bugs / バグを修正するまでの時間・コストが小さい• The tests themselves are the speci

cation / テストそのものが仕様書• No need to worry about if the bug is still there / バグが残っているか心配する必要がない• Can know if it is completed or not / 完成したかどうかがわかる• It feels good to be ”Green” so often. Less stress / 頻繁にGreenになるので気持ちがいい。ストレスが少ない• Can refactor with con

dence / 自信をもってリファクタリングできる• Easier to maintain as there are no duplicates / 重複がないので、メンテナン

スが楽• Clean code is actually faster / きれいなコードは実際速い

fi

fi

fi

8

Writing Comments• Comments in Source Code / ソースコード中のコメントについて• A comment is of zero (or negative) value if it is wrong / たとえコメントを入れても、それが不適切なものであれば価値はゼロ（あるいはマイナス）である (B. W.
Kernighan and P. J. Plauger)• Comments are not running code / 実行されるのはコメントではない• Avoid duplication / 重複を避ける• Let the code speak for itself / コード自身に語らせる• How to write comments / コメントの書き方• Write "How" in code / コードには「How」• Write "What" in tests / テストコードには「What」• Write "Why" in commit logs / コミットログには「Why」• Write ”Why not" in code comments / コードコメントには「Why not」

9

Tools for TDD• Tools for TDD / テスト駆動開発に必要なツール類• Text editor / テキストエディタ• Visual Studio Code, Vim, Emacs, nano, Mousepad...
• Programming language / プログラミング言語• C++ compiler, Python interpreter, Julia interpreter / C++コンパイラ,

Pythonインタプリタ, Juliaインタプリタ• Build tools / ビルドツール• Make , AutoTools, CMake• Test framework / テストフレームワーク• C++: Google Test, Boost.Test, Catch2• Python: DocTest, UnitTest, pytest• Julia: @test, @testset (built-in macros / 組み込みマクロ)• Version control system (VCS) / バージョン管理システム• Continuous integration (CI) / 継続的インテグレーション• Subversion, Git, GitLab, GitHub, Jenkins, Travis CI

10

Make & CMake• Make (1976〜！）• Automates a series of tasks based on dependencies / 依存関係に基づき、一連の作業を自動化• Describe dependencies and work procedures in the Makele / 依存関係や作業手順はMake leに記述する• UNIX/Linux standard tool / UNIX/Linux標準ツール• CMake (1999〜) https://cmake.org/• Utility that generates a Makele / Make leを生成してくれるユーティリティ• Settings are written in CMakeLists.txt / 設定はCMakeLists.txtに記述する• Automatic detection ofle dependencies / ファイルの依存関係の自動検出• Automatic detection of various external libraries / さまざまな外部ライブラ

リの自動検出• test execution function / テスト実行機能 (ctest)

CMakeLists.txt

Make lecmake

Executables
make

fi

fi

fi

fi

fi

fi

11

Tools Installation Example• Homebrew on macOS: https://utphys-comp.github.io/homebrew$ xcode-select --install$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/
install/HEAD/install.sh)"# for zsh on Apple silicon (M1/M2)$ echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> $HOME/.zpro le# for bash on Apple silicon (M1/M2)$ echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> $HOME/.bash_pro le$ brew install cmake• Debian/Ubuntu Linux$ sudo apt-get install -y build-essential python3-dev cmake git• on Windows• WSL2: https://utphys-comp.github.io/wsl2• MateriApps LIVE!: VirtualBox version / Docker version

fi

fi

12

TDD Work ow• Red• Write a failing automated test before you write any code / コードを書く

前に失敗する自動テストコードを必ず書く• git fetch → git merge → git checkout• vim → cmake → make → ｃtest• Green• Write just enough code to pass the test / テストをパスする最低限のコードを書く• [vim → cmake → make → ｃtest ...] → git add → git commit ...
• git checkout → git merge → git push
• Refactor• Remove duplication / 重複を除去する• git checkout• [[vim → cmake → make → ｃtest ...] → git add → git commit ...]• git checkout → git merge → git pushfl13

Don't Repeat Yourself (DRY)• DRY principle / DRY原則• Fundamental principle for creating simpler, more maintainable,higher-quality programs / シンプルで、品質が高く、保守もしやすいプログラムを作るための最も基本的な指針• Don't Repeat Yourself / 繰り返しを避ける• Duplication is waste / 重複は無駄• Repetition in process calls for automation / 作業の重複は自動化で避ける• Repetition in logic calls for abstraction / ロジックの重複は抽象化で避ける• DRY ⇔ WET• "write everything twice"• "write every time"• "we enjoy typing"• "waste everyone's time"14

Measuring programming progress by lines of code is like measuring
aircraft building progress by weight.
プログラミングの進展をコードの行数で測るのは、飛行機建造の進展を重量で測るようなものだ— Bill Gates

What Are Good Tests?
• F.I.R.S.T. principle• Fast / 速い
• Independent / 互いに独立している• Repeatable / 再現可能性• Self-Validating / 自律的検証? → 自動化されている？
• Timely / 適切なタイミング• A-TRIP principle• Automated / 自動化されている• Thorough / 徹底的• Repeatable / 再現可能性• Independent / 互いに独立している• Professional / プロの？

16

Part I: Test-Driven Development / テスト駆動開発

TDD Demonstration / テスト駆動開発の実演

TDD Demonstration• TDD Demonstration / テスト駆動開発実演• Fibonacci sequence / Fibonacci数列• f(0) = 0, f(1) = 1, f(n) = f(n − 1) + f(n − 2)
• 0, 1, 1, 2, 3, 5, 8, 13, ...

• TDD iterations• 1st iteration: cmake && make• 2nd iteration: cmake && make && ctest• 3rd iteration:

bonacci(0) == 0

• 4th iteration:

bonacci(1) == 1

• 5th iteration:

bonacci(2) == 1 &&• 6th iteration:

bonacci(10) == 55• 7th iteration:

bonacci(-1) == 1 &&bonacci(3) == 2bonacci(-2) == -1• 8th iteration: speed up• 9th iteration:

bonacci(100) == 354224848179261915075• 10th iteration: Lucas series

fi

fi

fi

fi

fi

fi

fi

fi

18

• Test to pass: cmake && make• Create source & build directories / ソース・ビルドディレクトリの作成•

bonacci: source directory / ソースコードを作成するディレクトリ

•bonacci/build: build directory / ソースコードをコンパイルするディレクトリ

• Pass the location of source directory (directory with CMakeLists.txt) to

cmake / cmakeの引数にソースディレクトリ(CMakeLists.txtのあるディレクトリ)を指定$ mkdir bonacci$ mkdir bonacci/build$ cd bonacci/build$ cmake ..
CMake Error: The source directory ".../ bonacci" does not appear to contain
CMakeLists.txt.

fi

fi

fi

19
fi

fi

fi

TDD Demonstration: 1st iteration （C++)

• Test to pass: cmake && make• Create CMakeLists.txt

bonacci/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project( bonacci CXX)
set(CMAKE_CXX_STANDARD 14)
add_executable( bonacci bonacci.cpp)
target_compile_options( bonacci PRIVATE -Wall -Wextra)$ cd bonacci/build$ cmake ..
CMake Error at CMakeLists.txt:5 (add_executable):
Cannot nd source le: ...

fi

fi

fi

fi

fi

fi

20
fi

fi

TDD Demonstration: 1st iteration （C++)

• Test to pass: cmake && make• Create

bonacci.cpp

bonacci/ bonacci.cpp#include <iostream>
int main() {std::cout << "hello, world" << std::endl;}$ cd bonacci/build$ cmake ..
-- Build les have been written to: .../ bonacci/build$ make$ ./ bonacci
hello, world

fi

fi

fi

fi

fi

21
fi

fi

TDD Demonstration: 1st iteration （C++)

• Test to pass: cmake && make• Create CMakeLists.txt

bonacci/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project( bonacci NONE)
nd_package(Python)
con gure_ le( bonacci bonacci FILE_PERMISSIONS OWNER_READOWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTEWORLD_READ WORLD_EXECUTE)$ cd bonacci/build$ cmake ..
CMake Error at CMakeLists.txt:5 (con gure_ le):con gure_ le Problem con guring le

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

22
fi

fi

fi

TDD Demonstration: 1st iter. （Python)• Test to pass: cmake && make• Create

bonacci

bonacci/ bonacci#!@Python_EXECUTABLE@
print("hello, world")$ cd bonacci/build$ cmake ..
-- Build les have been written to: .../ bonacci/build$ make$ ./ bonacci
hello, world

fi

fi

fi

fi

fi

23
fi

fi

TDD Demonstration: 1st iter. （Python)• Test to pass: cmake && make• Create CMakeLists.txt

bonacci/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project( bonacci NONE)
nd_program(Julia_EXECUTABLE julia)
message(STATUS "Found Julia executable: ${Julia_EXECUTABLE}")con gure_ le( bonacci bonacci FILE_PERMISSIONS OWNER_READOWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTEWORLD_READ WORLD_EXECUTE)$ cd bonacci/build$ cmake ..
CMake Error at CMakeLists.txt:5 (con gure_ le):con gure_ le Problem con guring le

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

24
fi

fi

fi

TDD Demonstration: 1st iter. （Julia)• Test to pass: cmake && make• Create

bonacci

bonacci/ bonacci#!@Julia_EXECUTABLE@
println("hello, world")$ cd bonacci/build$ cmake ..
-- Build les have been written to: .../ bonacci/build$ make$ ./ bonacci
hello, world

fi

fi

fi

fi

fi

25
fi

fi

TDD Demonstration: 1st iter. （Julia)

Some Good Practices for C++/Python• C++• Specify options to make the compiler issue maximum warning

messages / コンパイラが最大限の警告メッセージを出すようにオプションを指定する• for GCC: "-Wall -Wextra"• Fix code until all warnings go away / 警告がなくなるまで修正する• Python• Do not use version 2, use version 3 / version 2ではなく、version 3を使う
• Install additional modules in the user area, not the system area / 追加

モジュールはシステム領域ではなくユーザ領域にインストール• create dedicated environment / 専用の環境を作る: venv, conda• for venv
• python3 -m venv venv
• source venv/bin/activate• pip3 install pytest• Common• Always follow a "coding standard" / "コーディング規格"に常に従う
26

• Test to pass: cmake && make && ctest• Modify CMakeLists.txt

bonacci/CMakeLists.txt...
include(FetchContent)
FetchContent_Declare(catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.1.0)
FetchContent_MakeAvailable(Catch2)
enable_testing()
add_executable( bonacci bonacci.cpp)
target_compile_options( bonacci PRIVATE -Wall -Wextra)
add_executable(test_ bonacci test_ bonacci.cpp)
target_compile_options(test_ bonacci PRIVATE -Wall -Wextra)
target_link_libraries(test_ bonacci Catch2::Catch2WithMain)
add_test(test_ bonacci test_ bonacci)

fi

fi

fi

fi

fi

fi

fi

fi

27
fi

fi

TDD Demonstration: 2nd iter. （C++)

• Test to pass: cmake && make && ctest• Create test_

bonacci.cpp

bonacci/test_ bonacci.cpp#include <catch2/catch_test_macros.hpp>
TEST_CASE(" bonacci", "test") {REQUIRE(2 * 2 == 4);}$ cd bonacci/build$ cmake ..
-- Build les have been written to: .../ bonacci/build$ make...
$ ctest
Test project .../ bonacci/build
Start 1: test_ bonacci
1/1 Test #1: test_ bonacci ................... Passed 0.02 sec
100% tests passed, 0 tests failed out of 1

fi

fi

fi

fi

fi

fi

fi

fi

28
fi

fi

TDD Demonstration: 2nd iter. （C++)

• Test to pass: cmake && make && ctest• Modify CMakeLists.txt

bonacci/CMakeLists.txt...
execute_process(COMMAND ${Python_EXECUTABLE} -m venv${CMAKE_BINARY_DIR}/venv)
set(ENV{VIRTUAL_ENV} ${CMAKE_BINARY_DIR}/venv)
set(Python_FIND_VIRTUALENV FIRST)
unset(Python_EXECUTABLE)
nd_package(Python)
execute_process(COMMAND ${Python_EXECUTABLE} -m pip install--upgrade pip)
execute_process(COMMAND ${Python_EXECUTABLE} -m pip install -r${CMAKE_SOURCE_DIR}/requirements.txt)
enable_testing()
con gure_ le( bonacci

bonacci ...)

fi

fi

fi

fi

fi

add_test(test_ bonacci ${Python_EXECUTABLE} -m pytest${CMAKE_CURRENT_SOURCE_DIR}/test_ bonacci.py)
fi

fi

fi

TDD Demonstration: 2nd iter. （Python)29• Test to pass: cmake && make && ctest• Create requirements.txt & test_

bonacci.py

bonacci/requirements.txt
pytestbonacci/test_ bonacci.py
def test_ bonacci():
assert 2 * 2 == 4
$ cd bonacci/build$ cmake ..
-- Build les have been written to: .../ bonacci/build$ make...
$ ctest
Test project .../ bonacci/build
Start 1: test_ bonacci
1/1 Test #1: test_ bonacci ................... Passed 0.02 sec
100% tests passed, 0 tests failed out of 1

fi

fi

fi

fi

fi

fi

fi

fi

30
fi

fi

fi

TDD Demonstration: 2nd iter. （Python)• Test to pass: cmake && make && ctest• Modify CMakeLists.txt

bonacci/CMakeLists.txt...
nd_program(Julia_EXECUTABLE julia)
message(STATUS "Found Julia executable: ${Julia_EXECUTABLE}")
enable_testing()
con gure_ le( bonacci bonacci FILE_PERMISSIONS OWNER_READOWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTEWORLD_READ WORLD_EXECUTE)
add_test(test_ bonacci ${Julia_EXECUTABLE}${CMAKE_CURRENT_SOURCE_DIR}/test_ bonacci.jl)

fi

fi

fi

fi

fi

31
fi

fi

fi

TDD Demonstration: 2nd iter. （Julia)• Test to pass: cmake && make && ctest• Create test_

bonacci.jl

bonacci/test_ bonacci.jl
using Test
@testset " bonacci" begin@test 2 * 2 == 4end
$ cd bonacci/build$ cmake ..
-- Build les have been written to: .../ bonacci/build$ make...
$ ctest
Test project .../ bonacci/build
Start 1: test_ bonacci
1/1 Test #1: test_ bonacci ................... Passed 0.22 sec
100% tests passed, 0 tests failed out of 1

fi

fi

fi

fi

fi

fi

fi

fi

32
fi

fi

TDD Demonstration: 2nd iter. （Julia)• Test to pass:• Modify test_

bonacci(0) == 0
bonacci.cpp and create

bonacci.hpp

bonacci/test_ bonacci.cpp#include <catch2/catch_test_macros.hpp>#include " bonacci.hpp"
TEST_CASE(" bonacci", "test") {REQUIRE( bonacci(0) == 0);}

bonacci/ bonacci.hpp#pragma once
int bonacci(int) {return 0;
}

fi

fi

fi

fi

fi

fi

fi

fi

33
fi

fi

fi

TDD Demonstration: 3rd iter. （C++)

• Test to pass:• Modify test_

bonacci(0) == 0
bonacci.py and create

bonacci.py

bonacci/test_ bonacci.py
frombonacci importbonacci

def test_ bonacci():
assert bonacci(0) == 0

bonacci/ bonacci.py
def bonacci(n):return 0

fi

fi

fi

fi

fi

fi

fi

fi

fi

34
fi

fi

fi

TDD Demonstration: 3rd iter. （Python)• Test to pass:bonacci(0) == 0

• Modify test_

bonacci.jl and create

bonacci.jl

bonacci/test_ bonacci.jl
using Test
include(" bonacci.jl")@testset " bonacci" begin@test bonacci(0) == 0
end

bonacci/ bonacci.jlfunction0end

bonacci(n)

fi

fi

fi

fi

fi

fi

fi

fi

35
fi

fi

fi

TDD Demonstration: 3rd iter. （Julia)• Test to pass:• Modify test_

bonacci(1) == 1
bonacci.cpp andbonacci.hpp

bonacci/test_ bonacci.cpp...
REQUIRE( bonacci(0) == 0);
REQUIRE( bonacci(1) == 1);...

bonacci/ bonacci.hpp...
int bonacci(int n) {if (n == 0)
return 0;
return 1;
}

fi

fi

fi

fi

fi

fi

fi

36
fi

fi

fi

TDD Demonstration: 4th iter. （C++)

• Test to pass:• Modify test_

bonacci(1) == 1
bonacci.py andbonacci.py

bonacci/test_ bonacci.py...
def test_ bonacci():
assert bonacci(0) == 0
assert bonacci(1) == 1

bonacci/ bonacci.py
def bonacci(n):if n == 0:
return 0
return 1

fi

fi

fi

fi

fi

fi

fi

fi

37
fi

fi

fi

TDD Demonstration: 4th iter. （Python)• Test to pass:• Modify test_

bonacci(1) == 1
bonacci.jl andbonacci.jl

bonacci/test_ bonacci.jl...
@testset " bonacci" begin@test bonacci(0) == 0
@test bonacci(1) == 1
end

bonacci/ bonacci.jlfunction bonacci(n)if n == 0
0
else
1
end
end

fi

fi

fi

fi

fi

fi

fi

fi

38
fi

fi

fi

TDD Demonstration: 4th iter. （Julia)• Test to pass:• Modify test_

bonacci(2) == 1 &&bonacci.cpp andbonacci(3) == 2bonacci.hpp

bonacci/test_ bonacci.cpp...
TEST_CASE(" bonacci", "test") {std::vector<std::tuple<int, int>> cases {{0, 0}, {1, 1}, {2, 1}, {3, 2}};for (auto c : cases) {REQUIRE( bonacci(std::get<0>(c)) == std::get<1>(c));}}

bonacci/ bonacci.hpp

fi

39
fi

fi

fi

fi

fi

fi

fi

...
int bonacci(int n) {if (n == 0)
return 0;
if (n <= 2)return 1;
return 2;
}
fi

fi

fi

TDD Demonstration: 5th iter. （C++)

• Test to pass:• Modify test_

bonacci(2) == 1 &&bonacci.py andbonacci(3) == 2bonacci.py

bonacci/test_ bonacci.py...
@pytest.mark.parametrize("n, v", [[0, 0], [1, 1], [2, 1], [3, 2]])
def test_ bonacci(n, v):
assert bonacci(n) == v

bonacci/ bonacci.py
def bonacci(n):if n == 0:
return 0
if n <= 2:return 1
return 2

fi

fi

fi

fi

fi

fi

fi

fi

40
fi

fi

fi

TDD Demonstration: 5th iter. （Python)• Test to pass:• Modify test_

bonacci(2) == 1 &&bonacci.jl andbonacci(3) == 2bonacci.jl

bonacci/test_ bonacci.jl...
@testset " bonacci" begin
let testcases = ((0, 0), (1, 1), (2, 1), (3, 2))
for (n, v) in testcases@test bonacci(n) == v
end
end
end

bonacci/ bonacci.jl...
elseif n <= 2
1
else
2
...

fi

fi

fi

fi

fi

fi

fi

41
fi

fi

fi

TDD Demonstration: 5th iter. （Julia)• Test to pass:• Modify test_

bonacci(10) == 55
bonacci.cpp andbonacci.hpp

bonacci/test_ bonacci.cpp...
std::vector<std::tuple<int, int>> cases {{0, 0}, {1, 1}, {2, 1}, {3, 2},{10, 55}};...

bonacci/ bonacci.hpp...
int bonacci(int n) {if (n == 0)
return 0;
if (n == 1)
return 1;
return bonacci(n-1) +}bonacci(n-2);

fi

fi

fi

fi

fi

fi

fi

42
fi

fi

fi

TDD Demonstration: 6th iter. （C++)

• Update “bonacci" driver program to use ourbonacci function

bonacci/ bonacci.cpp#include <iostream>#include <string>#include " bonacci.hpp"
int main(int argc, char** argv) {if (argc != 2) {std::cerr << "Error: " << argv[0] << " N" << std::endl;
return 1;}
std::cout << bonacci(std::atoi(argv[1])) << std::endl;
return 0;
}

fi

fi

fi

fi

43
fi

fi

TDD Demonstration: 6th iter. （C++)

• Test to pass:• Modify test_

bonacci(10) == 55
bonacci.py andbonacci.py

bonacci/test_ bonacci.py...
@pytest.mark.parametrize("n, v", [[0, 0], [1, 1], [2, 1], [3, 2], [10, 55]])
def test_ bonacci(n, v):
assert bonacci(n) == v

bonacci/ bonacci.py
def bonacci(n):if n == 0:
return 0
if n == 1:
return 1
return bonacci(n-1) +bonacci(n-2)

fi

fi

fi

fi

fi

fi

fi

fi

fi

44
fi

fi

fi

TDD Demonstration: 6th iter. （Python)• Update “bonacci" driver program to use ourbonacci function

bonacci/ bonacci#!@Python_EXECUTABLE@
import sys
sys.path.append('@CMAKE_SOURCE_DIR@')
from bonacci import bonacci
assert len(sys.argv) == 2, sys.argv[0] + " N"print( bonacci(int(sys.argv[1])))

fi

fi

fi

fi

fi

45
fi

fi

TDD Demonstration: 6th iter. （Python)• Test to pass:• Modify test_

bonacci(10) == 55
bonacci.jl andbonacci.jl

bonacci/test_ bonacci.jl...
@testset " bonacci" begin
let testcases = ((0, 0), (1, 1), (2, 1), (3, 2), (10, 55))...
end

bonacci/ bonacci.jlfunction bonacci(n)if n == 00elseif n == 1
1
else
bonacci(n - 1) +end
end

bonacci(n - 2)

fi

fi

fi

fi

fi

fi

fi

fi

46
fi

fi

fi

TDD Demonstration: 6th iter. （Julia)• Update “bonacci" driver program to use ourbonacci function

bonacci/ bonacci#!@Julia_EXECUTABLE@
include("@CMAKE_SOURCE_DIR@/ bonacci.jl")@assert size(ARGS, 1) == 1
println( bonacci(parse(Int, ARGS[1])))

fi

fi

fi

fi

47
fi

fi

TDD Demonstration: 6th iter. （Julia)• Test to pass:• Modify test_

bonacci(-1) == 1 &&bonacci.cpp andbonacci(-2) == -1

bonacci.hpp

bonacci/test_ bonacci.cpp...
std::vector<std::tuple<int, int>> cases {{-2, -1}, {-1, 1}, {0, 0}, {1, 1}, {2, 1},{3, 2}, {10, 55}};...

bonacci/ bonacci.hpp...
int bonacci(int n) {if (n < 0)return bonacci(n+2) - bonacci(n+1);
if (n == 0)
return 0;
if (n == 1)
return 1;
return bonacci(n-1) + bonacci(n-2);
}

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

48
fi

fi

fi

TDD Demonstration: 7th iter. （C++)

• Test to pass:• Modify test_

bonacci(-1) == 1 &&bonacci.py andbonacci(-2) == -1

bonacci.py

bonacci/test_ bonacci.py...
@pytest.mark.parametrize("n, v", [[-2, -1], [-1, 1], [0, 0], [1, 1], [2, 1], [3, 2],[10, 55]])...

bonacci/ bonacci.py
def bonacci(n):if n < 0:return bonacci(n+2) - bonacci(n+1)
if n == 0:
return 0
if n == 1:
return 1
return bonacci(n-1) + bonacci(n-2)

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

49
fi

fi

fi

TDD Demonstration: 7th iter. （Python)• Test to pass:• Modify test_

bonacci(-1) == 1 &&bonacci.jl andbonacci(-2) == -1

bonacci.jl

bonacci/test_ bonacci.jl...
let testcases = ((-2, -1), (-1, 1), (0, 0), (1, 1), (2, 1), (3, 2), (10, 55))...

bonacci/ bonacci.jlfunction bonacci(n)if n < 0bonacci(n + 2) - bonacci(n + 1)
elseif n == 00elseif n == 1
1
else
bonacci(n - 1) + bonacci(n - 2)
end
end
fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

50
fi

fi

fi

TDD Demonstration: 7th iter. （Julia)

• Refactoring for speed up for large N (〜45)• Modify

bonacci.hpp

bonacci/ bonacci.hpp

fi

fi

int bonacci(int n) {int v0 = 0;
int v1 = 1;
if (n < 0) {for (int i = -1; i >= n; --i) {auto v0_old = v0; v0 = v1 - v0_old; v1 = v0_old;}
return v0;}
if (n == 0)
return v0;
if (n == 1)
return v1;
for (int i = 2; i <= n; ++i) {auto v1_old = v1; v1 = v0 + v1_old; v0 = v1_old;}
return v1;
}
fi

fi

TDD Demonstration: 8th iter. （C++)

51

• Refactoring for speed up for large N (〜45)• Modify

bonacci.py

bonacci/ bonacci.py
def bonacci(n):v0 = 0v1 = 1
if n < 0:for _ in range(-1, n-1, -1):
v0, v1 = (v1 - v0, v0)
return v0
if n == 0:
return v0
if n == 1:
return v1
for _ in range(2, n+1):
v1, v0 = (v0 + v1, v1)
return v1

fi

fi

52
fi

fi

TDD Demonstration: 8th iter. （Python)• Refactoring for speed up for large N (〜45)• Modify

bonacci.jl

bonacci/ bonacci.jlfi

fifunction bonacci(n)v0 = 0v1 = 1
if n < 0for _ in -1:-1:n(v0, v1) = (v1 - v0, v0)
endv0
elseif n == 0v0elseif n == 1
v1
else
for _ in 2:n(v1, v0) = (v0 + v1, v1)
end
v1
...
fi

fi

TDD Demonstration: 8th iter. （Julia)

53• Test to pass:bonacci(100) == 354224848179261915075• Modify CMakeLists.txt to use Boost.multiprecision library

bonacci/CMakeLists.txt...
nd_package(Boost REQUIRED)
include(FetchContent)...
enable_testing()
add_executable( bonacci bonacci.cpp)
target_compile_options( bonacci PRIVATE -Wall -Wextra)
target_link_libraries( bonacci PRIVATE Boost::boost)
add_executable(test_ bonacci test_ bonacci.cpp)
target_compile_options(test_ bonacci PRIVATE -Wall -Wextra)
target_link_libraries(test_ bonacci PRIVATE Boost::boost
Catch2::Catch2WithMain)
add_test(test_ bonacci test_ bonacci)

fi

fi

fi

fi

fi

fi

fi

fi

fi

fi

54
fi

fi

fi

TDD Demonstration: 9th iter. （C++)

• Test to pass:• Modify test_

bonacci(100) == 354224848179261915075
bonacci.cpp

bonacci/test_ bonacci.cpp...
std::vector<std::tuple<int, mp::cpp_int>> cases {{-2, -1}, {-1, 1}, {0, 0},{1, 1}, {2, 1}, {3, 2}, {10, 55}, {40, 102334155},{100, mp::cpp_int("354224848179261915075")}};for (auto c : cases) {REQUIRE( bonacci(std::get<0>(c)) == std::get<1>(c));
if (std::get<0>(c) > 0)
REQUIRE( bonacci(std::get<0>(c)) > 0);
}
...

fi

fi

fi

fi

55
fi

fi

TDD Demonstration: 9th iter. （C++)

• Test to pass:• Modify

bonacci(100) == 354224848179261915075

bonacci.hpp

bonacci/ bonacci.hpp#pragma once#include <boost/multiprecision/cpp_int.hpp>
namespace mp = boost::multiprecision;
mp::cpp_int bonacci(int n) {mp::cpp_int v0 = 0;
mp::cpp_int v1 = 1;
if (n < 0) {
...

fi

fi

fi

56
fi

fi

TDD Demonstration: 9th iter. （C++)

• Test to pass:• Modify test_

bonacci(100) == 354224848179261915075
bonacci.py and it just works as a charm

bonacci/test_ bonacci.py...
cases = [[-2, -1], [-1, 1], [0, 0], [1, 1], [2, 1], [3, 2], [10, 55],
[40, 102334155], [100, 354224848179261915075]]
...

fi

fi

57
fi

fi

TDD Demonstration: 9th iter. （Python)• Test to pass:• Modify test_

bonacci(100) == 354224848179261915075
bonacci.jl andbonacci.jl

bonacci/test_ bonacci.jl...
let testcases = ((-2, -1), (-1, 1), (0, 0), (1, 1), (2, 1), (3, 2), (10, 55),
(40, 102334155), (100, 354224848179261915075))...

bonacci/ bonacci.jlfunction bonacci(n)v0 = big(0)v1 = big(1)if n < 0
...

fi

fi

fi

fi

fi

58
fi

fi

fi

TDD Demonstration: 9th iter. （Julia)• Test to pass: lucas(0) == 2 && lucas(1) == 1 && ...
• Create test_lucas.cpp and lucas.hpp, and modify CMakeLists.txt

bonacci/CMakeLists.txt...
foreach(name bonacci lucas)
add_executable(${name} ${name}.cpp)
target_compile_options(${name} PRIVATE -Wall -Wextra)
target_link_libraries(${name} PRIVATE Boost::boost)
add_executable(test_${name} test_${name}.cpp)
target_compile_options(test_${name} PRIVATE -Wall -Wextra)
target_link_libraries(test_${name} PRIVATE Boost::boost
Catch2::Catch2WithMain)
add_test(test_${name} test_${name})
endforeach(name)

59
fi

fi

TDD Demonstration: 10th iter. （C++)

• Test to pass: lucas(0) == 2 && lucas(1) == 1 && ...
• Refactor

bonacci.hpp and lucas.hpp by creating recursion.hpp

bonacci/ bonacci.hpp...
#include "recursion.hpp"
mp::cpp_int bonacci(int n) {return recursion(0, 1, n);}bonacci/recursion.hpp...
mp::cpp_int recursion(mp::cpp_int v0, mp::cpp_int v1, int n) {
...

fi

fi

60
fi

fi

fi

TDD Demonstration: 10th iter. （C++)

• Test to pass: lucas(0) == 2 && lucas(1) == 1 && ...
• Create test_lucas.py and lucas.py, and modify CMakeLists.txt

bonacci/CMakeLists.txt...
foreach(name bonacci lucas)
con gure_ le(${name} ${name} FILE_PERMISSIONS OWNER_READOWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTEWORLD_READ WORLD_EXECUTE)
add_test(test_${name} ${Python_EXECUTABLE} -m pytest${CMAKE_CURRENT_SOURCE_DIR}/test_${name}.py)
endforeach(name)

fi

fi

61
fi

fi

TDD Demonstration: 10th iter. （Python)• Test to pass: lucas(0) == 2 && lucas(1) == 1 && ...
• Refactor

bonacci.py and lucas.py by creating recursion.py

bonacci/ bonacci.py
from recursive import recursive
def bonacci(n):return recursive(0, 1, n)

bonacci/recursion.py...
def recursion(v0, v1, n):
...

fi

fi

62
fi

fi

fi

TDD Demonstration: 10th iter. （Python)• Test to pass: lucas(0) == 2 && lucas(1) == 1 && ...
• Create test_lucas.jl and lucas.jl, and modify CMakeLists.txt

bonacci/CMakeLists.txt...
foreach(name bonacci lucas)
con gure_ le(${name} ${name} FILE_PERMISSIONS OWNER_READOWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTEWORLD_READ WORLD_EXECUTE)
add_test(test_${name} ${Julia_EXECUTABLE}${CMAKE_CURRENT_SOURCE_DIR}/test_${name}.jl)
endforeach(name)

fi

fi

63
fi

fi

TDD Demonstration: 10th iter. （Julia)• Test to pass: lucas(0) == 2 && lucas(1) == 1 && ...
• Refactor

bonacci.jl and lucas.jl by creating recursion.jl

bonacci/ bonacci.jl
include("recursion.jl")function bonacci(n)recursion(big(0), big(1), n)end

bonacci/recursion.jlfunction recursion(v0, v1, n)
...

fi

fi

64
fi

fi

fi

TDD Demonstration: 10th iter. （Julia)

Good Practices in TDD• Keep iterations as short as possible / 各イテレーションをできるだけ小さくする• 10 min to several hours / 10分〜数時間• Always be Green at the end of the day / 1日の終わりには必ずGreenに• Review the test if the iteration seems to take too long / 時間がかかりすぎる

ようであればテストを見直す• Move the current test to the To-Do list and consider a smaller test /今のテストはTo-Doリストに移し、もう少し小さなテストを考える• Focus on making the Red in front of you Green, even if you want toxsomething else while working / 作業中に別のところを修正したくなっても、目の前のRedをGreenにすることに集中する• Write down the potential improvement on your To-Do list and start

writing a test for it later / 修正候補はTo-Doリストに書いておいて、あとでそのテストを書くところから始める

fi

65

Part II: Version Control / バージョン管理

What's VCS？ / バージョン管理システムとは？

Traditional "File Management"• Traditional "File Management" / 従来の「ファイル管理」• Based onle/directory name / ファイル名・ディレクトリ名による管理• date, person name, version number, etc. / 日付、人名、バージョン番号など• e.g.) main_v1.0.cpp, main_v1.0_todo-3.cpp, main_v1.0.2_synge.cpp• Recorded by handwritten log

le / 手書きのログファイルによる記録• Problems / 問題点• Forget to keep records, record mistakes, incomplete records / 記録を付け忘れる、記録を間違う、不完全な記録• Different people have different naming conventions / 人により命名規則がばらばら• Copying between computers makes it dif

cult to know which one
was modi ed and which one is new / コンピュータ間でコピーを繰り返すと、どれを修正したか、どれが新しいか分からなくなる• Another person would make independent modi

cations based on thesame version / 同じバージョンを元に、別の人が独立に修正を行ってしまう• version branching / バージョンの分岐

fi

fi

fi

fi

fi

67

A Common Example

25/45

ƾǴǄǖǞȢȓȽȺȸȽȃȶ1)ƘĖǌǔȉȽțǹȏȢȉȺǦ

ȉȽț

ȏȢȉȺ

ȉȽț
2)MǃǞǃǗǔǡǛŔKǌǚ*ïǎǵ3)ȏȢȉȺǛŕ ƹAǡ*ïǹǎǵȉȽțA4)*ïǌǔȉȽțǹȏȢȉȺǦ

ȉȽțB

ȉȽțB
ƾǗƹȉȽțAǹÔǅǌǖǯǗǔȾ

University of Tokyo

68

What's Version Control System (VCS)?
• System for managing all

le histories in a database (repository) / ファイルの履歴をデータベース(リポジトリ)で一括管理するシステム• Save all revision history (diffs) / 全ての修正履歴(差分)を保存• Unique version number (commit ID) for each update / 更新毎に一意なバージョン番号(コミットID)を付与• Can make comparison between any versions / 任意のバージョン間の比較が可能• Support for working in team and distributed environments / チーム・分散環

境での作業をサポート• Share repository over Internet / インターネット経由でリポジトリを共有• Detect and resolve collisions when updated by multiple people/

multiple locations simultaneously / 複数人で/複数場所から同時に更新した場合に衝突を検知・解決• Branch, merge, and tag management / ブランチ・マージ・タグの管理fi69ȡȽȎȳȺĳċǌǚƿǵv`With Version
Control System
ȸȽȃȶ

ȏȢȉȺ

ȵȪȎȚȵ
1)ƘĖǌǔȉȽțǹȵȪȎȚȵǦ

26/45

2)ȵȪȎȚȵǃǳȏȢȉȺǦȕȀȖȆǼǿȚ

ȉȽț

ȉȽț

5)ȏȢȉȺǡ*ïǹ§ǶǚAǡ*ïȉȽț3)MǃǞǃǗǔǡǛŔKǌǚ*ïǎǵ6)*ïǹȉȬȖȚǌǲǀǜǌǚƹŗĬǟôǙǆ

ȉȽțB

ŗĬ

ȉȽțA

4)*ïǹȉȬȖȚȉȽțA7)ȏȢȉȺcǈǡ*ïǜÊǌƿ*ïǹŀ` (ȫȽȎ)

ȉȽțCUniversity of Tokyo70

What's Repository• Repository / リポジトリ• Database that manages all history (diffs) of

les / ファイルの全ての履歴(差分)を管理するデータベース• Interaction with repository / リポジトリとのやりとり• checkout / チェックアウト• Retrieve the latest (or a specied) version ofles / 最新版(あるいは指定したバージョン)のファイルを取り出す• commit / コミット
• Registerle changes / ファイルの変更をリポジトリに登録する• Go one version further / バージョンが一つ進む

repository
C1

repository
C2

C3

C1

checkout

C3

C4

commit

files

files

fi

working directoryfi

fi

working directory
fi

C2

71

Disadvantages of VCS• Disadvantages and troublesome points of VCS / バージョン管理システムの欠点・面倒な点• Must be updated to the latest state before modi

cation / 修正前に最新の状態にアッートしなけれ ならない
⇒ Becomes a habit / 習慣になります• All changes must be "committed" / 全ての修正点を「コミット」しなけれならない⇒ Becomes a habit / 習慣になります• Con

icts must be dealt with when they occur / コンフリクトへの対応が面倒⇒ Horrible if xed without realizing it / 気 か に修正してしまうほう 怖い• Server setup is cumbersome / サーのセットアッ面倒⇒ GitHub, GitLab, etc are available / GitHub, GitLabなどが使えます

•

が

ば

fi

が

ず

プ

づ

バ

ば

fi

デ

プ

fl

72

Advantages of VCS• Advantages of Using VCS / バージョン管理システムを使う利点• All records are kept automatically / 全ての記録が自動的に残る• No need to be afraid of bold changes / 大胆な変更を恐れる必要がなくなる• No need to comment out and save old code / 古いコードをコメントアウトしてとっておく必要なし• No more stress of maintaining

le history / ファイルの履歴管理というストレスから開放• Using VCS more than doubles your work ef

ciency /ー ョン管理システム

を使うと作業効率 倍以上になる⇒ If you don't, you lose half your life / 使わないと人生を半分損する

ジ

バ

fi

fi

が

73

diff ＆ patch• diff command• Output difference between two textles / 2つのテキストファイルの差分を出力• More compact than storing entire

le / ファイル全体を保存するよりコン クト• Easy to see the changes / 変更点を確認しやすい$ diff -u

le1.txt

le2.txt >le.diff• patch command• Apply the diff generated by the diff command / diff コマン

生成した差分をファイルに適用• Generate modi

ed le from original
ら変更後のファイルを生成$ patch <le and diff / もとのファイルと差分か

le.diff

パ

が

ド

fi

fi

fi

fi

fi

fi

fi

fi

fi

74

diff & patch: Single File Example$ cp /somewhere/shakespeare/prologue.txt prologue.txt$ cp prologue.txt prologue-orig.txt# edit prologue.txt$ vim prologue.txt# take a diff and look at it contents$ diff -u prologue-orig.txt prologue.txt > prologue.diff$ less prologue.diff# apply patch$ cp /somewhere/shakespeare/prologue.txt prologue.txt$ patch < prologue.diff$ less prologue.txt

75diff & patch: Directory Example$ cp -r /somewhere/shakespeare shakespeare$ cp -r shakespeare shakespeare.orig# edit contents of directory$ (vim, cp, mv, etc)
# take a diff and look at its contents$ diff -urN shakespeare.orig shakespeare > shakespeare.diff$ less shakespeare.diff# apply patch$ rm -rf shakespeare$ cp -r /somewhere/shakespeare shakespeare$ patch -p0 < shakespeare.diff76Git Demonstration: initialize repository• First setup / 初回の設定 (Just do it once for the

rst time on each PC/WS)• Setup of username etc (used for logs, etc / ロ

な に使用される)$ git con g --global user.name ’Synge Todo’$ git con g --global user.email wistaria@phys.s.u-tokyo.ac.jp$ git con g --global init.defaultBranch main
• Create working directory and git repository / 作業用ィレクトリと git リ

トリの作成$ mkdir bonacci$ cd bonacci$ git init
Initialized empty Git repository in .../ bonacci/.git$ ls -a. .. .git• All history information is stored in .git. Never delete .git! / 全ての履歴情報

は .git に保存される。けっして .git を消さないように!

ジ

ポ

デ

ど

fi

グ

fi

fi

fi

fi

fi

fi

77

Git Demonstration:• Create

rst commit

les and perform test / ファイルの作成とテスト$ vim CMakeLists.txt$ vim bonacci.cpp# cmake & make• Add

les as targets to be committed / ファイルをcommitの対象として追加$ git add CMakeLists.txt$ git status...

bonacci.cpp• Commit to repository / リポジトリにコミット• Use "-m" option for commit log / コミットログは "-m" で指定 (Write "Why")$ git commit -m 'cmake and make to work'• Check log / ログの確認$ git log

fi

fi

fi

fi

fi

78

Git Demonstration: 2nd iteration• Edit and add

les / ファイルの編集・追加$ vim CMakeLists.txt$ vim test_ bonacc.cpp# cmake & make & ctest• Check status and diff / 状態と差分を見てみる$ git status...
$ git diff...
• Commit to repository / リポジトリにコミット$ git add CMakeLists.txt test_ bonacci.cpp$ git commit -m ' rst test to work'• Check log / ログの確認$ git log

fi

fi

fi

fi

79

TDD Work ow• Red• Write a failing automated test before you write any code / コードを書く

前に失敗する自動テストコードを必ず書く• git fetch → git merge → git checkout• vim → cmake → make → ｃtest• Green• Write just enough code to pass the test / テストをパスする最低限のコードを書く• [vim → cmake → make → ｃtest ...] → git add → git commit ...
• git checkout → git merge → git push
• Refactor• Remove duplication / 重複を除去する• git checkout• [[vim → cmake → make → ｃtest ...] → git add → git commit ...]• git checkout → git merge → git pushfl80• Only source code and CMakeLists.txt etc should be managed under Git /GitではソースコードやCMakeLists.txtのみを管理• Files generated by cmake and make under build should notbemanaged / build以下のcmakeやmakeで生成されたファイルは管理しない• List unmanaged

les in .gitignore / .gitignoreに管理しないファイルのリスト$ git status

bonacci/.gitignore
build$ git status• Manage .gitignore itself by Git / .gitignore自体はGitで管理する$ git add .gitignore$ git commit -m 'ignore build'$ git status

81
fi

fi

“.gitignore"

Part II: Version Control / バージョン管理

Branch & Merge / ブランチとマージ

What's Branch?
• Branch / ブランチ
• Working in a separate stream from the main / メインとは別の流れで作業を続ける機能• Can work without affecting other branches / 他のブランチには影響を与えずに作業ができる
C1

main
C4

C2

C3
develop

C5• Creating new branch / 新規ブランチの生成

C6
topic

• git branch ...
• Switching between branches / ブランチの切り替え• git checkout ...
83

Git Demonstration: branch• Assume done up to 6th iteration / 6th iteration まで終わっていると仮定• Create a topic branch (negative-n) for 7th iteration and work there /７ｔｈ iterationのためのトピックブランチ(negative-n)を作成してそこで作業$ git status$ git branch negative-n$ git checkout negative-n$ git status# [vim → cmake → make → ctest]$ git add bonacci.hpp test_ bonacci.cpp$ git commit -m 'for supporting negative n'• Go back to the main branch / mainブランチに戻ってみる$ git checkout main$ less bonacci.hpp• Can go back and forth between main and negative-n with git checkout /git checkout で main と negative-n の間を行ったり来たりできる

fi

fi

fi

84

Multiple Branches• Go back to main (or create a new branch) and commit there, then theworld line branches off / mainに戻って(あるいは新しいbranchを作って)そこで
commitすると世界線が枝分かれする
main
C1

C2

C3
develop

topic

main
C1

C4

C2

main
C1

C4

C2

C3

C3

developdevelop85

What's Merge• Merging branch / ブランチのマージ• Merge divergent world lines / 分岐した世界線を統合する

main
C4

C2

C1

C3
develop

main
C1

C4

C2

C5

C3
develop86

Git Demonstration: merge• Once work on negative-n branch is completed, merge it into main branch/ negative-nブランチの作業が完了したので、mainブランチにmergeする$ git status$ git checkout main
$ git status$ git log --graph$ git merge negative-n$ git log --graph• Remove negative-n branch as it is no longer needed / negative-nブランチ

はもう不要なので削除$ git branch -D negative-n$ git log --graph• The divergent world lines have come back together / 分岐していた世界線が一

つに戻った

87

Git Demonstration: branch ＆ merge• Try to do 8th iteration and 9th iteration in parallel / 8th iteration と 9th

iterationを並行してやってみる• Create a branch (linear) for 8th iteration and work there / 8ｔｈiterationのためのブランチ(linear)を作成してそこで作業$ git status$ git branch linear$ git checkout linear# [vim → cmake → make → ctest]$ git add bonacci.hpp test_ bonacci.cpp$ git commit -m 'for supporting negative n'• Return back to main branch and create a branch (multiprec) for 9th

iteration and work there / mainブランチに戻り、9th iterationのためのブランチ(multiprec)を作成して作業

fi

fi

fi

fi

$ git checkout main
$ git branch multiprec$ git checkout multiprec# [vim → cmake → make → ctest]$ git add CMakeLists.txt bonacci.hpp test_ bonacci.cpp$ git commit -m 'for supporting arbitrary large n'

88Git Demonstration: con ict• Merge linear branch into main and then try merging multiprec branch /linearブランチをmainにマージしてから、multiprecブランチをマージしてみる$ git checkout main
$ git merge linear$ git merge multiprec
Auto-merging bonacci.hpp
CONFLICT (content): Merge con ict in bonacci.hpp
Auto-merging test_ bonacci.cpp
CONFLICT (content): Merge con ict in test_ bonacci.cpp
Automatic merge failed; x con icts and then commit the result.
• Git has decided it's not possible to integrate automatically / Gitは自動的に統合するのは無理と判断した$ git status
On branch main
You have unmerged paths.
( x con icts and run "git commit")(use "git merge --abort" to abort the merge)
...

fl

fi

fi

fl

fl

fl

fi

fi

fi

fl

fi

89

• Conicts must be adjusted by hand / 衝突は手で調整しなければならない

bonacci/ bonacci.hpp#include <tuple><<<<<<< HEAD
int bonacci(int n) {int v0 = 0;
int v1 = 1;=======#include <boost/multiprecision/cpp_int.hpp>
namespace mp = boost::multiprecision;
mp::cpp_int bonacci(int n) {mp::cpp_int v0 = 0;
mp::cpp_int v1 = 1;>>>>>>> multiprec
if (n < 0) {

fl

fi

fi

fl

90
fi

fi

Git Demonstration: resolving con ict

•bonacci.hpp and test_ bonacci.cpp have been modi ed /と test_ bonacci.cppの修正が完了した

bonacci.hpp# [cmake → make → ctest]$ git add bonacci.hpp test_ bonacci.cpp$ git commit -m 'merge branch multiprec'$ git status$ git log --graph• The merge is successfully completed and the world lines are united / 無

事mergeが完了して世界線が一つに$ git branch -d linear multiprec
Deleted branch linear (was 38e6ae4).
Deleted branch multiprec (was dda8e49).
$ git status$ git log --graph• Never merge into the main branch if there are still tests that do not pass/ 通らないテストが残っている場合には絶対にmainブランチにマージしない

fl

fi

fi

fi

fi

fi

91
fi

fi

Git Demonstration: resolving con ict

Part II: Version Control / バージョン管理

Using GitHub / GitHubの利用

Git & GitHub• Git allows multiple repositories to be used in sync with each other / Git

では複数のリポジトリを互いに同期しながら使うことができる• GitHub can be used as one of remote repositories / GitHubはリモートリポジ

トリのひとつとして使える• Copy (backup) can be made by pushing from local repository / ローカ

ルリポジトリからpushすることでコピー(バックアップ)を取ることができる• As we can access from anywhere, GitHub works asa hub for synchronizing repositories across multiple
computers / どこからでもアクセスすることができるので、複数のコンピュータでリポジトリーを同期するためのハブとして利用できる• Convenient for source code sharing by a team andsource code publication / チームでのソースコード
共有・ソースコード公開にも便利• Use as a CI (Continuous Integration) tool

/ CI (継続的インテグレーション)ツールとしての利用

https://git-scm.com/book/93Using GitHub• GitHub Account Registration / GitHubアカウント登録 (if you do not yet haveregistered / ま アカウントを持っていない場合)• https://github.com → Sign up for GitHub → Create an account• Register SSH public key or obtain HTTPS access token / SSH公開鍵の登録

あるいはHTTPSアクセストークンの取得• To write to GitHub repository with git command, either must be set

up in advance / gitコマンドでGitHubリポジトリに書き込むためには、あらかじめど
ちらかの設定が必要• SSH public key / SSH公開鍵の登録• Setting → SSH and GPG keys → New SSH Key• HTTPS access token / HTTPSアクセストークンの取得• Setting → Developer settings → Personal access tokens → check"repo" and "work ow" → Generate new token

fl

だ

94

GitHub Demonstration: initialize repository• Initialization of repository / リポジトリの初期化• Instead of doing a local git init, it is easier to create a repository on

GitHub and copy it / localでgit initする代わりに、GitHubでリポジトリを作りそれをコピーするほうが楽• First create a repository on GitHub / 最初にGitHub上でリポジトリを作成• determine public or private / publicにするかprivateにするか決める• name of project / プロジェクトの名前 ← ultra-important / 超重要• Clone the GitHub repository locally and start development / GitHubのリポ

ジトリをローカルにcloneしてから開発開始• Copy repository URL / リポジトリのURLをコピー (https://... or

git@github.com...)• git clone$ git clone https://github.com/wistaria/ bonacci.git• [vim → cmake → make → ｃtest ...] → git add → git commit ...

fi

95

GitHub Demonstration: sync repositories• GitHub → local repository / GitHub → ローカルのリポジトリ$ git fetch• Entire repository on GitHub is copied / リポジトリ全体がコピーされる• Branch on GitHub (e.g. main) is locally named origin/main / GitHub上のブランチ(例: main)はローカルではorigin/mainという名前がつけられる• Branch diverges if repository is modi

ed from elsewhere/by others /他の場所から/他の人がリポジトリを変更している場合にはブランチが分岐する
GitHub
C2

C1

main

GitHub

C4

C1

main
C4

C2

fetch

origin/main

main
C1

C2

C1

C3

C4

C2

C3

local

local

main

fi

96

GitHub Demonstration: sync repositories• local repository → GitHub / ローカルのリポジトリ → GitHub• Specify branch to be duplicated / 複製するブランチを指定する (e.g. main)$ git push origin main
• Fails if someone else has pushed to main branch on GitHub / 他の人がGitHub上のmainブランチにpushしている場合には失敗する→ fetch & merge rst, then push / fetch & merge してから push する
GitHub main

GitHub

C2

C1

C1

main
C4

C2

push main

origin/main

main
C1

C4

C2

C1

develop

C4

C2

C3

C3

local

main

local

developfi

97

TDD Work ow• Red• Write a failing automated test before you write any code / コードを書く

前に失敗する自動テストコードを必ず書く• git fetch → git merge → git checkout• vim → cmake → make → ｃtest• Green• Write just enough code to pass the test / テストをパスする最低限のコードを書く• [vim → cmake → make → ｃtest ...] → git add → git commit ...
• git checkout → git merge → git push
• Refactor• Remove duplication / 重複を除去する• git checkout• [[vim → cmake → make → ｃtest ...] → git add → git commit ...]• git checkout → git merge → git pushfl98

Using Git & GitHub Successfully• Tips for using Git & GitHub successfully / Git & GitHubをうまく使うコツ• Be well aware that there are 3 layers / 階層が3つあることを十分に認識する• local working space ⇔ local repository ⇔ remote repository(GitHub)• local working space ⇔ local repository• git checkout & git commit• local repository ⇔ remote repository• git fetch & git push
• Always create a branch and work on it / 必ずブランチを作って作業する• Commit frequently / マメにコミットする• Think VCS as backup / バックアップだと考える• Test frequently / マメにテストする• Compile & make sure all tests pass before merging into main branch/ コンパイル & 全てのテストが通ることを確認してから main ブランチにマージする

99

Part II: Version Control / バージョン管理

Continuous Integration (CI) / 継続的インテグレーション

More Automated Testing• Ideal / 理想
• In TDD, main branch is always in Green state / テスト駆動開発においては、

mainブランチは常にGreen状態• Real / 現実
• Forget to run tests / テストを忘れる• Tests may not pass in other environments (OS, compiler) / 他の環境

(OS・コンパイラ)ではテストが通らないことも• Can't know if others are running tests correctly / 他の人がテストを正しく実行しているか分からない

101

What's Continuous Integration?
• Continuous Integration (CI) / 継続的インテグレーション (CI)• Automatically run tests when code is commited to the repository /コードがリポジトリにcommitされたタイミングで自動的にテストを走らせる• Cumbersome to set up such a con

guration on local PC / ローカルPCでそのような設定をするのは面倒• GitHub Actions https://docs.github.com/ja/actions• Execute any job at the time of push to GitHub (or other) / GitHubにpushした（あるいは別の)タイミングで任意のジョブを実行• Use for CI / CIに利用する• Setting up GitHub Actions / GitHub Actionsの設定• Create a YAML (.yml)

le under .github/work ows / .github/work ows の下にYAML (.yml)ファイルを作成

fl

fi

fi

fl

102

GitHub Actions• Create a YAML (.yml)

le under .github/work ows / .github/work ows の下にYAML (.yml)ファイルを作成.github/work ows/unittest.yml
name: unittest
on: [push]jobs:
build:
runs-on: ubuntu-latest
steps:- name: checkout
uses: actions/checkout@v3- name: cmakerun: mkdir build && cd build && cmake ..
- name: makerun: cd build && make- name: ctest
run: cd build && ctest

fl

fl

fi

fl

103

CI by GitHub Actions• Con

rmation of results / 結果の確認• GitHub Repository Web → 「Action」 tab• You will receive an email if the automated test fails / 自動テストがfailした場合にはメールが届く• Using matrix• Matrix functionality allows to run tests on multiple versions ofcompilers, multiple operating systems, etc / Matrix機能を使うと、複数バー
ジョンのコンパイラ、複数のオペレーティングシステムなどでテストを実行できる• https://docs.github.com/ja/actions/using-jobs/using-a-matrix-for-your-jobs• Various other tasks can be automated / それ以外にも様々な作業を自動化できる

fi

104

TDD Work ow• Red• Write a failing automated test before you write any code / コードを書く

前に失敗する自動テストコードを必ず書く• git fetch → git merge → git checkout• vim → cmake → make → ｃtest• Green• Write just enough code to pass the test / テストをパスする最低限のコードを書く• [vim → cmake → make → ｃtest ...] → git add → git commit ...
• git checkout → git merge → git push
• Refactor• Remove duplication / 重複を除去する• git checkout• [[vim → cmake → make → ｃtest ...] → git add → git commit ...]• git checkout → git merge → git push

fl

105

Epilogue: Summary and Final Words• By using TDD, VCS, etc• We can develop programs with fewer defects without being anxious /不安をかかえこまに、欠陥の少ない ロ ラムを開発できる• We can use TDD and VCS in various situations, from small tools tohuge software, from individual to large-group development / 小さなツールから非常に大規模なソフ トウェアま 、個人開発から大きな ルーの開発ま• Don't Repeat Yourself (DRY) principle / DRY原則• Think of every line of code you write as a message for someone in the

future / 自分の書くコードはすべて未来の誰かへのメッセージだと考える• including yourself :-) / 含む自分自身w• You yourself last month/last week/three days ago were a stranger /先月の/先週の/3日前の自分は他人

で

で

プ

グ

で

グ

プ

ず

106

References• 「Test Driven Development: By Example」 by K. Beck
• https://www.oreilly.com/library/view/test-driven-development/

0321146530/• https://shop.ohmsha.co.jp/shopdetail/000000004967/• 「Pro Git」 by S. Chacon and B. Straub• https://git-scm.com/book/ja/v2• 「97 Things Every Programmer Should Know」 ed. K. Henney• https://github.com/97-things/97-things-every-programmer-should-

know• https://ja.wikisource.org/wiki/カテゴリ:プログラマが知るべき97のこと• Sample Code Repository• https://github.com/wistaria/tdd-tutorial• contributors: https://github.com/wistaria/tdd-tutorial/graphs/contributors
107