name
ソフトウェア開発での必須スキルとなるTDD(test driven development, テスト駆動開発), class, refactoringを,Ruby言語で習得する
zoom link
- ミーティングID: 822 0399 4456
- パスコード: 473581
最終課題
RubyでなんかCLA(自分の作業に便利な)を作って!
- その作ったexecutableなCLAをgithubにあげる
- README.mdで
- 使用前の問題点
- 使用法
- 使ったcodeの簡単な解説
- 使用後どれほど効率が上がったか
- を書く
- LUNAにpdfを提出
- A4, 1-2pagesにまとめて
- citationをちゃんとしてね
- github(publicでなくていい)のlinkをcitationに
- githubのcollaboratorに担当者のidを入れてください.
- わからなんだらお問い合わせください
- 提出期限は,24/1/17 24:00です.
Schedule, text and movie
data | text | title | memo | 動画 |
---|---|---|---|---|
d1 (9/20) | TDD(preface) | Intro, chat GPT | memo | link |
d2 (9/27) | TDD(intro) | my_help, six things | link | |
d3 (10/4) | TDD(c1 , c2 ) | TDD by Ruby | link | |
d4 (10/11) | TDD(c3,c4,c5) | link | ||
d5 (10/18) | TDD(c6, c7, c8, c9, c10) | link | ||
d6 (10/25) | TDD(c11, c12,) | link | ||
d7 (11/1) | TDD() | |||
d8 (11/8) | TDD( c13, c14 ) | link | ||
d9 (11/15) | TDD( c15, c16 ) | link | ||
Pattern( Matz template, | ||||
d10(11/22) | strategy, | link | ||
d11(11/29) | observer, factory | Russ Olsen(J) | link | |
d12(12/6) | CoC, DSL(Rakefile) | gem 作成 | link | |
d13(12/13) | FSM | qiita | link |
d9-
Kent BeckのTDDを読み込んでどうやったやろ.私が初めて読んだ時の感想は,
- TDDバンザイ
- Clean code that works.
- Divide and Conquer, baby
- Red, Green, Refactoringってそういう意味やったんや
なんかです.すごいprogram codeは何度かみたことがあって,どうやるんやろ?って思ってたんですが,それがbottom upで作られたと思うとなんとなくそのコンセプトを征服できたみたいで理解が進むようになりました.
さて,デザインとか,アーキテクチャというのは後でついてくるものというのは,実感できたと思うのですが,それでも知ってないと発明する必要があって,それはNIHなんでダメですよね.
そこで,トップダウンの典型になるデザインパターンを紹介します.まずは,Rubyの父のMatzの言葉を読んでください.デザインパターンの本質が「名前」であると看破してます.
d7(11/1)
interface Expression
ask 'JavaのinterfaceをRubyで実装する方法を教えて' on Bing,
Javaのinterfaceは、特定のメソッドを持つことを強制するための契約のようなものです。しかし、Rubyはダックタイピングと呼ばれる概念を使用しており、クラスが特定のメソッドに応答するかどうかは各クラスに委ねられています。そのため、RubyにはJavaのようなinterfaceは存在しません。
ただし、Rubyではモジュールを使用してJavaのinterfaceに似た機能を実現することができます。モジュール内でメソッドを定義し、そのモジュールをクラスにミックスインすることで、クラスが特定のメソッドを持つことを保証することができます。
qiita JavaのinterfaceをRubyで実装する方法を教えて https://ruby-processing.github.io/JRubyArt/modules/interface
従って,Javaでは型定義が必要なので便利だが,RubyではExpressionを明示する必要はない.
- c14のPairのところでやめた.
以下は最終版
# frozen_string_literal: true
require_relative "tdd_example4/version"
module TddExample4
class Pair
def initialize(from, to)
@from = from
@to = to
end
=begin
def equals(object)
pair = Pair.new(object)
return from.equals(pair.from) && to.equals(pair.to)
end
=end
def hashcode()
return 0
end
end
class Sum
attr_reader :augend, :addend
def initialize(augend, addend)
@augend = augend
@addend = addend
end
def reduce(bank, to)
amount = @augend.reduce(bank, to).amount +
@addend.reduce(bank, to).amount
return Money.new(amount, to)
end
end
module Expression
# Ruby implementation of Java's interface, but ...
end
class Bank
def initialize
@rates = {}
end
# include Expression
def add_rate(from, to, rate)
@rates[Pair.new(from, to).hashcode] = rate
end
def reduce(source, to)
=begin
if source.class == Money
return source.reduce(to)
end
sum = source # not new
=end
return source.reduce(self, to) #Money.new(10).dollar
end
def rate(from, to)
return 1 if from == to
return @rates[Pair.new(from, to).hashcode]
# return (from=='CHF' && to=='USD') ? 2 : 1
end
end
class Money
public attr_reader :amount
public attr_reader :currency
def initialize(amount, currency=nil)
@amount = amount
@currency = currency
end
def reduce(bank, to)
rate = bank.rate(@currency, to)
return Money.new(@amount/rate, to) #self
end
def +(addend) = Sum.new(self, addend)
# return Money.new(@amount + addend.amount, currency)
def ==(object)
money = object
return @amount == money.amount &&
self.currency == money.currency
end
def dollar = Money.new(@amount, 'USD')
def franc = Money.new(@amount, 'CHF')
def times(multiplier)
return Money.new(@amount * multiplier, @currency)
end
end
end
# frozen_string_literal: true
require "test_helper"
class TddExample4Test < Test::Unit::TestCase
include TddExample4
test "VERSION" do
assert do
::TddExample4.const_defined?(:VERSION)
end
end
test "something useful" do
# assert_equal("expected", "actual")
assert_equal("expected", "expected")
end
test "mixed addition" do
five_bucks = Money.new(5).dollar
ten_franc = Money.new(10).franc
# sum = Sum.new(five_bucks, ten_franc) # expression
bank = Bank.new()
bank.add_rate('CHF', 'USD', 2)
result = bank.reduce(five_bucks + ten_franc, 'USD')
assert_equal(Money.new(10).dollar, result)
end
test "identity rate" do
assert_equal(1, Bank.new.rate('USD', 'USD'))
end
test "plus returns sum" do
five = Money.new(5).dollar
sum = five + five # expression
assert_equal(five, sum.augend)
assert_equal(five, sum.addend)
end
test "reduce money different currency" do
bank = Bank.new()
bank.add_rate('CHF', 'USD', 2)
result = bank.reduce(Money.new(2).franc, 'USD')
assert_equal(Money.new(1).dollar, result)
end
test "bank returns reduce sum" do
three_usd = Money.new(3).dollar
four_usd = Money.new(4).dollar
sum = Sum.new(three_usd, four_usd) # expression
bank = Bank.new()
result = bank.reduce(sum, 'USD')
assert_equal(Money.new(7).dollar, result)
end
test "reduce money" do
bank = Bank.new()
result = bank.reduce(Money.new(1).dollar, 'USD')
assert_equal(Money.new(1).dollar, result)
end
test "simple addition" do
five = Money.new(5).dollar
sum = five + five # expression
bank = Bank.new
reduced = bank.reduce(sum, 'USD')
assert_equal(Money.new(10).dollar, reduced)
# assert_equal(Money.new(10).dollar, sum)
end
test "currency" do
assert_equal 'USD', Money.new(1).dollar.currency
assert_equal 'CHF', Money.new(1).franc.currency
end
test "equality" do
assert_true Money.new(5).dollar == Money.new(5).dollar
assert_false Money.new(5).dollar == Money.new(6).dollar
assert_true Money.new(5).franc == Money.new(5).franc
assert_false Money.new(5).franc == Money.new(6).franc
assert_false Money.new(5).franc == Money.new(5).dollar
end
test "multiplication" do
five = Money.new(5).dollar
assert_true Money.new(10).dollar == five.times(2)
assert_true Money.new(15).dollar == five.times(3)
end
test "Franc multiplication" do
five = Money.new(5).franc
assert_true Money.new(10).franc == five.times(2)
assert_true Money.new(15).franc == five.times(3)
end
end
d6(10/25)
c12, 13
Expressionを作った.これで,interfaceが...できるか?? ようわからんな.というところ
whole todo[10/16]
- $5 + 10 CHF = $10 if rate is 2:1
- $5+$5=$10
- Return Money from $5 + $5
- [X] $5 * 2 $10
- [X] Make "amount' private
- [X] class Dollar side-effects?
- Money rounding?
- [X] equals()
- hashCode()
- Equal null
- Equal object
- [X] 5 CHF * 2 = 10 CHF
- [X] Common times
- [X] Dollar/Franc duplication
- [X] Common equals
- [X] Compare Francs with Dollars
- [X] Currency?
- Delete Franc multiplication?
current codes
Moneyクラスへの統合が済んだので,codeはスッキリ.Kent本にはありませんが,Ruby独自の仕様でさらに読みやすくできます.その辺りから始めて,本丸(フランとドルの計算)へ突き進んでいきます.
# frozen_string_literal: true
require_relative "tdd_example4/version"
module TddExample4
class Money
protected attr_reader :amount
def initialize(amount, currency=nil)
@amount = amount
@currency = currency
end
def equals(object)
money = object
# p [@amount, self.class, ":", money.amount, money.class]
return @amount == money.amount &&
self.currency == money.currency
end
def dollar()
return Money.new(@amount, 'USD')
end
def franc()
return Money.new(@amount, 'CHF')
end
def currency
return @currency
end
def times(multiplier)
return Money.new(@amount * multiplier, @currency)
end
end
end
# frozen_string_literal: true
require "test_helper"
class TddExample4Test < Test::Unit::TestCase
include TddExample4
test "VERSION" do
assert do
::TddExample4.const_defined?(:VERSION)
end
end
test "something useful" do
# assert_equal("expected", "actual")
assert_equal("expected", "expected")
end
test "currency" do
assert_equal('USD', Money.new(1).dollar.currency() )
assert_equal('CHF', Money.new(1).franc.currency() )
end
test "equality" do
assert_true( Money.new(5).dollar.equals( Money.new(5).dollar ) )
assert_false( Money.new(5).dollar.equals( Money.new(6).dollar ) )
assert_true( Money.new(5).franc.equals( Money.new(5).franc ) )
assert_false( Money.new(5).franc.equals( Money.new(6).franc ) )
assert_false( Money.new(5).franc.equals( Money.new(5).dollar ) )
end
test "multiplication" do
five = Money.new(5).dollar
assert_true( Money.new(10).dollar.equals( five.times(2) ) )
assert_true( Money.new(15).dollar.equals( five.times(3) ) )
end
test "Franc multiplication" do
five = Money.new(5).franc
assert_true( Money.new(10).franc.equals( five.times(2) ) )
assert_true( Money.new(15).franc.equals( five.times(3) ) )
end
end
d5(10/18) c6-c10
current codes
5日目を始める時のcodeの現況はこんな感じ.
- FrancをDollarからコピペで作ったばかり
で,この段階としては最も大きくなっています.このあと,Moneyクラスに統合していくんだけど,作業内容は,Kentの言葉"Remove duplication(in c5)"が最も象徴的.でも,単なる重複削除ではなく,その思考法が大事.super/sub class, factory, currency(class but string)などの言葉を覚えておくと,自作コードが拡張性も見据えてオシャレになる.
# frozen_string_literal: true
require_relative "tdd_example3/version"
module TddExample3
class Error < StandardError; end
# Your code goes here...
def hello
return 'hello'
end
class Dollar
protected attr_reader :amount
def initialize(amount)
@amount = amount
end
def times(multiplier)
return Dollar.new(@amount * multiplier)
end
def equals(object)
dollar = object
return @amount == dollar.amount
end
end
class Franc
protected attr_reader :amount
def initialize(amount)
@amount = amount
end
def times(multiplier)
return Franc.new(@amount * multiplier)
end
def equals(object)
franc = object
return @amount == franc.amount
end
end
end
# frozen_string_literal: true
require "test_helper"
class TddExample3Test < Test::Unit::TestCase
include TddExample3
test "VERSION" do
assert do
::TddExample3.const_defined?(:VERSION)
end
end
test "equality" do
assert_true Dollar.new(5).equals Dollar.new(5)
assert_false Dollar.new(5).equals Dollar.new(6)
end
test 'multiplication' do
five = Dollar.new(5)
assert_true Dollar.new(10).equals five.times(2)
assert_true Dollar.new(15).equals five.times(3)
end
test 'franc multiplication' do
five = Franc.new(5)
assert_true Franc.new(10).equals five.times(2)
assert_true Franc.new(15).equals five.times(3)
end
end
c10 Interesting Times
- [X] Common times
- [X] Currency?
c9 Times We're Livin' In
- Currency!!
c8 Makin' Objects
c7 Apples and Oranges
- [X] Compare Francs with Dollars
- Currency?
c6 Equality
- [X] Dollar/Franc duplication
- [X] Common equals
d4(10/11) c1-4 again
c5 Franc-ly Speaking[5/13]
- Dollar/Franc duplication
c4 Privacy
- $5 + 10 CHF = $10 if rate is 2:1
- Make "amount' priate
- [X] class Dollar side-effects?
- Money rounding?
- [X] equals()
- hashCode()
- Equal null
- Equal object
c3 Equality for All[/]
-
$5 + 10 CHF = $10 if rate is 2:1
-
Make "amount' priate
-
[X] class Dollar side-effects?
-
Money rounding?
-
[X] equals()
-
hashCode()
-
Triangle
c2 Degenerate Objects[1/4]
- $5 + 10 CHF = $10 if rate is 2:1
- Make "amount' priate
- [X] class Dollar side-effects?
- Money rounding?
cat lib/tdd_example4.rb test/tdd_example4_test.rb
# frozen_string_literal: true
require_relative "tdd_example4/version"
module TddExample4
class Dollar
attr_reader :amount
def initialize(amount)
@amount = amount
end
def times(multiplier)
# @amount *= multiplier
return Dollar.new(@amount * multiplier)
end
end
end
# frozen_string_literal: true
require "test_helper"
class TddExample4Test < Test::Unit::TestCase
include TddExample4
test "VERSION" do
assert do
::TddExample4.const_defined?(:VERSION)
end
end
test "something useful" do
# assert_equal("expected", "actual")
assert_equal("expected", "expected")
end
test "multiplication" do
five = Dollar.new(5)
product = five.times(2)
assert_equal(10, product.amount)
product = five.times(3)
assert_equal(15, product.amount)
end
end
c1 Multi_currency_money
-
株価,shareから総資産を表示する.
-
$からスイスフランを追加.
-
[X] $5 * 2 $10
# frozen_string_literal: true
require "test_helper"
class TddExample4Test < Test::Unit::TestCase
include TddExample4
test "multiplication" do
five = Dollar.new(5)
five.times(2)
assert_equal(10, five.amount)
end
end
# frozen_string_literal: true
require_relative "tdd_example4/version"
module TddExample4
class Error < StandardError; end
# Your code goes here...
class Dollar
attr_reader :amount
def initialize(amount)
# @amount = 5 * 2
@amount = amount
end
def times(multiplier)
@amount *= multiplier
end
end
end
d3 bundle, framework, test-unit
-
bundle
gem install bundler # not bundle bundle gem -t test-unit tdd_example3
> cat ~/.bundle/config (base) --- BUNDLE_GEM__TEST: "test-unit" BUNDLE_GEM__COC: "true" BUNDLE_GEM__CI: "false" BUNDLE_GEM__CHANGELOG: "true" BUNDLE_GEM__MIT: "true" BUNDLE_GEM__LINTER: "false"
-
rake
-
bat
-
Akamai:Install and Use the Linux bat Command
sudo apt install bat
mkdir - p ~/.local/bin
ln -s /usr/bin/batcat ~/.local/bin/bat
[ ] hello
-
Text -> Multiscaleの意味
Multiscaleの意味
秋学期の間,講義に付き合っていただいてありがとうございます.コロナで君らの学生生活は埋まっちゃったと思うんですが,当初は,LUNAの提出先を開けるの忘れたり,Zoomの録画をどじったりして,ご迷惑をかけましたね.今でもですが...でも,教える側もこのドタバタを通して,いくつかのツールを有効に使うスキルを身につけました.Zoomとか手書き表示とかです.
さて,講義の題目のマルチスケールの意味についてです.この講義は20年やってきたんですが,当初は,物理のマルチスケール(オングストロームからマイクロメータ)で量子力学,分子動力学,モンテカルロ,有限要素法,フェーズフィールドといったそれぞれの手法を紹介していました.ところが,情報の学生に教えるにはあまりに物理なので,内容を再構成しようと思って徐々に変えてきました.そして今秋は,「コードもマルチスケールじゃね?」という方針に行きつきました.
粒度という概念を知っていますか?英語の直訳はgrain sizeですが,scaleと考えることもできます.コードでは,ループやifブロック,メソッド,クラスという感じで,対象とするコードの粒度が異なります.途中から紹介したデザインパターンは明らかにクラスレベルへの対処法をマニュアル化したものです.しかし,最後で紹介した新しいパターンとしての
- CoC(Convention over configuration: 設定よりも規約)や
- FSM(Finite state machine: 有限状態マシン,野田くん発音の指摘ありがとう,国際会議でも恥かいてます)
はアプリやメソッドレベルへのパターンです.さらに,テスト駆動開発は,全てのスケールで適用できます.そう考えると,RailsでブレークしたCoCパターンのうち,ファイルやディレクトリーの名前に意味を持たせるというのは,
適切な変数名を考えることをスケールを変えて適用した
と捉えることができます.
このように言葉の持つイメージや概念をマルチスケールに膨らませれば,新しいイノベーションの可能性がいくらでも転がっているようです.事実,私も本業の数値計算で,これらの手法をqueueなんかに繋げて,スパコンスケールで活用しています.さらに,マシンスケールでシステムにしちゃうとどこで何を書いたかが覚えてられるから不思議です.
これらは,前人が残してくれた知恵の賜物です.特に授業でも紹介した,
- Kent Beck, 'Test-Driven Development by Example', (Pearson, 2003).
- Kent Beck (著), 和田 卓人 (翻訳), 「テスト駆動開発」 (オーム社 2017).
- Russ Olsen, 'Design Patterns in Ruby', (Addison-Wesley, 2007).
- ラス・オルセン, 「Rubyによるデザインパターン」(ピアソン桐原 2009).
- David Thomas, Andrew Hunt, 'The Pragmatic Programmer: Your journey to mastery, 20th Anniversary Edition' (Addison-Wesley Professional 2019).
- David Thomas, Andrew Hunt, 「達人プログラマー(第2版): 熟達に向けたあなたの旅」(オーム社 2020).
には,ベストプラクティス(至宝の知恵)が詰まっています.結局,コーディングのスキルは,記憶を強化するコツの塊なんですよね.つまみ読みでいいんで,全文に目を通されることをお勧めします.あるいは,なんか行き詰まった時に読み返されることを.この講義が,いいコーディング習慣の一助になれば幸いです.
d1, Ruby環境構築
- https://chat.openai.com
- win11上のWSLでemacs, ruby, fishをインストールする方法を教えてください.
- Ruby言語でmy_helpをインストールする方法を教えてください.
- source ~/git_hub/ruby_docs/multi_scale_23/README.org