Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MIXI TECH NOTE #09

MIXI TECH NOTE #09

#技術書典14 に出典された、MIXI GROUP エンジニア有志による技術書です。

<< 目次 >>
1章:静的解析ツールで Golang のうっかりミスをなくそう
2章:探訪 STM at Haskell
3章:Web の回帰テストの自動化
4章:micro:bit のおもしろ活用考査
5章:ChatGPT を QA が使いこなす為のアイデア

<< TECH NOTE 一覧 >>
mixi tech note #01
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-01

mixi tech note #02
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-02

mixi tech note #03
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-03

mixi tech note #04
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-04

mixi tech note #05
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-05

mixi tech note #06
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-06

mixi tech note #07
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-07

MIXI TECH NOTE #08
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-08

MIXI TECH NOTE #09
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-09

XFLAG Tech Note Vol.01
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-01

XFLAG Tech Note vol.02
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-02

MIXI ENGINEERS

May 22, 2023
Tweet

More Decks by MIXI ENGINEERS

Other Decks in Technology

Transcript

  1. ·͕͖͑ ຊॻʮMIXI TECH NOTE #09ʯ͸ɺMIXI GROUP ʹॴଐ͢Δ༗ࢤୡʹΑͬͯࣥචɾ੍࡞͞Εٕͨ ज़ॻͰ͢ɻ࣮ࡍͷݱ৔Ͱ࢖ΘΕٕͨज़΍ߟ͑ํɺ·ͨɺݸਓతʹڵຯɾؔ৺ͷ͋Δ෼໺͔Βɺࢥ͍ࢥ ͍ʹࣥච͍ͨ͠·ͨ͠ɻͦͷͨΊɺ֤ষͦΕͧΕͰ׬͍݁ͯ͠Δ಺༰ʹͳ͍ͬͯ·͢ͷͰɺ޷͖ͳষ ͔Β޷͖ͳॱ൪Ͱָ͓͠Έ͍ͩ͘͞ɻ

    ·ͨɺຊॻ͸ɺMIXI GROUP ʹ͋Δٕज़త஌ݟ΍ΞΠσΞΛੵۃతʹڞ༗ɾެ։͍ͯ͘͜͠ͱ ͰɺੈͷதʹΑΓྑ͍αʔϏε͕ҲΕग़͢͜ͱΛئͬͯץߦ͞Ε͍ͯ·͢ɻܝࡌ͞Ε͍ͯΔ৘ใ͸ɺ ࣥචऀࣗ਎ͷ؀ڥͰݕূࣥ͠ච͞Εͨ΋ͷͰ͢ͷͰɺ͝ࢀߟʹ͞ΕΔࡍ͸ɺࣗ͝਎ͷ੹೚Ͱ൑அ͠ ͝׆༻͍ͩ͘͞ɻͳ͓ɺจষදݱʹ͖ͭ·ͯ͠΋ɺࣥචऀࣗ਎ͷݴ༿Ͱ఻͑ͨ͘ɺϑϥϯΫͳදݱͱ ͳ͓ͬͯΓ·͢͜ͱ͝ཧղ͍͚ͨͩΕ͹ͱࢥ͍·͢ɻ MIXI DEVELOPERS Ұಉ ˗ຊॻʹؔ͢Δ͓໰͍߹Θͤઌ ɹ https://twitter.com/mixi_engineers ˗ MIXI GROUP ʹ͍ͭͯ ɹ https://mixi.co.jp/ ˞ MIXI ͷ໊শɺ͜Εʹؔ࿈͢Δ঎ඪٴͼϩΰ͸ɺגࣜձࣾ MIXI ͷ঎ඪٴͼొ࿥঎ඪͰ͢ɻ·ͨɺ ֤ࣾͷձ໊ࣾɺαʔϏεٴͼ੡඼ͷ໊শ͸ɺͦΕͧΕͷॴ༗͢Δ঎ඪ·ͨ͸ొ࿥঎ඪͰ͢ɻ iii
  2. ໨࣍ ·͕͖͑ iii ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1

    1.1 ͸͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Go Analysis Λ࢝ΊΔ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 ੩తղੳπʔϧΛॻ͍ͯΈΔ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.4 ͓ΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 ୈ 2 ষ ୳๚ STM at Haskell 13 2.1 Software Transactional Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.2 STM ͷ࢖ΘΕํ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.3 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 ୈ 3 ষ Web ͷճؼςετͷࣗಈԽ 23 3.1 ճؼςετͱ͸ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.2 ՝୊ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.3 Ξϓϩʔν . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.4 ࣮ફ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.5 ͍͞͝ʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 29 4.1 ຊষʹ͍ͭͯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4.2 ಺ଂ Beep ԻεϐʔΧʔͰϝϩσΟϓϨΠϠʔ . . . . . . . . . . . . . . . . . . . . 32 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ . . . . . . . . . . . . . . . . . . . . . . 35 4.4 ϚΠίϯνοϓ୯ಠϛχήʔϜ੍࡞ . . . . . . . . . . . . . . . . . . . . . . . . . . 45 4.5 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 49 5.1 ChatGPT ͔Β GPT-4 ͕ϦϦʔε . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.2 ςετϓϩηε͝ͱͷ׆༻ΞΠσΞ . . . . . . . . . . . . . . . . . . . . . . . . . . 50 5.3 ৼΓฦΓͰͷ׆༻ΞΠσΞ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 v
  3. ໨࣍ 5.4 ࣮ફʂ ެࣜαΠτͷ͓஌ΒͤνΣοΫ . . . . . .

    . . . . . . . . . . . . . . . . . . 54 5.5 ࠓޙͷల๬ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 ஶऀ঺հ 59 vi
  4. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛ ͳͦ͘͏ 1.1 ͸͡Ίʹ ຊষʹڵຯΛ࣋ͨΕͨͱݴ͏͜ͱ͸ɺ͓ͦΒ͘೔ʑۀ຿΍झຯͰେྔͷιʔείʔυʹ೴Λম͔Ε

    ͍ͯΔํͱࢥ͍·͢ɻ ࢲ͕ܞΘ͍ͬͯΔڞ༡ܕεϙʔπϕοςΟϯάαʔϏε TIPSTAR *1 Ͱ͸ɺօ͞Μͱಉ༷ʹ೔ʑ ਺ઍ͔Β਺ສͷίʔυΛॻ͍ͨΓϨϏϡʔͨ͠Γ (ॻ͖௚ͨ͠Γ) ͓ͯ͠ΓɺͦͷதͰͷେ͖ͳ՝୊ ͱ࣮ͯ͠૷࿙Ε΍ϨϏϡʔ࿙Ε͕͋Γ·͢ɻ ࠷ۙͰ͸ਂ૚ֶशͷൃలʹ൐ͬͯࣗಈͰϓϩμΫτίʔυ͕ग़ͯ͘Δ & ϨϏϡʔͯ͘͠ΕΔະདྷ ΋ඵಡΈ͔ɺͱ͍͏ྲྀΕ΋͋Γ·͕͢ɺґવͱͯ͠ʮͰ͖ΔͳΒ࣮֬ʹ͜͜͸ݟಀͨ͘͠ͳ͍ʯͱ͔ ʮ͜Μͳ໌Β͔ͳ͏͔ͬΓϛε͸ͬ͞͞ͱؾ෇͍ͯ΄͍͠ʯΈ͍ͨͳ͜ͱ͸͋Δͱࢥ͍·͢ɻ ͨͱ͑͹࣍ͷϖʔδͷ human.go ΛϨϏϡʔͯ͠Έ·͠ΐ͏ɻ *1 https://about.tipstar.com/ MIXI ͕ӡӦ͢ΔɺڝྠɾPIST6ɾΦʔτϨʔεͷωοτ౤ථΛجຊແྉͰָ͠Ή͜ͱ ͕Ͱ͖ΔαʔϏεͰ͢ 1
  5. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.1 ͸͡Ίʹ Ϧετ 1.1:

    human.go 1: package main 2: 3: import ( 4: "errors" 5: "fmt" 6: "log" 7: ) 8: 9: type Human struct { 10: Name string 11: Age int 12: } 13: 14: func (m *Human) IsValid() error { 15: if m.Name == "" { 16: return errors.New("Human has no Name") 17: } 18: return nil 19: } 20: 21: func (m *Human) Profile() (string, error) { 22: if err := m.IsValid(); err != nil { 23: log.Printf("[err] Human Profile raise err: since %v", err) 24: return "", nil // error handling ... 25: } 26: return fmt.Sprintf("Name: %s, Age: %d", m.Name, m.Age), nil 27: } 28: 29: func main() { 30: me := Human{Name: "Meguru", Age: 25} 31: profile, err := me.Profile() 32: if err != nil { 33: log.Fatal(err) 34: } 35: fmt.Printf("[%s] Hello, World\n", profile) 36: } ϩάΛग़ͯ҆͠৺ͯ͠͠·ͬͨͷ͔ɺProfile ؔ਺ͷ L.23 Ͱൃੜͨ͠ΤϥʔΛݟա͍ͯ͝͠· ͢Ͷɻ͜ͷ··Ͱ͸ main ؔ਺Ͱҙਤ͠ͳ͍ Hello, World ͕දࣔ͞Εͯ͠·͍·͢ɻ ຊষͰ͸͜ͷΑ͏ͳϨϏϡʔͷۤ͠ΈΛগ͠Ͱ΋ղফ͢Δɺ੩తղੳπʔϧͷ࡞Γํʹ͍ͭͯ঺հ ͠·͢ɻ 2
  6. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.2 Go Analysis Λ࢝ΊΔ

    1.2 Go Analysis Λ࢝ΊΔ ੩తղੳͱ͸ϓϩάϥϜͷίʔυΛίʔυͱͯ͠ (࣮ߦ͢Δ͜ͱͳ͘) ݕূ͢Δ͜ͱΛࢦ͠ɺಘΒ Εͨղੳ݁ՌΛར༻͢Δ͜ͱͰҙਤ͠ͳ͍ಈ࡞Λݕ஌Ͱ͖·͢ɻ Go ͷ੩తղੳͷͨΊඪ४ύοέʔδͱͯ͠͸ Go Analysis *2 ͕͋Γɺ͜ͷύοέʔδΛ༻͍ͯ ੩తղੳͷॲཧΛڞ௨Խ͢Δ͜ͱͰޮ཰తʹ੩తղੳπʔϧΛ࣮૷Ͱ͖·͢ɻ ·ͨઌਓͨͪ΋ଟ͘ͷπʔϧΛ࣮૷͓ͯ͠Γɺͨͱ͑͹ GoStaticAnalysis *3 ϦϙδτϦʹ͸ଟ ͘ͷ੩తղੳπʔϧ͕ଘࡏ͢ΔͨΊɺ͜ΕΒΛࢀߟʹ͢Δ͜ͱ΋Ͱ͖·͢ɻ ʢࠓճ͸͔̍Β࡞ͬͯΈ ·͢ʣ ݸਓతͳܦݧͰ͸͋Γ·͕͢ɺಛʹ Go Analysis Λ༻͍ͯ੩తղੳπʔϧΛ࣮૷͢ΔͨΊͷύλʔ ϯͱͯ͠ɺҎԼͷΑ͏ͳྲྀΕͰ࣮૷͢Δ͜ͱ͕ଟ͍Ͱ͢ɻ 1. ҙਤ͠ͳ͍ίʔυͷαϯϓϧΛ࡞Δ 2. ͦͷαϯϓϧίʔυΛதؒදݱͱݺ͹ΕΔ੩తղੳʹศརͳܗʹม׵ͯ͠ɺҙਤ͠ͳ͍ڍಈ͕ ͲͷΑ͏ͳঢ়ଶʹΑͬͯҾ͖ى͜͞ΕΔͷ͔Λௐ΂Δ 3. αϯϓϧίʔυͷҙਤ͠ͳ͍෦෼ʹ͍ͭͯܯࠂΛൃੜ͢ΔΑ͏ʹ੩తղੳπʔϧΛ࣮૷͢Δ 4. ࣮૷্ؾ෇͍ͨ͜ͱͳͲΛࢀߟʹɺαϯϓϧͷ௥Ճ + πʔϧͷϦϑΝΫλϦϯάΛߦ͏ ࠓճ͸ 1. ͷαϯϓϧͱͯ͠ human.go Λ༻͍͍͖ͯɺ2., 3. ʹ͍ͭͯΛ͜ͷޙͷઅͰ঺հ͍ͯ͠ ͖·͢ɻ Go ͷίʔυΛதؒදݱͰಡΈ௚ͯ͠ΈΔ தؒදݱͱ͸ Go ͷιʔείʔυΛ෼ੳ͠΍ͨ͘͢͠΋ͷͰ͋Γɺ۩ମతʹ͸ ந৅ߏจ໦ (AST, Abstract Syntax Tree) ͱ੩త୯Ұ୅ೖܗࣜ (SSA, Static Single Assignment) ͳͲ͕͋Γ·͢ɻ ҎԼʹͦΕͧΕͷදݱͱ Go ͷίʔυΛಡΈࠐΜͰͦΕͧΕͷதؒදݱͰग़ྗͯ͘͠ΕΔ؆қεΫ ϦϓτΛ঺հ͍͖ͯ͠·͢ɻ ந৅ߏจ໦ (AST) ந৅ߏจ໦ͱ͸ʮTreeʯͱ໊લʹ͋ΔΑ͏ʹɺϓϩάϥϜͳͲͷίʔυΛ໦ߏ଄ʹஔ͖׵͑ͨ΋ͷ ʹͳΓ·͢ɻͨͱ͑͹ 1 + 2 ͱ͍ͬͨ଍͠ࢉΛந৅ߏจ໦্Ͱද͢ͱ • Ճࢉԋࢉࢠ + Λ෼ذ఺ • ࠨӈʹ஋Ͱ͋Δ 1 , 2 Λ༿ ͱ͢ΔΑ͏ͳਫ෼ࢠͷΑ͏ͳΠϝʔδ͕ߟ͑ΒΕ·͢ɻ *2 https://godoc.org/golang.org/x/tools/go/analysis *3 https://github.com/gostaticanalysis 3
  7. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.2 Go Analysis Λ࢝ΊΔ

    ਤ 1.1: 1 + 2 ͷந৅ߏจ໦ Go ͷίʔυΛந৅ߏจ໦ʹ෼ղ͢Δʹ͸ҎԼͷΑ͏ͳαϯϓϧίʔυΛར༻Ͱ͖·͢ɻ Ϧετ 1.2: cmd/astdump/main.go 1: package main 2: 3: import ( 4: "flag" 5: "go/ast" 6: "go/parser" 7: "go/token" 8: "log" 9: ) 10: 11: func main() { 12: s := flag.String("f", "human.go", "file-path") 13: flag.Parse() 14: 15: fset := token.NewFileSet() 16: f, err := parser.ParseFile(fset, *s, nil, 0) 17: if err != nil { 18: log.Fatalf("Failed to parse file: cause %v", err) 19: } 20: if err := ast.Print(fset, f); err != nil { 21: log.Fatalf("Print failed: cause %v", err) 22: } 23: } go run ./cmd/astdump -f human.go Ͱग़ྗΛಘΒΕɺͦͷ͏ͪͷ Profile ؔ਺ͷҰ෦ΛऔΓ ग़͢ͱ࣍ͷΑ͏ʹͳΓ·͢ɻ ಛʹ L.366 ͷ *ast.ReturnStmt ͸ human.go ʹ͓͚Δ return "", nil // error handlin g ... ͷ෦෼ʹ֘౰͠·͢ɻ 4
  8. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.2 Go Analysis Λ࢝ΊΔ

    astdump.log 226 . . 3: *ast.FuncDecl { 283 . . . Body: *ast.BlockStmt { 284 . . . . Lbrace: human.go:21:43 285 . . . . List: []ast.Stmt (len = 2) { 286 . . . . . 0: *ast.IfStmt { 287 . . . . . . If: human.go:22:2 321 . . . . . . Cond: *ast.BinaryExpr { 322 . . . . . . . X: *ast.Ident { 323 . . . . . . . . NamePos: human.go:22:25 324 . . . . . . . . Name: "err" 325 . . . . . . . . Obj: *(obj @ 293) 326 . . . . . . . } 327 . . . . . . . OpPos: human.go:22:29 328 . . . . . . . Op: != 329 . . . . . . . Y: *ast.Ident { 330 . . . . . . . . NamePos: human.go:22:32 331 . . . . . . . . Name: "nil" 332 . . . . . . . } 333 . . . . . . } 334 . . . . . . Body: *ast.BlockStmt { 335 . . . . . . . Lbrace: human.go:22:36 336 . . . . . . . List: []ast.Stmt (len = 2) { 337 . . . . . . . . 0: *ast.ExprStmt { 338 . . . . . . . . . X: *ast.CallExpr { 339 . . . . . . . . . . Fun: *ast.SelectorExpr { 340 . . . . . . . . . . . X: *ast.Ident { 341 . . . . . . . . . . . . NamePos: human.go:23:3 342 . . . . . . . . . . . . Name: "log" 343 . . . . . . . . . . . } 344 . . . . . . . . . . . Sel: *ast.Ident { 345 . . . . . . . . . . . . NamePos: human.go:23:7 346 . . . . . . . . . . . . Name: "Printf" 347 . . . . . . . . . . . } 348 . . . . . . . . . . } 365 . . . . . . . . } 366 . . . . . . . . 1: *ast.ReturnStmt { 367 . . . . . . . . . Return: human.go:24:3 368 . . . . . . . . . Results: []ast.Expr (len = 2) { 369 . . . . . . . . . . 0: *ast.BasicLit { 370 . . . . . . . . . . . ValuePos: human.go:24:10 371 . . . . . . . . . . . Kind: STRING 372 . . . . . . . . . . . Value: "\"\"" 373 . . . . . . . . . . } 374 . . . . . . . . . . 1: *ast.Ident { 375 . . . . . . . . . . . NamePos: human.go:24:14 376 . . . . . . . . . . . Name: "nil" 377 . . . . . . . . . . } 440 . . } 5
  9. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.2 Go Analysis Λ࢝ΊΔ

    ੩త୯Ұ୅ೖܗࣜ (SSA) ੩త୯Ұ୅ೖܗࣜͱ͸ղੳ͢Δίʔυ্Ͱม਺ఆ͕ٛҰҙʹͳΔΑ͏ͳ (ಉ໊͡લͷม਺Λڐ͞ͳ ͍) ܗͷதؒදݱͰ͢ɻ͜ͷදݱΛར༻͢Δͱɺಉ໊͡લͷม਺ʹ஋Λ্ॻ͖ͯ͠͠·ͬͨ͜ͱΛݕ ஌ͨ͠Γɺ͋Δ஋͕ͲͷܕͰѻΘΕ͍ͯΔ͔Λௐࠪͨ͠Γɺͱ͍ͬͨ͜ͱ͕༰қʹͳΓ·͢ɻ ιʔείʔυΛ SSA ΁ม׵͢Δʹ͸ golang.org/x/tools/cmd/ssadump Λར༻Ͱ͖·͢ɻ sample.sh go build -o ./bin/ssadump golang.org/x/tools/cmd/ssadump ./bin/ssadump -build=F ./human.go ग़ྗͷ͏ͪ Profile ؔ਺ͷΈΛऔΓग़͢ͱ࣍ͷΑ͏ʹͳΓ·͢ɻ ಛʹ return "":string, nil:error ͸ human.go ʹ͓͚Δ return "", nil // error han dling ... ͷ෦෼ʹ֘౰͠·͢ɻ ssadump.log func (m *Human) Profile() (string, error): 0: entry P:0 S:2 t0 = (*Human).IsValid(m) error t1 = t0 != nil:error bool if t1 goto 1 else 2 1: if.then P:1 S:0 t2 = new [1]any (varargs) *[1]any t3 = &t2[0:int] *any t4 = change interface any <- error (t0) any *t3 = t4 t5 = slice t2[:] []any t6 = log.Printf("[err] Humun Profi...":string, t5...) () return "":string, nil:error 2: if.done P:1 S:0 t7 = &m.Name [#0] *string t8 = *t7 string t9 = &m.Age [#1] *int t10 = *t9 int t11 = new [2]any (varargs) *[2]any t12 = &t11[0:int] *any t13 = make any <- string (t8) any *t12 = t13 t14 = &t11[1:int] *any t15 = make any <- int (t10) any *t14 = t15 t16 = slice t11[:] []any t17 = fmt.Sprintf("Name: %s, Age: %d":string, t16...) string return t17, nil:error 6
  10. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.3 ੩తղੳπʔϧΛॻ͍ͯΈΔ 1.3 ੩తղੳπʔϧΛॻ͍ͯΈΔ

    ੩తղੳπʔϧΛ࣮૷͢ΔͨΊͷςϯϓϨʔτͱͯ͠ skeleton *4 ͕͋Γ·͢ɻ skeleton Λར༻ͨ͠৔߹ͷ੩తղੳπʔϧͷςϯϓϨʔτ͸ҎԼͷΑ͏ʹͳΓ·͢ɻ ·ͣ͸ samplelinter/testdata/src/a/a.go ΁αϯϓϧίʔυ (hello.go) Λςετͱͯ͠഑ ஔͯ͠ɺςετʹ߹֨͢ΔΑ͏ίʔυΛΰϦΰϦॻ͍͍͖ͯ·͠ΐ͏ɻ skeleton-tree . ᵋᴷᴷ samplelinter ᵓᴷᴷ cmd ᴹ ᵋᴷᴷ samplelinter ᴹ ᵋᴷᴷ main.go ᵓᴷᴷ go.mod ᵓᴷᴷ samplelinter.go // ͜͜ʹίʔυΛॻ͘ ᵓᴷᴷ samplelinter_test.go ᵋᴷᴷ testdata ᵋᴷᴷ src ᵋᴷᴷ a ᵓᴷᴷ a.go // human.go Α͏ͳαϯϓϧσʔλΛ֨ೲ͢Δ ᵋᴷᴷ go.mod human.go ͷΈͷέʔεΛߟ͑Ε͹ɺҎԼͷΑ͏ͳ࣮૷Λ͢Ε͹Αͦ͞͏Ͱ͢ *5 *6 ɻ Ϧετ 1.3: samplelinter/samplelinter.go 1: package samplelinter 2: 3: import ( 4: "go/token" 5: "go/types" 6: "strings" 7: 8: "github.com/gostaticanalysis/comment" 9: "github.com/gostaticanalysis/comment/passes/commentmap" 10: "golang.org/x/tools/go/analysis" 11: "golang.org/x/tools/go/analysis/passes/buildssa" 12: "golang.org/x/tools/go/ssa" 13: ) *4 https://github.com/gostaticanalysis/skeleton *5 ࣮ࡍ͸ΑΓଟ͘ͷαϯϓϧέʔεΛߟ͑ͨΓɺࣗಈੜ੒ͷϑΝΠϧΛݟಀͨ͠Γͱ͍ͬͨϓϩδΣΫτ͝ͱͷࡉ͔ͳઃ ఆΛ଍͍ͯ͘͠ඞཁ͕͋Γ·͢ɻ *6 ࠓճͷΑ͏ͳΤϥʔϋϯυϦϯάʹ͍ͭͯ͸ https://github.com/gostaticanalysis/nilerr ͷΑ͏ͳطଘͷπʔϧΛ ར༻͢Δ͜ͱ΋ՄೳͰ͢ɻͰ͕࣮͢͸ࠓճͷ human.go ͷΑ͏ͳέʔε͸ nilerr ͩͱݕ஌͠ͳ͍έʔεͩͬͨΓ͠· ͢ (ࠓճͷٕज़ॻయΛॻ͘ʹࢸͬͨಈػ)ɻ 7
  11. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.3 ੩తղੳπʔϧΛॻ͍ͯΈΔ 14: 15:

    const ( 16: doc = "samplelinter is checker for missing error handling" 17: nilErr = "nil:error" 18: ) 19: 20: var Analyzer = &analysis.Analyzer{ 21: Name: "samplelinter", 22: Doc: doc, 23: Run: run, 24: Requires: []*analysis.Analyzer{ 25: buildssa.Analyzer, 26: commentmap.Analyzer, 27: }, 28: } 29: 30: var errorType = types.Universe.Lookup("error").Type() 31: 32: func run(pass *analysis.Pass) (any, error) { 33: s := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) 34: cmaps := pass.ResultOf[commentmap.Analyzer].(comment.Maps) 35: 36: // ର৅ͷίʔυ಺ͷؔ਺ʹ͍ͭͯ෼ੳ 37: for _, f := range s.SrcFuncs { 38: fileName := pass.Fset.Position(f.Pos()).Filename 39: // ςετͷϑΝΠϧ͸আ֎ 40: if strings.HasSuffix(fileName, "_test.go") { 41: continue 42: } 43: // error ܕΛฦ͞ͳ͍ؔ਺͸আ֎ 44: if !hasErrInResults(f.Signature.Results()) { 45: continue 46: } 47: for _, b := range f.Blocks { 48: for _, instr := range b.Instrs { 49: switch instr := instr.(type) { 50: // if err != nll Λݕ஌ 51: case *ssa.BinOp: 52: if isNilErrorCheck(instr) { 53: retBlock := instr.Block().Succs[0] 54: // ؼΓ஋ͷதʹ err (not nil) ͕ 55: // ೖ͍ͬͯͳ͚Ε͹ܯࠂ 56: checkErrorReturnValue( 57: retBlock, pass, cmaps, 58: ) 59: } 60: } 61: } 62: } 63: } 64: return nil, nil 65: } 66: 67: func isNilErrorCheck(ifstmt *ssa.BinOp) bool { 8
  12. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.3 ੩తղੳπʔϧΛॻ͍ͯΈΔ 68: if

    ifstmt.Op != token.NEQ { 69: return false 70: } 71: // ‘if err != nil‘ or ‘if nil != err‘ Λݕ஌ 72: return (isTypeError(ifstmt.Y.Type()) && ifstmt.X.Name() == nilErr) || 73: (isTypeError(ifstmt.X.Type()) && ifstmt.Y.Name() == nilErr) 74: } 75: 76: func isTypeError(t types.Type) bool { 77: if _, ok := t.Underlying().(*types.Interface); !ok { 78: return false 79: } 80: return types.Identical(t, errorType) 81: } 82: 83: func checkErrorReturnValue( 84: b *ssa.BasicBlock, pass *analysis.Pass, cmaps comment.Maps, 85: ) { 86: for _, instr := range b.Instrs { 87: ret, ok := instr.(*ssa.Return) 88: if !ok { 89: continue 90: } 91: // ‘//lint:ignore samplelinter xxx‘ ίϝϯτΛແࢹ͢Δ 92: if cmaps.IgnorePos(ret.Pos(), "samplelinter") { 93: continue 94: } 95: hasErr := false 96: for _, v := range ret.Results { 97: if isTypeError(v.Type()) && v.Name() != nilErr { 98: hasErr = true 99: } 100: } 101: if len(ret.Results) != 0 && !hasErr { 102: pass.Reportf( 103: ret.Pos(), 104: "[samplelinter] return err should be included "+ 105: "in this return stmt."+ 106: "you seem to be ignoring error handling", 107: ) 108: } 109: } 110: } 111: 112: func hasErrInResults(rets *types.Tuple) bool { 113: for i := 0; i < rets.Len(); i++ { 114: ret := rets.At(i) 115: if ret.Type() == errorType { 116: return true 117: } 118: } 119: return false 120: } 9
  13. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.3 ੩తղੳπʔϧΛॻ͍ͯΈΔ ϓϩδΣΫτʹಋೖ͢Δ ͍͟੩తղੳπʔϧΛ࡞ͬͨͱ͜ΖͰɺ࣮ࡍʹϓϩμΫτίʔυ΁ద༻Ͱ͖ͳ͚Ε͹͔ͤͬ͘ͷ౒

    ྗ͕ແବʹͳͬͯ͠·͍·͢ɻ TIPSTAR Ͱ͸ɺ࡞੒ͨ͠੩తղੳπʔϧ͸ϓϩδΣΫτ಺ʹ഑ஔͯ͠ CI ্Ͱ࣮ߦ͞ΕΔΑ͏ʹ ઃఆͯ͠೔ʑͷίʔυͷ҆৺ɾ҆શΛक͍ͬͯ·͢ɻ ۩ମతʹ͸࣍ͷΑ͏ͳσΟϨΫτϦߏ଄ͷ഑ஔΛߦ͍ɺ࡞੒ͨ͠੩తղੳπʔϧΛ myanalyzer/ main.go ΁഑ஔͯ͠όΠφϦʹϏϧυ *7 ͢Δ͜ͱͰར༻͍ͯ͠·͢ɻ app-dir ./app ᵓᴷᴷ Makefile ᵓᴷᴷ README.md ᵓᴷᴷ bin ᴹ ᵋᴷᴷ myanalyzer ᵓᴷᴷ go.mod ᵓᴷᴷ go.sum ᵓᴷᴷ internal ᵋᴷᴷ tools ᵋᴷᴷ myanalyzer ᵓᴷᴷ samplelinter/ ᵓᴷᴷ xxxlinter/ ᵋᴷᴷ main.go Ϧετ 1.4: tools/mylinters/main.go 1: package main 2: 3: import ( 4: "golang.org/x/tools/go/analysis/multichecker" 5: 6: "github.com/project/app/tools/myanalyzer/samplelinter" 7: "github.com/project/app/tools/myanalyzer/xxxlinter" 8: ) 9: 10: func main() { 11: multichecker.Main( 12: samplelinetr.Analyzer, 13: xxxlinter.Analyzer, 14: ) 15: } *7 go build -o bin/mylinters tools/myanalyzer/main.go 10
  14. ୈ 1 ষ ੩తղੳπʔϧͰ Go ͷ͏͔ͬΓϛεΛͳͦ͘͏ 1.4 ͓ΘΓʹ 1.4 ͓ΘΓʹ

    ຊষͰ͸ Go ͷ੩తղੳΛ௨ͯ͡͏͔ͬΓͳϛεʹؾ෇ͨ͘Ίͷ͘͠ΈΛ঺հ͠·ͨ͠ɻ೔ʑͷ։ ൃ଎౓Λۤ͠·ͣʹՃ଎ͤ͞Δʹ͸ɺ։ൃऀ͕ੜΈग़͍ͨ͠Ձ஋ͷϝΠϯϩδοΫʹूதͰ͖Δ؀ڥ ͮ͘ΓΛࢧԉ͢Δ͜ͱ͕த௕ظతʹ͸༗ޮͰ͢ɻ ౰ͨΓલʹΘ͔Δࡉ͔͍࡞ۀ͸ AI ͷΈͳΒͣɺ͜ͷΑ͏ͳπʔϧΛ׆༻͢Δ͜ͱͰͲΜͲΜࣗಈ Խ͍͖ͯ͠·͠ΐ͏ɻ 11
  15. ୈ 2 ষ ୳๚ STM at Haskell ϓϩάϥϛϯάݴޠͷओཁͳػೳͷҰͭʹฒྻɾฒߦϓϩάϥϛϯάͷͨΊͷػೳ͕͋Γ·͢ɻ ຊߘͰ͸ɺฒྻɾฒߦϓϩάϥϛϯάͷͨΊͷػೳͱͯ͠ Haskell

    ʹ͋Δ Software Transactional MemoryʢSTMʣʹ͍ͭͯɺOSS Ͱͷར༻ͷ͞ΕํΛަ͑ͳ͕Β঺հ͠·͢ɻ஫ҙ఺ͱͯ͠ɺSTM ͸ Haskell ͷσϑΝΫτελϯμʔυͳॲཧܥͰ͋Δ GHC Ͱ࣮૷͞Εͨػೳʢਖ਼֬ʹ͸ GHC 6.4 ͔ΒʣͰɺҎ߱ Haskell ͱݴͬͨ৔߹͸҉໧తʹ GHC Λࢦ͠·͢ɻ·ͨɺຊߘͰ͸ STM ͷ಺෦࣮ ૷΍ݪ࿦จʹ͍ͭͯ͸ಛʹݴٴͤͣɺར఺΍࢖͍ํɾ࢖ΘΕํͳͲʹ͍ͭͯ঺հ͢Δɺൺֱత؆୯ͳ هࣄͰ͢ɻ 2.1 Software Transactional Memory Software Transactional Memory ͸ɺฒྻɾฒߦϓϩάϥϛϯάͷࡍʹϦιʔεΛڞ༗͢ΔͨΊ ͷ͘͠ΈͷҰͭͰ͢ɻσʔλϕʔεʹ͋ΔΑ͏ͳෆՄ෼ͳॲཧΛ࣮ߦ͢ΔͨΊʹ࢖͏τϥϯβΫγϣ ϯͷ͘͠ΈΛɺϝϞϦϦιʔεͰ࣮ݱ͠·͢ɻ ͨͱ͑͹ɺෳ਺εϨουͰڞ༗͍ͯ͠Δม਺ΛಡΈࠐΜͰߋ৽͍ͨ͜͠ͱ͕͠͹͠͹͋Δͱࢥ͍· ͢ɻଟ͘ͷ৔߹ɺഉଞ੍ޚΛར༻ͯ͠ɺม਺ΛಡΈࠐΜͰߋ৽ͯ͠อଘ͢ΔؒΛෆՄ෼ͳॲཧͱͯ͠ ࣮૷͢Δͱࢥ͍·͢ɿ // ͜Ε͸ Go Ͱͷ࣮૷ func (ConcurrentMap cm) insert(k, v string) bool { cm.mu.lock() defer cm.mu.unlock() if _, ok := cm.m[k]; ok { return false } cm.m[k] = v return true } ͜Ε͸ͨͩɺ࿈૝഑ྻͷܕʹ஋Λొ࿥͍ͯ͠Δ͚ͩͷؔ਺Ͱ͢ɻͨͩ͠ɺϚϧνεϨουʹ࣮ߦ͞ 13
  16. ୈ 2 ষ ୳๚ STM at Haskell 2.1 Software Transactional

    Memory Εͯ΋ྑ͍Α͏ʹɺlock() ͱ unlock() Ͱഉଞ੍ޚΛ͍ͯ͠·͢ɻରͯ͠ STM ͸ɺ͜ͷΑ͏ͳෆ Մ෼ͳॲཧΛ࣍ͷΑ͏ʹॻ͖·͢ɿ type ConcurrentMap = TVar (Map String String) insert :: ConcurrentMap -> String -> String -> STM Bool insert cm k v = do m <- readTVar cm if Map.member k m then return False else do modifyTVar cm $ Map.insert k v return True STM ͳڞ༗Ϧιʔεʹ͸ TVar a ܕΛ࢖͍·͢ɻ࣮ࡍʹѻ͏ܕ͕ a ͷํͰɺࠓճ͸ Map String String ͱݴ͏γϯϓϧͳ࿈૝഑ྻܕΛ࢖͍ͬͯ·͢ɻTVar a ܕͷ஋͔Β a ܕͷ஋ΛऔΓग़͢ͷʹ ͸ readTVar ؔ਺Λ࢖͍ɺ্ॻ͖͢Δ৔߹ʹ͸ writeTVar ؔ਺Λɺߋ৽͢Δ৔߹ʹ͸ modifyTVar ؔ਺Λ࢖͍·͢ɿ readTVar :: TVar a -> STM a writeTVar :: TVar a -> a -> STM () modifyTVar :: TVar a -> (a -> a) -> STM () औΓग़ͨ͠͸ͣͳͷʹ໭Γ஋ͷܕ͕ STM a ʹͳ͍ͬͯ·͢Ͷɻ͜ͷ STM ͱݴ͏෦෼͕ɺෆՄ෼ͳ ॲཧͰ͋Δ͜ͱΛදݱ͍ͯ͠·͢ɻSTM ͸ Monad ܕΫϥεͷΠϯελϯεͰ͢ͷͰɺDo ه๏ʹΑͬ ͯ؆୯ʹ߹੒ՄೳͰ͢ɻ ࣮͸ɺinsert ؔ਺ʹҾ਺Λ༩͑Δ͚ͩͰ͸ɺॲཧ͕࣮ߦ͞Ε·ͤΜɻSTM a ͳෆՄ෼ͳॲཧΛ࣮ ߦ͢Δʹ͸ atomically ͱ͍͏ؔ਺Λ࢖͍·͢ɻ atomically :: STM a -> IO a -- insert ͸࣍ͷΑ͏ʹ࢖͏ atomically $ insert cm k v atomically ʹΑͬͯෆՄ෼ͳॲཧ͕࣮ߦ͞Ε͍ͯΔ్தͰɺڞ༗Ϧιʔεʹߋ৽͕͋ͬͨ৔߹ ͸ɺͳΜͱෆՄ෼ͳॲཧΛ࠷ॳ͔Β΍Γ௚͠·͢ɻinsert ؔ਺Ͱ͋Ε͹ɺreadTVar Λͯ͠ modif yTVar ͢ΔؒʹɺผͷεϨου͔Β cm ͕ߋ৽͞Εͨ৔߹Ͱ͢ɻ͜ͷΑ͏ʹෆՄ෼ͳॲཧΛࣗಈͰ΍ Γ௚ͯ͘͠ΕΔͨΊɺഉଞ੍ޚΛ͢Δඞཁ͕ͳ͍ͱݴ͏Θ͚Ͱ͢ɻ 14
  17. ୈ 2 ষ ୳๚ STM at Haskell 2.1 Software Transactional

    Memory ͪͳΈʹɺHaskell Ͱͷฒߦɾฒྻϓϩάϥϛϯάʹؔͯ͠͸ɺ ʮHaskell ʹΑΔฒߦɾฒྻϓϩά ϥϛϯάʯ ʢݪஶ͸ʮParallel and Concurrent Programming in Haskellʯ ʣ *1 ͱ͍͏ྑॻ͕͋Γɺͦ ͜Ͱ͸ୈ 10 ষͰҰষؙʑΛ࢖ͬͯ঺հ͞Ε͍ͯ·͢ɻ2014 ೥ग़൛ʢݪஶͷ৔߹͸ 2013 ೥ʣͱগ͠ ݹ͍ॻ੶Ͱ͕͢ɺຊߘΛಡΜͰڵຯΛ࣋ͬͨํ͸ͥͻɺΑΓৄ͘͠ॻ͍ͯ͋ΔʮHaskell ʹΑΔฒߦɾ ฒྻϓϩάϥϛϯάʯΛಡΜͰΈ͍ͯͩ͘͞ɻ stm ύοέʔδ ઌड़ͨ͠ܕ΍ؔ਺ɺ ʮHaskell ʹΑΔฒߦɾฒྻϓϩάϥϛϯάʯͰ঺հ͞Ε͍ͯΔ͍͔ͭ͘ͷ࣮૷ ύλʔϯ͸ stm ύοέʔδ*2 ʹ͋Γ·͢ɻͨͱ͑͹ɺTVar a ܕͷ΄͔ʹ࣍ͷΑ͏ͳΑΓϦονͳ σʔλߏ଄͕͢Ͱʹఆٛ͞Ε͍ͯ·͢ɿ • TChan a ܕɿແ੍ݶ௕ͷ FIFO νϟϯωϧΛදͨ͠ܕ • TQueue a ܕ : TChan ΑΓߴ଎͕ͩෳ੡ෆՄೳͳνϟϯωϧ • TBQueue a ܕ : TQueue ʹ௕͞ͷ্ݶΛઃ͚ͨ΋ͷ ޙड़͢Δ OSS Ͱ͸ɺ͜ΕΒͷܕΛར༻ͯ͠ɺ͞·͟·ͳڞ༗ϦιʔεΛѻ͏͘͠ΈΛ࣮૷͍ͯ͠ ·͢ɻͪͳΈʹɺຊߘͰ͸ࣥච࣌఺ͷ stm ύοέʔδͷ࠷৽όʔδϣϯͰ͋Δ 2.5.1.0 Λલఏʹ͠ ·͢ɻ Haskell Ͱฒߦϓϩάϥϛϯά Haskell ͸ɺGo ͷ goroutine ͷΑ͏ͳܰྔεϨουʢάϦʔϯεϨουʣΛ࣮૷͍ͯ͠ΔͨΊɺൺ ֱత؆୯ʹฒߦϓϩάϥϛϯά͕ՄೳͰ͢ɻผͷεϨουͰ IO ΞΫγϣϯΛ࣮ߦ͢Δʹ͸ forkIO ͱݴ͏ؔ਺Λ࢖͍·͢ɿ forkIO :: IO () -> IO ThreadId ThreadId ͸໊લͷ௨Γɺ࡞੒͞ΕͨεϨουͷ ID Ͱ͢ɻ·ͨɺ࡞੒ͨ͠εϨουͷऴྃΛ଴ͬ ͨΓɺྫ֎ॲཧΛ͏·͘΍ͬͨΓ͢ΔͨΊͷ async ύοέʔδ*3 ͱݴ͏ͷ͕͋Γ·͢ɻ data Async a async :: IO a -> IO (Async a) wait :: Async a -> IO a cancel :: Async a -> IO () *1 https://www.oreilly.co.jp/books/9784873116891/ *2 https://hackage.haskell.org/package/stm *3 https://hackage.haskell.org/package/async 15
  18. ୈ 2 ষ ୳๚ STM at Haskell 2.2 STM ͷ࢖ΘΕํ

    Async a ܕ͸ɺผεϨουͰ IO ΞΫγϣϯΛ࣮ߦͨ݁͠Ռɺa ܕͷ஋ΛಘΔͱݴ͏ͷΛදͨ͠ܕ Ͱ͢ɻasync ؔ਺ʹΑͬͯผεϨου͕࡞੒͞Εɺ࡞੒ݩ͸ wait ͰॲཧͷऴྃΛ଴ͬͨΓɺcance l Ͱڧ੍ऴྃͨ͠ΓͰ͖·͢ɻ ͪͳΈʹɺ಺෦తʹ͸ STM Λར༻ͯ͠ɺ͜ͷΑ͏ͳৼΔ෣͍Λදݱ͍ͯ͠·͢ɻ 2.2 STM ͷ࢖ΘΕํ ͔͜͜Β͸ɺOSS Ͱͷ stm ύοέʔδͷ࢖͍ํΛྫʹͯ͠ɺSTM ͷศརͳ࢖͍ํΛ঺հ͠·͢ɻ MIXI Git Challenge ͷείΞαʔό MIXI Ͱ͸ɺGit Challenge ͱ͍͏ֶੜ޲͚ڝٕܕΠϕϯτΛఆظతʹ։࠵͍ͯ͠·͢*4 ɻGit Λ ࢖ͬͯղ͘ڝٕϓϩάϥϛϯάͷΑ͏ͳ΋ͷͰ͢ɻ͜Εͷࣗಈ࠾఺Λͨ͠Γɺ ੒੷ΛӾཡͰ͖Δ Web ϖʔδΛฦͨ͠Γ͢ΔείΞαʔόΛ Haskell Ͱࣗ࡞͍ͯ͠·͢*5 ɻ ͜ͷείΞαʔόͰ͸ɺࣗಈ࠾఺Λඇಉظʹߦ͏αʔό෦෼Ͱ STM Λར༻͍ͯ͠·͢ɻαʔό ͸ɺ࣮ࡍʹॲཧΛߦ͏ Worker Λෳ਺୆؅ཧ͓ͯ͠Γɺͦͷ Worker ͷ؅ཧ৘ใΛ STM ʹ͍ͯ͠ ·͢ɿ src/Git/Plantation/Job/Worker.hs ΑΓൈਮ type Workers = TVar (Map Id (Maybe Worker)) newtype Id = Id Int32 deriving newtype (Show, Eq, Ord, Num, Binary, FromJSON, ToJSON, Display) type Worker = Record ’[ "id" >: Id , "working" >: Bool , "conn" >: WS.Connection ] Id ܕͱ Worker ܕ͸ͦΕͧΕɺ Worker ͷ ID ͱ Worker ࣗମΛදͨ͠ܕͰ͢ɻͦΕͧΕͪΐͬ ͱ Haskell ͷςΫχΧϧͳܕͷ͘͠ΈΛར༻͍ͯ͠·͕͢ɺͳΜͱͳ͘ಡΊΔ͸ͣͰ͢ͷͰɺ͜͜Ͱ ͸ׂѪ͠·͢*6 ɻαʔόͱ Worker ͸ɺ Worker ͔Βͷ WebSocket ͰίωΫγϣϯΛհͯ͠௨৴Λ ͠·͢ɻͦͷίωΫγϣϯΛදͨ͠ܕ͕ WS.Connection Ͱ͢*7 ɻͦͯ͠ɺMap Id (Maybe Worke *4 ίϩφՒҎ߱ɺࣥච࣌఺·Ͱ͸গͳ͘ͱ΋։࠵͍ͯ͠·ͤΜ͕ɺMIXI ͷ৽ଔݚमͰ࠵͍ͯ͠·ͨ͠ɻ *5 https://github.com/matsubara0507/git-plantation *6 Id ܕͷํ͸ GeneralizedNewtypeDeriving ͱ͍͏ػೳͰɺWorker ܕ͸ extensible ύοέʔδΛར༻֦ͨ͠ுՄೳ ϨίʔυܕͰ͢ɻ *7 https://hackage.haskell.org/package/websockets Λ࢖͍ͬͯ·͢ɻ 16
  19. ୈ 2 ষ ୳๚ STM at Haskell 2.2 STM ͷ࢖ΘΕํ

    r) ͕ɺαʔόͱ઀ଓ͕Ұ౓Ͱ΋ཱ֬ͨ͠ Worker ͷ৘ใ܈Ͱ͢*8 ɻ͜ΕΛ TVar Ͱϥοϓ͢Δ͜ͱ ͰɺϚϧνεϨουͰ҆શʹڞ༗Ͱ͖ΔϦιʔεͱͳΓ·͢ɻ ͜ͷڞ༗ϦιʔεΛૢ࡞͢ΔϝιουΛ͍͔ͭ͘ݟͯΈ·͢ɿ src/Git/Plantation/Job/Worker.hs ΑΓൈਮ new :: Id -> WS.Connection -> Worker new = ... connect :: Workers -> WS.Connection -> STM Worker connect workers conn = do maxId <- Map.size <$> readTVar workers let worker = new (fromIntegral $ maxId + 1) conn modifyTVar workers (Map.insert (worker ^. #id) $ Just worker) pure worker disconnect :: Workers -> Id -> STM () disconnect workers wid = modifyTVar workers (Map.update (\_ -> Just Nothing) wid) connect ؔ਺΋ disconnect ؔ਺΋ STM a ܕΛฦ͍ͯ͠ΔͷͰɺ͜ͷؔ਺୯ମͰ͸࣮ߦ͞Ε·ͤ Μɻ͜ͷؔ਺ͷ໭Γ஋Λ atomically ؔ਺ʹ౉͢͜ͱͰෆՄ෼ʹ࣮ߦ͞Ε·͢ɻconnect ؔ਺ͷํ ͸ɺId ܕͷ஋Λࡶʹ࡞ΔͨΊʹɺWorkers ͷαΠζΛऔಘ͠ɺͦΕΛ৽͍͠ Worker ܕͷ஋ʹؚΊ ͯ Workers ΁ૠೖ͍ͯ͠·͢ɻ͜͜Ͱ STM Λ࢖Θͳ͔ͬͨ৔߹ɺαΠζͷऔಘ͔Βཁૉͷૠೖ· Ͱͷؒʹ΄͔ͷεϨουʹΑͬͯཁૉ͕૿͍͑ͯΔͱɺId ͕ॏෳͯ͠͠·͏Մೳੑ͕͋Γ·͢ʢ͜ ͷ࣮૷ͷ৔߹ɺ্ͨͩॻ͖͞Ε·͢ʣ ɻ͔͠͠ɺSTM Ͱϥοϓͯ͋͛͠Δ͚ͩͰɺ೉͍͠ഉଞ੍ޚΛ ͢Δ͜ͱͳ҆͘શʹڞ༗ϦιʔεΛ؅ཧͰ͖·͢ɻ Agda Haskell ͸ϓϩάϥϛϯάݴޠͷ࣮૷Ͱ࢖ΘΕΔ͜ͱ͕͠͹͠͹͋Γ·͢ɻAgda *9 ͱ͍͏ϓϩά ϥϛϯάݴޠ΋ͦͷҰͭͰɺґଘܕͱ͍͏ܕΛ͓࣋ͬͯΓɺͦΕΛར༻ͯ͠ఆཧূ໌ͳͲʹར༻͞Ε ·͢ɻ·ͨɺه๏͕ Haskell ʹࣅ͍ͯ·͢ɻ ࣥච࣌఺ͷ࠷৽όʔδϣϯͰ͋Δ v2.6.3 ͷ Agda Ͱ͸ɺSTM Λ REPL ͷ࣮૷Ͱ࢖͍ͬͯ· ͢*10 ɻTChan ͱ TVar Λ࢖ͬͯɺREPL ্ͰͷίϚϯυΛඇಉظʹॲཧ͢ΔͨΊͷΩϡʔΛ࣮૷͠ ͍ͯ·͢ɿ *8 Maybe ʹͳ͍ͬͯΔͷ͸ɺId Λ࡞Δͷʹ Map ͷαΠζΛར༻͢Δ͔ΒͰ͢ɻେྔͷ Worker Λ઀ଓ͢ΔΘ͚͡Όͳ ͍ͷͰɺ͍ͩͿࡶͳ࣮૷Ͱ͢ɻ *9 https://github.com/agda/agda *10 ΑΓਖ਼֬ʹ͸ɺଟ͘ͷݴޠʹ͋ΔΑ͏ͳλʔϛφϧ্Ͱͷର࿩؀ڥͰ͸ͳ͘ɺEmacs ্Ͱͷର࿩؀ڥͰ͢ɻ 17
  20. ୈ 2 ষ ୳๚ STM at Haskell 2.2 STM ͷ࢖ΘΕํ

    src/full/Agda/Interaction/Base.hs ΑΓൈਮ data CommandQueue = CommandQueue { commands :: !(TChan (Integer, Command)) , abort :: !(TVar (Maybe Integer)) } ! ͷ෦෼͸ɺࠓճ͸ແࢹͯ͠ಡΜͰ΋Βͬͯେৎ෉Ͱ͢ɻAgda Ͱఆٛ͞Ε͍ͯΔ Command ܕʹ ͍ͭͯ͸ɺ͜͜Ͱ͸ׂѪ͠·͢ɻREPL Ͱઐ༻ͷίϚϯυΛड͚औͬͯΩϡʔʹૠೖ͠ɺͦΕΛඇಉ ظʹॲཧ͢ΔΑ͏ͳײͩ͡ͱࢥ͍ͬͯͩ͘͞ɻίϚϯυͷॲཧ͸ TChan ͷΩϡʔΛհͯ͠ඇಉظʹ ॲཧ͞Ε·͕͢ɺ ʢ͓ͦΒ͘ʣ͕͔͔࣌ؒΔΑ͏Ͱɺͦͷؒʹڧ੍ऴྃͷίϚϯυʢabortʣΛड͚औ ΔͨΊʹผͷ TVar Λ༻ҙ͍ͯ͠ΔΑ͏Ͱ͢ɻ࣮ࡍʹ CommandQueue ܕͷ஋͕࢖ΘΕ͍ͯΔͱ͜Ζ ΛݟͯΈ·͢ɿ src/full/Agda/Interaction/InteractionTop.hs ΑΓൈਮ -- ίϚϯυΛඇಉظʹॲཧ͢ΔผεϨουΛ࡞Δؔ਺ initialiseCommandQueue :: IO Command -> IO CommandQueue initialiseCommandQueue next = do commands <- newTChanIO abort <- newTVarIO Nothing let readCommands n = do c <- next -- ίϚϯυΛͳΜ͔͠Βͷ֎෦ೖྗΑΓಡΈࠐΉ case c of Command c | IOTCM _ _ _ Cmd_abort <- c Nothing -> do atomically $ writeTVar abort (Just n) readCommands n _ -> do let n’ = (succ n) atomically $ writeTChan commands (n’, c) case c of Done -> return () _ -> readCommands n’ -- forkIO ͰผεϨουͱͯ͠Ҿ਺ͷ IO ΞΫγϣϯΛ࣮ߦ _ <- forkIO (readCommands 0) return (CommandQueue { .. }) case ࣜͷ෼ذͷ͏ͪɺલऀ͸ abort Λड͚औͬͨ৔߹ͳͷͰ CommandQueue ͷ abort ͷํΛߋ ৽͠ɺͦΕҎ֎ͷ৔߹͸ίϚϯυΛඇಉظʹॲཧ͢ΔͨΊͷΩϡʔͰ͋Δ commands ΁ૠೖ͍ͯ͠· ͢ɻ͜͜Ͱ͓΋͠Ζ͍ͷ͸ abort ͷಡΈऔΓଆͷํͰ͢ɿ 18
  21. ୈ 2 ষ ୳๚ STM at Haskell 2.2 STM ͷ࢖ΘΕํ

    src/full/Agda/Interaction/InteractionTop.hs ΑΓൈਮ waitForAbort :: Integer -> CommandQueue -> IO Integer waitForAbort n q = do atomically $ do a <- readTVar (abort q) case a of Just a’ | n <= a’ -> return a’ _ -> retry ৽͘͠ retry ؔ਺͕ग़͖ͯ·ͨ͠ɻ͜Ε΋ STM ͷؔ਺Ͱɺ ʮݱࡏͷτϥϯβΫγϣϯΛഁغͯ͠ ΋͏Ұ౓΍Γ௚͢ʯͱ͍͏ৼΔ෣͍Λ͠·͢ɻͭ·Γɺabort ͷ݁Ռ͕ Just a’ ʹͳΔ·Ͱʢ୭͔ ͕ abort Λೖྗ͢Δ·Ͱʣ ɺӬԕͱ atomically ҎԼͷτϥϯβΫγϣϯΛ܁Γฦ͢Θ͚Ͱ͢ɻ΋ͪ ΖΜɺແݶϧʔϓͷΑ͏ʹԿճ΋࣮ߦͯ͠ CPU ϦιʔεΛ৯͍௵͢͜ͱ͸͋Γ·ͤΜɻSTM ͷ࣮ ૷͸ݡ͘Ͱ͖͍ͯͯɺͳΜ͔͠ΒͷมԽ͕ͳ͍ݶΓτϥϯβΫγϣϯΛ࠶౓࣮ߦ͢Δ͜ͱ͸ͳ͍Α͏ Ͱ͢ɻͭ·ΓɺreadTVar (abort q) ͷ݁Ռ͕มΘΒͳ͍ݶΓɺ͜ͷεϨου͸ϒϩοΫ͞ΕΔΘ ͚Ͱ͢ʢ·͞ʹ waitForAbort Ͱ͢Ͷʣ ɻ waitForAbort ؔ਺͸͜Μͳײ͡ʹ࢖ΘΕ͍ͯ·͢ɿ src/full/Agda/Interaction/InteractionTop.hs ΑΓൈਮ -- IO ͳؔ਺ͷத -- CommandQueue ܕͷ஋ q ͔Β Command Λ1ͭऔಘ (n, cmd) <- atomically $ readTChan (commands q) case cmd of ... Command c -> do result <- Async.race (run c) (waitForAbort n q) case result of Left ... -> ... -- abort ͷ৔߹ Right ... -> ... -- Command ͕࣮ߦͰ͖ͨ৔߹ async ύοέʔδͷ race ؔ਺͸ɺ౉ͨ͠ 2 ͭͷ IO ΞΫγϣϯΛผʑͷεϨουͰಉ࣌ʹ࣮ߦ͠ ͯɺઌʹऴྃͨ͠΋ͷͷ݁ՌΛ Either Ͱฦ͠·͢ɻͭ·ΓɺίϚϯυ͕ऴΘΔલʹ abort ͕ೖྗ ͞ΕΔͱɺઌʹ waitForAbort Λ࣮ߦͨ͠εϨου͕ऴྃ͢ΔͨΊ race ؔ਺͕ίϚϯυͷ࣮ߦΛ ͱΊΔΘ͚Ͱ͢Ͷɻ ༨ஊͰ͕͢ɺretry Λ࢖ͬͨϒϩοΩϯάΛ͢Δํ๏͸ʮHaskell ʹΑΔฒߦɾฒྻϓϩάϥϛϯ άʯͰ΋঺հ͞Ε͍ͯΔํ๏Ͱ͢ɻ·ͨɺ͜ͷϒϩοΩϯάͷ͘͠ΈΛར༻ͯ͠νϟϯωϧܥͷσʔ λߏ଄͸ɺreadTChan ؔ਺ͳͲͷνϟϯωϧ͔ΒͷσʔλͷಡΈऔΓΛɺσʔλ͕ૠೖ͞ΕΔ·Ͱ ଴ػ͍ͯ͠·͢ɻ 19
  22. ୈ 2 ষ ୳๚ STM at Haskell 2.2 STM ͷ࢖ΘΕํ

    haskell-language-server haskell-language-server *11 ͸ɺHaskell ެࣜͰϝϯςφϯε͞Ε͍ͯΔɺHaskell ϓϩάϥϛϯ άΛࢧԉ͢ΔͨΊͷ Language Server Protocol ४ڌͳπʔϧͰ͢ʢIDEʣ ɻhaskell-language-server Ͱ͸ STM ΛԿϱॴ͔Ͱ࢖͍ͬͯ·͕͢ɺࠓճ͸ҎԼͷσʔλߏ଄ʹ͍ͭͯ঺հ͠·͢ɿ ghcide/src/Development/IDE/Types/Action.hs ΑΓൈਮ data ActionQueue = ActionQueue { newActions :: TQueue DelayedActionInternal, inProgress :: TVar (HashSet DelayedActionInternal) } DelayedActionInternal ܕ͸ haskell-language-server Ͱఆٛ͞Ε͍ͯΔܕͰɺඇಉظʹॲཧ͠ ͍ͨͳΜ͔͠ΒͷΞΫγϣϯΛදݱ͍ͯ͠·͢ɻActionQueue ܕ͸໊લ͔Β෼͔ΔΑ͏ʹɺඇಉظ ॲཧͷͨΊͷΩϡʔΛදݱͨ͠σʔλߏ଄Ͱ͢ɻnewActions ϑΟʔϧυଆ͕ΩϡʔຊମͰɺinPro gress ϑΟʔϧυ͕ඇಉظॲཧதͷΞΠςϜΛೖΕ͓ͯ͘഑ྻͷΑ͏ͳ΋ͷͰ͢ɻΩϡʔ͔ΒΞΠ ςϜΛऔΓग़ؔ͢਺ popQueue ΛݟͯΈ·͢ɿ ghcide/src/Development/IDE/Types/Action.hs ΑΓൈਮ popQueue :: ActionQueue -> STM DelayedActionInternal popQueue ActionQueue {..} = do x <- readTQueue newActions modifyTVar inProgress (Set.insert x) return x Ωϡʔຊମ͔ΒΞΠςϜΛ 1 ͭऔΓग़ͨ͠ޙɺinProgress ͷํʹૠೖͯ͠ɺऔΓग़ͨ͠ΞΠςϜ Λฦ͍ͯ͠·͢ɻ໭Γ஋ͷܕ͕ DelayedActionInternal Ͱ͸ͳͯ͘ STM DelayedActionIntern al Ͱ͢ͷͰɺ͜ΕΒͷॲཧ͸ atomically ؔ਺ͳͲΛར༻ͯ͠ෆՄ෼ͳॲཧͱ࣮ͯ͠ߦՄೳͱ͍͏ Θ͚Ͱ͢ɻ Semantic Semantic ͸ GitHub ͕։ൃ͍ͯ͠Δɺ͞·͟·ͳϓϩάϥϛϯάݴޠͷղੳΛ͢ΔͨΊͷπʔϧ Ͱ͢ʢݱࡏͰ΋࢖͍ͬͯΔ͔͸Θ͔Γ·ͤΜ͕ʣ *12 ɻOSS ͱͯ͠ެ։͞Ε͓ͯΓɺϓϩάϥϛϯάݴ ޠͷߏจ໦Λ؆୯ʹѻ͏ͨΊʹ Haskell Λ࢖͍ͬͯΔΑ͏Ͱ͢*13 ɻ *11 https://github.com/haskell/haskell-language-server *12 https://github.blog/2020-08-04-codegen-semantics-improved-language-support-system/ Ͱ঺հ͞Ε ͍ͯ·͢ɻ *13 https://github.com/github/semantic 20
  23. ୈ 2 ষ ୳๚ STM at Haskell 2.2 STM ͷ࢖ΘΕํ

    Semantic Ͱ͸ stm ύοέʔδͷ୅ΘΓʹ stm-chans ύοέʔδ*14 Λ࢖͍ͬͯΔΑ͏Ͱ͢ɻstm- chans ύοέʔδʹ͸ɺstm ύοέʔδʹ͋Δલड़ͨ͠νϟϯωϧܥͷσʔλߏ଄ʹɺνϟϯωϧͷ ΫϩʔζΛ௥Ճͨ͠Α͏ͳσʔλߏ଄Λఏڙ͍ͯ͠·͢ɻSemantic Ͱ͸ TBMQueue Λར༻ͯ͠ඇಉ ظॲཧͷΩϡʔΛ࡞͍ͬͯ·͢ɿ src/Semantic/Telemetry/AsyncQueue.hs ΑΓൈਮ data AsyncQueue a = AsyncQueue { asyncQueue :: TBMQueue a , asyncQueueSink :: Async () } asyncQueue ͕ΩϡʔຊମͰɺasyncQueueSink ͸Ωϡʔ͔ΒཁૉΛऔΓग़͠ඇಉظʹॲཧͯ͠ ͘ΕΔผεϨουΛදͨ͠ϑΟʔϧυͰ͢ɻAsyncQueue ͷॳظԽ࣌ʹ asyncQueueSink Λ࣮ߦ͠ ͓͖ͯ·͢ɿ src/Semantic/Telemetry/AsyncQueue.hs ΑΓൈਮ newAsyncQueue :: Int -> (a -> IO ()) -> IO (AsyncQueue a) newAsyncQueue i f = do q <- newTBMQueueIO i -- i ͸Ωϡʔͷ௕͞ s <- Async.async (sink q) pure (AsyncQueue q s) where shink q = do msg <- atomically (readTBMQueue q) maybe (pure ()) go msg where go msg = f msg >> sink f q asyncQueue ͸ɺΩϡʔ͕Ϋϩʔζ͞Εͨ࣌ʹ͸ Nothing Λฦ͢Α͏ʹͳΓ·͢ɻmaybe ͷͱ͜ ΖͰɺNothing ͕ฦͬͯ͘Δ·Ͱ࠶ؼ͠ͳ͕Βͣͬͱ f Λ࣮ߦ͠ଓ͚͍ͯΔ͜ͱ͕Θ͔Δͱࢥ͍· ͢ɻAsyncQueue ΛΫϩʔζ͢Δʹ͸࣍ͷؔ਺Λ࢖͍·͢ɿ src/Semantic/Telemetry/AsyncQueue.hs ΑΓൈਮ closeAsyncQueue :: AsyncQueue a extra -> IO () closeAsyncQueue AsyncQueue{..} = do atomically (closeTBMQueue asyncQueue) Async.wait asyncQueueSink *14 https://hackage.haskell.org/package/stm-chans 21
  24. ୈ 2 ষ ୳๚ STM at Haskell 2.3 ऴΘΓʹ closeTBMQueue

    ؔ਺ͰΩϡʔຊମΛΫϩʔζ͠ɺasync ύοέʔδͷ wait ؔ਺Λ࢖͏͜ͱͰɺA sync ͳΞΫγϣϯ͕ऴྃ͢ΔͷΛ଴ͪ·͢ɻ͜͏͢Δ͜ͱͰɺ࣮ߦதͩͬͨඇಉظॲཧ͕ͪΌΜͱ ऴྃ͢Δ·Ͱ଴ͭΑ͏ʹͳ͍ͬͯΔΘ͚Ͱ͢ʢAgda ͷ࣌ͷΑ͏ʹڧ੍ऴྃ͸͠ͳ͍ʣ ɻ 2.3 ऴΘΓʹ ଞʹ΋ଟ͘ͷ Haskell ੡ΞϓϦέʔγϣϯͰ STM ͕࢖ΘΕ͍ͯ·͢ɻ͜ΕΒͷ OSS ͷ͓͔͛ ͰɺSTM Λ࢖͑͹ฒྻɾฒߦϓϩάϥϛϯάͰ؆୯ʹڞ༗ϦιʔεΛ࢖ͬͨॲཧ͕͔͚Δ͜ͱ͕఻ Θͬͨͱࢥ͍·͢ɻಛʹɺඇಉظॲཧͷΩϡʔΛ࣮૷͢Δͷʹͱͯ΋ศརͦ͏Ͱ͢ΑͶɻ 22
  25. ୈ 3 ষ Web ͷճؼςετͷࣗಈԽ Web αʔϏεͷ։ൃʹ͓͍ͯγεςϜ͕ظ଴௨Γʹಈ͔͘Ͳ͏͔ΛνΣοΫ͢ΔͨΊʹɺ͞·͟ ·ͳςετΛߦ͏৔߹͕͋Γ·͢ɻ ςετΛߦ͏͜ͱͰϦϦʔεʹؚ·ΕΔෆ۩߹ΛݮΒ͢͜ͱ͕Ͱ͖·͢ɻΞδϟΠϧ։ൃʹ͓͍ͯ ͸ൺֱత୹͍ظؒͷதͰ։ൃͱϦϦʔεΛ܁Γฦ͢ͷͰසൟʹςετΛߦͬͨΓ͠·͢ɻ

    ςετʹ͸ɺ͞·͟·ͳछྨ͕͋Γ·͢ɻ • Ϣχοτςετ – Ϟδϡʔϧ୯ҐͰظ଴͢ΔڍಈΛ͢Δ͔Ͳ͏͔ΛνΣοΫ͠·͢ɻ • ΠϯςάϨʔγϣϯςετ – ϞδϡʔϧΛ͍͔ͭ͘૊Έ߹Θͤͯظ଴͢ΔڍಈΛ͢Δ͔Ͳ͏͔ΛνΣοΫ͠·͢ɻ – Web Ͱ͸ίϯϙʔωϯτͷςετΛߦ͏ࡍʹɺίϯϙʔωϯτʹ಺แ͞ΕΔϞδϡʔϧ ܈͕૊Έ߹Θͬͨ͞ঢ়ଶͰظ଴͢Δಈ࡞Λ͢Δ͔Ͳ͏͔ΛνΣοΫ͠·͢ɻ • E2E ςετ – ݶΓͳ͘ຊ൪؀ڥʹ͍ۙঢ়ଶͰɺαʔό͔ΒΫϥΠΞϯτ·ͰΛͭͳ͍ͩঢ়ଶͰظ଴͢Δ ಈ࡞Λ͢Δ͔Ͳ͏͔ΛνΣοΫ͠·͢ɻ – Web Ͱ͸ϒϥ΢β্ͰνΣοΫର৅ͷγεςϜΛ࣮ࡍʹૢ࡞͢Δ͜ͱͰνΣοΫ͠·͢ɻ ·ͨɺγεςϜ඼࣭ͷνΣοΫʹ΋ड͚ೖΕςετ΍ճؼςετͳͲ͞·͟·ͳछྨͷςετ͕ ͋Γ·͢ɻࠓճ͸ൺֱతςετͷن໛΍޻਺͕ංେԽ͕ͪ͠ͳճؼςετͷࣗಈԽʹ͍ͭͯղઆ͠ ·͢ɻ 3.1 ճؼςετͱ͸ ճؼςετͱ͸ɺίʔυΛมߋͨ͜͠ͱͰγεςϜͷ΄͔ͷՕॴͰ༧ظͤ͵ෆ۩߹͕ग़͍ͯͳ͍͔ ΛνΣοΫ͢ΔςετͰ͢ɻͰ͢ͷͰɺճؼςετͷνΣοΫ࣌ʹ͸γεςϜશମΛର৅ʹҰ௨Γͷ ૢ࡞͕Մೳ͔Ͳ͏͔΍ಈ࡞ʹҟৗ͕ͳ͍͔ΛνΣοΫ͠·͢ɻ ࣮ࡍʹγεςϜΛૢ࡞ͯ͠νΣοΫ͢ΔͷͰɺϢʔβʔͷؾ࣋ͪʹͳͬͯͦͷγεςϜͷ࢖͍ͮΒ ͞ʹؾ෇͖͔͚ͬ͘ʹ΋ͳΓ·͢ɻ 23
  26. ୈ 3 ষ Web ͷճؼςετͷࣗಈԽ 3.2 ՝୊ ͨͩɺ࣮ࡍʹճؼςετΛ։ൃϑϩʔͷதʹಋೖ͍ͯ͘͠ͱൃੜ͢Δ՝୊΋͋Γ·͢ɻ 3.2 ՝୊

    ճؼςετ͸γεςϜશମͷཁ݅ʹԊͬͯςετέʔε͕࡞ΒΕ͍͖ͯ·͢ɻͰ͢ͷͰɺ։ൃΛਐ Ίͯػೳ͕૿͍͚͑ͯ͹૿͑Δ΄Ͳςετ߲໨͕૿͍͖͑ͯ·͢ɻ ໢ཏ཰ 100% Λ໨ࢦͤ͹໨ࢦ͢΄Ͳςετ߲໨͸૿͍͖͑ͯςετͷίετ͸ରԠ͖͠Εͳ͍΄Ͳ ංେԽͯ͠͠·͏ͷͰɺςετ߲໨ʹ༏ઌ౓Λ͚ͭΔ͜ͱͰγεςϜ্ॏཁͳՕॴΛް͘ςετ͢ Δɺͱ͍͏Α͏ͳํ๏΋͋Γ·͕͢ɺςετͷίετ૿େͦͷ΋ͷͷղܾࡦʹ͸ͳΓ·ͤΜɻ ςετͷίετ͕૿͑ͯճؼνΣοΫʹ͔͔Δ͕࣌ؒ૿͑ΔͱͦͷͿΜϦϦʔε͕஗͘ͳͬͯ͠· ͏Մೳੑ͕͋Γ·͢ɻ ࠓճ͸͜ͷςετ߲໨͕૿͑Δ͜ͱʹΑΔςετͷίετ૿େͷ՝୊ղܾΛࢼΈ·͢ɻ 3.3 Ξϓϩʔν E2E ςετπʔϧΛಋೖ͢Δ͜ͱͰճؼςετͷࣗಈԽΛ࣮ݱͰ͖·͢ɻ E2E ςετπʔϧʹ͸ίʔυϕʔεͰςετ͢Δ΋ͷ΍ɺϊʔίʔυͰςετ͢Δ΋ͷͳͲ͕͋ Γ·͢ɻ • Playwright – JavaScriptʢTypeScriptʣ Λ࢖ͬͨίʔυϕʔεͰςετΛߦ͏ E2E ςετπʔϧͰ͢ɻ • MagicPod – GUI ্ͰςετέʔεΛ૊ΈɺϊʔίʔυͰςετΛߦ͏ E2E ςετπʔϧͰ͢ɻ ্هͷΑ͏ͳ E2E ςετπʔϧʹΑͬͯɺਓྗͰߦ͍ͬͯͨճؼςετͷςετ߲໨ΛࣗಈԽ͢ Δʹ͸ɺςετ߲໨ͷఆٛΛػց͕ղऍՄೳͳঢ়ଶʹ͢Δඞཁ͕͋Γ·͢ɻ ͨͱ͑͹ʮϔομʹ͋Δτοϓϖʔδ΁ͷϦϯΫΛΫϦοΫͨ͠Βҧ࿨ײͳ͘τοϓϖʔδʹભҠ ͞ΕΔʯͱ͍͏Α͏ͳςετέʔε͕͋ͬͨͱͯ͠ɺ͜ΕΛػց͕ղऍՄೳͳఆٛʹม׵͢Δͱ͢Ε ͹ɺ ʮDesktop Chrome ͱ iPhone14 ͷ Webkit ͷϒϥ΢β؀ڥʹ͓͍ͯɺϔομʹ͋Δτοϓϖʔ δͷϦϯΫΛΫϦοΫͨ͠ΒɺΤϥʔ͕ൃੜͤͣ URL ͕ /(τοϓ) ʹભҠ͞ΕΔʯͷΑ͏ʹͳΔͰ ͠ΐ͏ɻ ͦͷςετ͕ͲͷΑ͏ͳ؀ڥͰ࣮ߦ͞ΕΔ͔ʁ ૝ఆ͞ΕΔ݁Ռͷ৚݅ͷఆٛ͸Կ͔ʁ ҧ࿨ײͷఆ ٛ͸Կ͔ʁ ͱ͍ͬͨΑ͏ͳ҉໧తʹ૝ఆ͞ΕΔ৚݅Λ໌จԽ͢Δ͜ͱ͕ɺࣗಈԽ΁ͷҠߦʹ͸ඞཁ Ͱ͢ɻ΋͠ɺςετέʔεʹ͓͚Δʮҧ࿨ײͷͳ͞ʯ͕ʮભҠઌͷϖʔδͷද่͕ࣔΕ͍ͯͳ͍ʯͱ ͍͏Α͏ͳҙຯ΋ؚΉͷͰ͋Ε͹ςετέʔεΛ෼ղ͢Δ͜ͱ΋ඞཁ͔΋͠Ε·ͤΜɻ ͨͩɺςετͷ݁ՌʮγεςϜ͕࢖͍ͮΒ͘ͳͬͯ͠·͍ͬͯΔʯͱ͍͏Α͏ͳ௚ײΛཁ͢Δ΋ͷ ʹ͍ͭͯ͸ࣗಈԽ͢Δ͜ͱ͕೉͍͠৔߹͕͋ΔͷͰɺແཧ΍ΓࣗಈԽ͢ΔΑΓ΋ਓ͕ؒςετΛߦ͏ ํ͕๬·͍͠৔߹΋͋Γ·͢ɻ ͜͏͍ͬͨςετέʔεΛͲͷΑ͏ʹࣗಈԽ͢Δ͔ʁ ࣗಈԽͨ݁͠ՌͲͷΑ͏ͳςετέʔεʹ 24
  27. ୈ 3 ষ Web ͷճؼςετͷࣗಈԽ 3.4 ࣮ફ ͳΔ͔ʁ ͱ͍͏΋ͷ͸νΣοΫ୲౰ͷਓͱ࣮૷ऀ͕Ұॹʹௐ੔͍ͯ͘͜͠ͱͰɺͲͷΑ͏ͳڍಈ͕ ୲อ͞Ε͍ͯΔͷ͔ͷڞ௨ೝࣝΛ࡞Γɺճؼςετͷݱ࣮ղΛಋ͘͜ͱ͕Ͱ͖ΔͰ͠ΐ͏ɻ

    3.4 ࣮ફ ࣮ࡍʹ E2E ςετπʔϧΛ࢖ͬͨςετέʔεͷ࡞੒Λͯ͠Έ·͢ɻ ࠓճ͸ Playwright Λ࢖༻ͯ͠Έ·͢ɻ Լه͸ෳ਺ϒϥ΢βʹΑΔςετέʔεͷ࣮ߦͷྫͰ͢ɻ Ϧετ 3.1: sample.spec.ts 1: import { devices, expect, test } from "@playwright/test"; 2: 3: // ςετΛߦ͏σόΠεͷҰཡ 4: const EMULATE_DEVICES = [devices["iPhone 13"], devices["Desktop Chrome"]]; 5: 6: test.use({ 7: ...EMULATE_DEVICES, 8: locale: "ja-JP", 9: }); 10: 11: test("φϏήʔγϣϯ্ͷϦϯΫ͔ΒμογϡϘʔυ΁ભҠ", async ({ page }) => { 12: await page.goto("https://github.com/microsoft/playwright"); 13: 14: // φϏήʔγϣϯ͕഑ஔ͞Ε͍ͯΔμΠΞϩάΛ։͘ 15: await page.locator(’[aria-label="Open side panel"]’).click(); 16: 17: // ϦϯΫͷ৔ॴΛಛఆͯ͠ԡԼ 18: const siteNavigateArea = page.locator(’[aria-label="Site navigation"]’); 19: await siteNavigateArea.getByText("Home").click(); 20: 21: // ૝ఆ͞ΕͨϖʔδϦϯΫʹભҠ͔ͨ͠Ͳ͏͔ΛνΣοΫ 22: expect(page).toHaveURL("https://github.com/dashboard"); 23: }); ·ͨɺϩάΠϯঢ়ଶΛ E2E ςετͰ੍ޚ͢Δʹ͸ԼهͷΑ͏ʹ࣮ݱ͠·͢ɻ Ϧετ 3.2: auth.setup.ts 1: import { test as setup } from "@playwright/test"; 2: 3: export const USER_A_AUTH_FILE = "playwright/.auth/user1.json"; 4: export const USER_B_AUTH_FILE = "playwright/.auth/user2.json"; 5: 6: setup("userA ೝূ", async ({ page }) => { 7: const USER_NAME = /** Ϣʔβʔ໊ */; 8: const PASSWORD = /** ύεϫʔυ */; 9: 25
  28. ୈ 3 ষ Web ͷճؼςετͷࣗಈԽ 3.4 ࣮ફ 10: await page.goto("https://github.com/login");

    11: await page.getByLabel("Username or email address").fill(USER_NAME); 12: await page.getByLabel("Password").fill(PASSWORD); 13: await page.getByRole("button", { name: "Sign in" }).click(); 14: 15: await page.waitForURL("https://github.com/"); 16: 17: expect( 18: page.getByRole("button", { name: "View profile and more" }) 19: ).toBeVisible(); 20: 21: await page.context().storageState({ path: USER_A_AUTH_FILE }); 22: }); 23: 24: setup("userB ೝূ", async ({ page }) => { 25: const USER_NAME = /** Ϣʔβʔ໊ */; 26: const PASSWORD = /** ύεϫʔυ */; 27: 28: await page.goto("https://github.com/login"); 29: await page.getByLabel("Username or email address").fill(USER_NAME); 30: await page.getByLabel("Password").fill(PASSWORD); 31: await page.getByRole("button", { name: "Sign in" }).click(); 32: 33: await page.waitForURL("https://github.com/"); 34: 35: expect( 36: page.getByRole("button", { name: "View profile and more" }) 37: ).toBeVisible(); 38: 39: await page.context().storageState({ path: USER_B_AUTH_FILE }); 40: }); ϑΥϩʔɾඃϑΥϩʔͳͲͷෳ਺ΞΧ΢ϯτΛ࢖༻ͨ͠ςετʹ΋ରԠͰ͖ΔΑ͏ʹෳ਺Ϣʔβʔ Ͱͷೝূ৘ใΛอ࣋Ͱ͖·͢ɻ ԼهͷΑ͏ͳઃఆϑΝΠϧΛ഑ஔ͢Δ͜ͱͰɺςετͷલʹೝূ৘ใͷऔಘΛߦ͏Α͏ʹͳΓ ·͢ɻ Ϧετ 3.3: playwright.config.ts 1: import { defineConfig } from "@playwright/test"; 2: 3: const config = defineConfig({ 4: projects: [ 5: // Setup project 6: { name: "setup", testMatch: /.*\.setup\.ts/ }, 7: ], 8: }); 9: 10: export default config; 26
  29. ୈ 3 ষ Web ͷճؼςετͷࣗಈԽ 3.5 ͍͞͝ʹ ͜ͷ E2E ςετΛɺճؼςετ࣌ʹ୭Ͱ΋࣮ߦͰ͖ΔΑ͏ʹ

    GitHub Actions ͷ workflow dispatch Λ࢖༻ͯ͠खಈ࣮ߦͰ͖ΔΑ͏ʹͯ͠ΈΔͳͲ΋ྑ͍Ͱ͠ΐ͏ɻ ͜͏͍ͬͨ E2E ςετ͸ɺ։ൃΛਐΊΔ͝ͱʹͲΜͲΜϓϩάϥϜͷมߋ͕ೖΓɺؾ෇͍ͨͱ͖ ʹ͸ E2E ςετ͕࣮ߦͰ͖ͳ͘ͳ͍ͬͯͨɺͱ͍͏Α͏ͳέʔε͕ԟʑʹͯ͋͠Γ·͢ɻͦͷͨ Ίɺఆظతʹ E2E ςετΛ࣮ߦͯ͠ςετͷࣦഊʹૣ͘ؾ෇͘͜ͱ͕ॏཁͰ͢ɻͦ͜ͰɺGitHub Actions ʹΑΔ E2E ςετͷఆظ࣮ߦΛಋೖ͢ΔͳͲͷํ๏͕͋Γ·͢ɻ 3.5 ͍͞͝ʹ ͜ͷΑ͏ʹ Playwright Λ࢖༻͢Δ͜ͱͰ Web ͷճؼςετΛࣗಈԽͰ͖·͢ɻ ·ͨ 100% ׬શʹࣗಈԽ͢ΔΑΓɺͲͷΑ͏ͳςετͳΒࣗಈԽՄೳ͔ʁ ͜ͷςετ͸ਓؒͷ νΣοΫʹΑͬͯ୲อ͢Δ΂͖͔ʁ ͱ͍͏൑அΛճؼςετέʔεͷઃܭ͝ͱʹඞཁʹͳΔͰ͠ΐ ͏ɻͦͷͨΊɺγεςϜઃܭ࣌ͳͲɺͲͷΑ͏ͳ࣮૷ʹ͍͔ͯ͘͠Λ͢Γ߹ΘͤͨΓڞ༗͢Δ৔͕͋ Ε͹ͦ͏͍ͬͨ৔Ͱςετઃܭ΋ҰॹʹߦͬͯΈ·͠ΐ͏ɻ 27
  30. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.1 ຊষʹ͍ͭͯ micro:bit ͱ͍͏ڭҭ༻ϚΠίϯϘʔυ͕͋Γɺֶߍڭҭʹܞ͍ͬͯΔιϑτ΢ΣΞΤϯδχΞͷ ਎ͱͯͦ͠Ε͕ͲΜͳ΋ͷ͔࣮ࡍʹ࢖ͬͯΈΔମݧهͷΑ͏ͳষͰ͢ɻઌߦςετࣄྫͳͲ͸ωοτ

    ʹͪΒ΄Βͱ͢Ͱʹ͋Δ΋ͷͰ͕͢ɺ࣮ࡍʹࣗ෼͕৮ͬͯಘΒΕΔ͜ͱ͸͖ͬͱଟ͋͘Δͱࢥ͍ࠓճ ΍ͬͱखΛ৳͹͠·͕ͨ͠ɺࢥ͍ͬͯͨΑΓ΋༗ೳͰͨ͠ͷͰڞ༗͍ͨ͠ͱࢥ͍·͢ɻ ຊষ͸ɺެࣜஂମ͕ఏڙ͍ͯ͠ΔΤσΟλͰ͋Δ Python editor *1 Λ࢖ͬͯɺMacBook Pro ͱ USB ઀ଓ͢Δݕূ΍ιʔείʔυΛܝࡌ͠·͢ɻMicrosoft ࣾͷ MakeCode ΤσΟλͰͷ Python ΍ɺMu ΤσΟλͰͷ Python ͸ͦΕͧΕʹޓ׵ੑ͕͋Γ·ͤΜͷͰ͝஫ҙ͍ͩ͘͞ɻ *1 micro:bit ެࣜஂମͷ Python editor : https://python.microbit.org/ 29
  31. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.1 ຊষʹ͍ͭͯ ͓खܰͰ͓΋͠Ζ͍σόΠε ࠓճ࣮ࡍʹௐ΂ͳ͕Βςετͯ͠෼͔ͬͨ͜ͱΛ݁࿦͔Βݴ͏ͱɺ͜Ε͸= 3,000

    ΄Ͳͷຊମ 1 ͭ ͚ͩͰͱͯ΋औΓ૊Έ͕͍ͷ͋Δڵຯਂ͍σόΠεͰ͢ɻ༡ͼͱֶͯ͠शͱͯ͠ɺ͋Δ͍͸ϥΠϑ ϋοΫͳͲɺ͏·͘΍Ε͹׆࿏͕͋Δϙςϯγϟϧ͕ײ͡ΒΕͯඇৗʹ͓΋͠Ζ͍σόΠεͰ͢ɻ ͦΕ͔Βɺιϑτ΢ΣΞ։ൃओମͰ͋ͬͨࢲʹͱͬͯϚΠίϯϘʔυ͸ීஈར༻͖ͯ͠·ͤΜͰ͠ ͕ͨɺݱ࣮ͷσόΠεͱιϑτ΢ΣΞ͕࿈ಈ͢Δ͜ͱͰਓͱιϑτ΢ΣΞ͕ͭͳ͕Δ͜ͱ͸ඇৗʹ༗ ҙٛͰ͢ɻ͞ΒʹՃ଎౓ηϯαɺ஍࣓ؾηϯαɺγϦΞϧϙʔτ઀ଓͳͲɺσόΠε੍ޚͷ؍఺͔Β ΋ଟ͘ͷऔΓ૊Έ୊ࡐ͕͋ΔͨΊɺࢠͲ΋ͷֶशڭࡐͱ͚ͯͩ͠Ͱ͸ͦͷද໘ͷҰ෦෼͔͠࢖͍ͬͯ ͳ͍ͱ͍͏ঢ়گͰ͋Δ͜ͱ͕෼͔Γ·ͨ͠ɻಉ༷ͷϚΠίϯϘʔυͰ͸ Raspberry Pi ͳͲ΋ڍ͛Β ΕΔͱࢥ͍·͕͢ɺຊػ͸Ձ֨= 3,000 લޙͳ͜ͱͱ͓खܰͰͱ͖ͬͭ΍͍͢͜ͱɺΉ͖ग़͠Ͱར༻ Ͱ͖Δ͜ͱͳͲɺඞཁͳΒେྔߪೖͯ͠Կ͔Ͱ͖Δ͔΋͠Εͳ͍ՄೳੑΛײ͡·͢ɻ ࠓճ͢΂ͯ͸ਂ͘৮ΕΔ͜ͱ͕Ͱ͖·ͤΜͰ͕ͨ͠ɺͦͷਂΈͱՄೳੑ͕ײ͡ΒΕͨ͜ͱΛத৺ʹ ίʔυྫͱͱ΋ʹ঺հ͍͖ͯ͠·͢ɻ   චऀϓϩϑΟʔϧ ήʔϜΛத৺ͱͨ͠ιϑτ΢ΣΞΤϯδχΞͱͯ͠׆ಈ͓ͯ͠ΓɺίϯγϡʔϚήʔϜ΍ϒϥ΢ βήʔϜͱεϚʔτϑΥϯΞϓϦͷ։ൃɺWeb αʔϏε΍ήʔϜاըʹ΋ܞΘΔɻۙ೥͸ڭҭ ݱ৔ʹ޲͚ͯɺ ʮϓϩάϥϛϯάֶशʯΛਪਐ͢Δߨࢣͱͯͦ͠ͷֶशιϑτ΢ΣΞ΍ΧϦΩϡ ϥϜ։ൃͱซͤͯऔΓ૊ΜͰ͍Δɻ LinkedIn: https://www.linkedin.com/in/akira-tanabe/   ໨࣍ • micro:bitʢϚΠΫϩϏοτʣͱ͸ • ಺ଂ Beep ԻεϐʔΧʔͰϝϩσΟϓϨΠϠʔ • Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ • ϚΠίϯνοϓ୯ಠϛχήʔϜ੍࡞ • ऴΘΓʹ 30
  32. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.1 ຊষʹ͍ͭͯ micro:bitʢϚΠΫϩϏοτʣͱ͸ micro:bitʢBBC micro:bitʣͱ͍͏ϓϩάϥϛϯάֶश޲͚खͷͻΒαΠζͷϚΠίϯϘʔυڭࡐ

    ͕ӳࠃ์ૹڠձ BBC ʹΑͬͯઃܭ͞Εɺݱࡏ͸શੈքͰ׆༻͞Ε͍ͯ·͢ɻόʔδϣϯ 1ʢV1ʣ͸ 2017 ೥͔Βఏڙ͞Εɺ2020 ೥ 10 ݄ʹ V2 ʹΞοϓσʔτ͞Εɺηϯαྨͱ API ͕௥Ճ͞Ε͍ͯ ·͢ɻ ಺ଂηϯαʹ͸ • Ճ଎౓ηϯα • ஍࣓ؾηϯα • Թ౓ηϯα • ؀ڥޫηϯα ΠϯλϑΣʔεʹ͸ • ϚΠΫϩ USB • ϚΠΫ • εϐʔΧʔ • A / B Ϙλϯ • ೖग़ྗ୺ࢠ 0/1/2/3V/GND ʜϫχΫϦοϓͱͷ઀ଓ༻ • Bluetooth • ຊମ LOGO λονʢV2ʣ ͕උΘ͍ͬͯ·͢ɻ ։ൃ؀ڥ͸ɺMicrosoft ࣾͷ MakeCode ΤσΟλͰͷϒϩοΫϓϩάϥϛϯάɾJavaScript ɾ Python ͕ɺެࣜஂମ͔Β͸ Python editorʢ˒ࠓճར༻͢Δʣ ɺApple ͔Β Swift Playgrounds Ξϓ ϦͳͲ͕ఏڙ͞Ε͍ͯ·͢ɻ 31
  33. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.2 ಺ଂ Beep ԻεϐʔΧʔͰϝϩσΟϓϨΠϠʔ ը૾͸

    micro:bit ެࣜ Web αΠτ *2 ͱ Python editorɻ ͦͷ΄͔पลػثͱͯ͠ਓܕϩϘοτᝑମ΍ϥδίϯΧʔɺύουೖྗج൫ͳͲͷػث͕֤͔ࣾΒ ൢച͞Ε͍ͯ·͢ɻ೔ຊͷֶߍڭҭݱ৔Ͱൺֱతଟ͘໨ʹ͢Δ΋ͷ͸ϩϘοτΧʔͷλΠϓͰɺԿ Β͔ͷηϯαʹΑͬͯंΛ૸ΒͤΔϓϩάϥϛϯάΛ MakeCodeʢScratch ෩ϒϩοΫϓϩάϥϛϯ άʣͰखॱʹԊ࣮ͬͯફ͢Δͱ͍͏΋ͷʹऔΓ૊ΜͰ͍Δ͜ͱ͕͋Γ·͢ɻ ֶߍڭҭݱ৔ʹͱͬͯ͜ͷखͷֶशڭࡐ͸Ωοτʹͳ͍ͬͯΔ΋ͷΛߪೖͯ͠ॱΛ௥࣮ͬͯફ͢Δ ͔͠ͳ͘ɺઐ໳ՈͰͳ͚Ε͹௨ৗऔΓ૊ΈͮΒ͍΋ͷͰ͢ɻmicro:bit ͸ࠃ಺Ͱॳ୅όʔδϣϯ͕ެ ։͞Ε͔ͯΒ 5 ೥ఔ౓ܦա͍ͯ͠Δ͜ͱ΋͋Γɺωοτ্Ͱར༻ํ๏Λௐ΂Δͱ͍͔ͭ͘ίʔυαϯ ϓϧͳͲΛ໨ʹ͠·͢ɻֶश༻్ͱֶͯ͠ߍͰͷ׆༻ͱͯ͠΋ར༻Ҋ͕঺հ͞Ε͍ͯΔ͜ͱ͕͋Γ· ͕͢ɺ૊Έࠐ·Ε͍ͯΔ͜ͱ͕Ͱ͖Δ͔Λࢼ͢ઌͷൃలతͳల։͸গͳ͍Α͏ʹײ͡ΒΕ·͢ɻ·ͨ ೔ຊͷ৔߹ɺൺֱత໨ʹ͢Δࣄྫ͸पลػثͱ߹Θͤͯൢചఏڙ͞Ε͍ͯͯڭࢣ͕ར༻͠΍͍͢ύο έʔδ඼Λߪೖͯ͠ར༻͍ͯ͠Δ͜ͱ͕͋Γɺຊମ 1 ͭΛϋοΫͯ͠׆༻͍ͯ͘͠܏޲ʹ͸ͳ͍Α͏ Ͱ͢ɻ ຊষͷ࣮ફʹ޲͚ͯ ຊମ 1 ͭ͋Ε͹͖ͬͱ͓΋͠Ζ͍͜ͱ͸Ͱ͖Δͱ͍͏Πϝʔδ͕͋Δ͜ͱͱɺಘҙͱ͢ΔήʔϜͷ ؍఺ͰԿ͔ੜ͔ͤΔΑ͏ͳയવͱͨ͠ՄೳੑΛײͨͨ͡ΊʹऔΓ૊ΈΛ࢝Ί·ͨ͠ɻ࣍ͷઅ͔Β͸͍ ͔ͭ͘ͷΞΠσΞ੾ΓޱͰࢼͯ͠Έͭͭɺࢲ͕ײ͓ͨ͡΋͠ΖΈ΍Մೳੑ͕͜͜Ͱڞ༗Ͱ͖ͨΒ͏Ε ͘͠ࢥ͍·͢ɻ 4.2 ಺ଂ Beep ԻεϐʔΧʔͰϝϩσΟϓϨΠϠʔ *2 https://microbit.org/code/ 32
  34. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.2 ಺ଂ Beep ԻεϐʔΧʔͰϝϩσΟϓϨΠϠʔ εϐʔΧʔ͕಺ଂ͞Ε͍ͯͯ

    Beep Ի͕ൃৼͰ͖Δ͜ͱ͕هࡌ͞Ε͍ͯͨͷͰप೾਺ΛׂΓग़ͯ͠ ԻఔΛͱͬͯϝϩσΟʔʹ͠Α͏ͱߟ͑ͯ࡞੒ͨ͠ͷ͕͜ͷઅͰ͢ɻ݁࿦͔Βݴ͏ͱ music ͱ͍͏ module ͕͋ͬͨʢͳΜͱʣͷͰ΋ͬͱ؆୯ʹ໐ΒͤΔ͜ͱ͕Ͱ͖·ͨ͠ɻ͜͜Ͱ͸ൃԻͱԻ֊ʹର ͢Δཧղͱ࣮ફͱ͍͏໨తʹ͠·͢ɻ Ի֊ Իͷݪཧ͸ɺৼಈͷप೾਺ʢ଎͞ʣ͕Իఔʹɺৼಈͷڧ͕͞ԻྔʹͳΓ·͢ɻυϨϛ͸Ͳ͜ͷप೾ ਺Ͱ͠ΐ͏ɻυϨϛϑΝιϥγυ͸ӳޠදهͰɹ C C# D D# E F F# G G# A A# B ɹͱ 12 Ի Ͱ 1 αΠΫϧΛΦΫλʔϒɻϐΞϊԻҬͰߟ͑Δͱɺ1 ΦΫλʔϒͷपظͰ A0ʢϥʣ͔Β C8ʢυʣ ͘Β͍·Ͱ͋Γ·͢ɻΦΫλʔϒͱΦΫλʔϒ͸प೾਺͕ 1/2 ഒ·ͨ͸ 2 ഒͱɺͪΐ͏Ͳ 1:2 ͷൺ཰ ͰഒʹͳΔؔ܎ɻ1 ΦΫλʔϒͷؒΛۉ౳ʹ 12 ͰׂͬͯԻ֊ΛׂΓৼͬͨͷ͕ฏۉ཯ͱ͍͏νϡʔ χϯάํ๏ͰҰൠతʹ༻͍ΒΕΔํ๏Ͱ͢ɻͲͷप೾਺Λج४ʹઃఆ͢Δ͔Λʮඪ४Իʯͱݴͬͯɺ ࠃࡍࣜදهͰ A4 Λ 440Hz ʹઃఆ͢Δͷ͕࠷΋ϙϐϡϥʔͰ͕͢ίϯαʔτϗʔϧͳͲͰ͸ 442Hz ʹͳ͍ͬͯΔΑ͏Ͱ͢ɻ ܭࢉࣜ͸ Python Ͱදه͢Δͱ f(Hz)=440 * 2 ** n / 12 ͱͳΓ·͢ɻ440 Λഒഒʹ͍ͯ͘͠ ͔ɺn Λ +-12 ͢ΔͱԻҬ্͕͛Լ͛͞Ε·͢ɻ pin_speaker.set_analog_period_microseconds micro:bit ͷεϐʔΧʔ͸ PWM ৴߸ͱ͍͏ৼ෯ͷपظʢmsʣΛࢦఆ͢ΔͨΊɺϒϒϒϒͱ Beep ԻΛͲͷ࣌ؒ։͚Δ͔Λࢦఆ͠·͢ɻԻ֊प೾਺ Hz ͷͭ΋ΓͰ 440,880 ͷΑ͏ͳ 2 ͭͷ৘ใΛ༩͑ Δͱ 2 ͭ໨͕ߴ͍ԻʹͳΒͣϒϒϒͷαΠΫϧ͕஗͘ͳΓԻ͕Լ͕Γ·͢ɻ͜͜Ͱ͸ f(Hz)=440 * 2 ** (12-n) / 12 ɹͱ 12 Իʹରͯ͠ٯʹ͢Δ͜ͱͰԻ֊ʹͰ͖·ͨ͠ɻ ࣮ݱ͍ͨ͠Ի֊Λӳޠදه c,d,e,f,g,a,b Ͱ͔͋ͭ͑ΔΑ͏ఆٛɻ Ի֊ɺʴٳූ c,d,e,f,g,a,b,v = 0,2,4,5,7,9,11,99 // 99 ٳූ ίʔυͷղઆ ॾػೳΛ੝ΓࠐΜͰΩϥΩϥޫΔʙͱ໐ΔϓϨΠϠʔ͕ҎԼͷΑ͏ʹͯ͠׬੒͠·ͨ͠ɻ • Իʢϊʔτʣ͸ͱΓ͋͑ͣ 2 খઅ • set_analog_period_microseconds ɹ͸ ms ࢦఆͳͷͰɹ 1000ʢ=1 ඵʣͰ 1 ഥΛج४ʹ sp eed Ͱ࠶ੜ଎౓ • ϊʔτ௕͕༨നͳͭ͘ͳ͕͍ͬͯΔͱ࣍ͷϊʔτ͕ฉ͑͜ͳ͍ͷͰ 0.9 ࠶ੜɺ0.1 ແԻ • button_a Ͱ࠶ੜɺbutton_b Ͱఀࢭ 33
  35. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.2 ಺ଂ Beep ԻεϐʔΧʔͰϝϩσΟϓϨΠϠʔ •

    write_analog ͰԻྔΛ্͛Լ͛ͯ͠ٳූ Ϧετ 4.1: ͖Β͖Β੕ playe@Pythonr 1: from microbit import * 2: while True: 3: if button_a.is_pressed(): 4: pin = pin_speaker 5: print("pin_speaker") 6: speed = 1000/4 7: power = 25 8: rate = 440*4 9: stp = 0 10: c,d,e,f,g,a,b,v = 0,2,4,5,7,9,11,99 // 99 ٳූ 11: musicstep = [c,c,g,g,a,a,g,v,f,f,e,e,d,d,c,v] 12: while len(musicstep)>stp: 13: note = int(2**((12-musicstep[stp]) / 12) * rate) 14: if musicstep[stp] is not v: 15: pin.write_analog(power) 16: pin.set_analog_period_microseconds(note) 17: print("({}){}".format(stp,note)) 18: sleep(int(speed*0.9)) 19: pin.write_analog(0) 20: sleep(int(speed*0.1)) 21: stp+=1 22: if button_b.is_pressed(): break 23: print("stop") 24: pin.write_analog(0) 25: ׬੒ [YouTube] https://youtu.be/qzfX0eibEKQ 34
  36. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ ͜ͷηϯα͸

    3 ࣠ͷՃ଎౓͕Ճ଎࣌ܭʢaccelerometerʣʹΑͬͯಘΒΕɺͦͷ΄͔౗͍ͯ͠Δ޲ ͖ͱͯ͠׆༻Ͱ͖·͢ɻ ਤͷΑ͏ͳػೳ͔Βɺઐ༻ήʔϜػͱಉ͡Α͏ͳ༡ͼํ͕ఏҊͰ͖ΔՄೳੑ͕͋Γ·͢ɻ͜ͷՃ଎ ౓ηϯα͕͋Δ͜ͱʹΑͬͯ׆࿏͕֨ஈʹ޿͕Δؾ͕͠·͢ɻ Ճ଎౓ͷར༻ʹ͋ͨͬͯ͸ຊػ׬݁Ͱ΋Α͍Ͱ͕͢ɺUnity ͷ 3D ήʔϜͱ࿈ಈͤͯ͞αϯϓϧΛ ࣔ͢͜ͱʹ͠·͢ɻࢼ͘͢͠Έ͸ɺຊମ͔ΒҰఆִؒͰ print ʹΑͬͯ৘ใऔಘ͓͖ͤͯ͞ɺ֎෦ ιϑτ΢ΣΞ͔Β print ৘ใΛऔಘ͢Δ͜ͱʹ͠·͢ɻ Unity ଆ͔Β͸औಘͨ͠ςΩετ৘ใΛ Json ύʔεͯ͠ߏ଄ମʹऩΊΔ͜ͱͱ͠·͢ɻ ίʔυͷ঺հ • accelerometer.get_values ɹ x,y,z ͷՃ଎౓৘ใͰ͢ɻ • accelerometer.get_strength ɹ x,y,Z ͢΂ͯͷ࣠ͷ߹ܭͰ͢ɻ • ૢ࡞ܥ button3 ͭ͸ Bit ϑϥάͰม਺ p ʹೲΊ͍ͯ·͢ɻ • ͦͷ΄͔ʹ΋ accelerometer.current_gesture ɹδΣενϟͱ͍͏ɺγΣΠΫͳͲ໊લΛ࣋ͬ ͨಈ͖΋औಘͰ͖·͕ͨ͠࢖͍·ͤΜɻ 35
  37. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ Ϧετ 4.3: Ճ଎౓ηϯαൃ৴ػ@Pythonʢmicro:bit

    ଆʣ 1: from microbit import * 2: while True: 3: p = 0 4: if button_a.is_pressed(): p+=1 5: if button_b.is_pressed(): p+=2 6: if pin_logo.is_touched(): p+=4 7: axisx,axisy,axisz = accelerometer.get_values() 8: strength = accelerometer.get_strength() 9: # gesture = accelerometer.current_gesture() 10: # gest_histry = accelerometer.get_gestures() 11: print("{},{},{},{},{}" 12: .format(p, axisx,axisy,axisz, strength )) 13: sleep(100) Mac ͰγϦΞϧ઀ଓʢUSBʣΛ֬ೝ͢Δ γϦΞϧ઀ଓ % ls /dev/cu.* >> ls /dev/cu.usbmodem10000 ͜ͷ cu. ɹҎ߱ͷ໊લ͕ݱࡏ઀ଓ͍ͯ͠ΔػثͷγϦΞϧ઀ଓ৘ใͳͷͰ߇͓͖͑ͯ·͢ɻ C#γϦΞϧ Ports ࢖༻͸ System.IO.Ports.SerialPortɻ ʲखॱ 1ʳΧελϜͷ Receiver Ϋϥε͸ SerialPort ΠϯελϯεΛ࡞੒͠ Thread ΞΫγϣϯͰ୺ ຤ͷ message Λड͚औΓ·͢ɻ SerialPortReciever ղઆ • SerialPort Λॴఆͷํ๏ͰΠϯελϯεΛ࡞੒͢Δ • thread Ͱ࣋ଓతʹ message Λड͚औΓ callback ͢Δ 36
  38. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ Ϧετ 4.3: Ճ଎౓ηϯαड৴ΞϓϦ@C#ʢUnity

    ଆʣ ɾSerialPortReciever Ϋϥε 1: using System; 2: using System.Threading; 3: using System.IO.Ports; 4: using UnityEngine; 5: /// <summary> 6: /// SerialPortΠϯελϯεΛ࡞੒ͯ͠ػثͱ઀ଓ͢Δ 7: /// </summary> 8: [Serializable] 9: public class SerialPortReciever 10: { 11: [SerializeField] SerialPort _serial; 12: Thread _thread; 13: public bool enable; 14: public string recieve; 15: public Action<string> onreceiveaction; 16: /// <summary> 17: /// SerialPortΠϯελϯεͷ࡞੒ 18: /// </summary> 19: /// <param name="portName"></param> 20: public static SerialPortReciever Create(string portName) 21: { 22: var r = new SerialPortReciever(); 23: if (r._Create(portName)) 24: { 25: r._thread = new Thread(r.RecieverAct); 26: r._thread.Start(); 27: return r; 28: } 29: else 30: { 31: Debug.LogError("create failure"); 32: return null; 33: } 34: } 35: 36: bool _Create(string portName) 37: { 38: _serial = new SerialPort(); 39: _serial.BaudRate = 115200; 40: _serial.Parity = Parity.None; 41: _serial.DataBits = 8; 42: _serial.StopBits = StopBits.One; 43: _serial.Handshake= Handshake.None; 44: _serial.PortName = portName; 45: try 46: { 47: _serial.Open(); 48: _serial.DtrEnable = true; 49: _serial.RtsEnable = true; 50: _serial.DiscardInBuffer(); 51: _serial.ReadTimeout = 5000; 52: this.enable = true; 37
  39. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ 53: return true;

    54: } 55: catch (Exception e) 56: { 57: Debug.LogError($"failure.. {e}"); 58: _serial.Close(); 59: _serial = null; 60: return false; 61: } 62: } 63: 64: void RecieverAct() 65: { 66: while (enable) 67: { 68: try 69: { 70: recieve = _serial?.ReadLine(); 71: onreceiveaction?.Invoke(recieve); 72: } 73: catch (Exception e) 74: { 75: recieve = e.ToString(); 76: } 77: } 78: } 79: 80: public void Dispose() 81: { 82: enable = false; 83: _thread?.Abort(); 84: _thread = null; 85: _serial?.Close(); 86: _serial = null; 87: } 88: } ʲखॱ 2ʳ࡞੒ͨ͠ SerialPortReciever ʹ֨ೲ͞Εͨ୺຤ͷ message Λࢀরͯ͠ GameObject Λ ੍ޚ͢Δ Player Ϋϥεͱద౰ͳ ObjectʢࠓճαϯϓϧʹඈߦػΛ࡞੒ʣΛ༻ҙ͠·͢ɻ 38
  40. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ SerialPortPlayer ղઆ •

    DeviceContext ߏ଄ମ͸ message ͷ json ύʔε data • Ճ଎౓ܭ৘ใ͸ϒϨ͕ܹ͍͠ͷͰฏۉԽͤͯ͞ SerialPortPlayer.average ͔Βࢀর • σʔλͷసૹϩεස౓͕ߴ͍ͷͰड৴σʔλͷਪଌɾॳظ஋Λ getintvalue Ͱ༩͑Δ • Ճ଎౓ܭ܏͖ͷ͋ͦͼ஋Λ MINB , MINH ʹͯ 0.5 ౓ఔ౓ઃఆ͢Δ Ϧετ 4.3: Ճ଎౓ηϯαड৴ΞϓϦ@C#ʢUnity ଆʣ ɾSerialPortPlayer Ϋϥε 1: using System; 2: using UnityEngine; 3: using System.Collections.Generic; 4: 5: public class SerialPortPlayer : MonoBehaviour 6: { 7: [SerializeField] string portname = "/dev/cu.usbmodem000"; 8: [SerializeField] SerialPortReciever receiver; 9: 10: void Awake() 11: { 12: receiver?.Dispose(); 13: receiver = SerialPortReciever.Create(portname); 14: receiver.onreceiveaction = onreceive; 15: } 39
  41. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ 16: 17: void

    OnDestroy() 18: { 19: receiver?.Dispose(); 20: receiver = null; 21: } 22: string getvalue(string m, string ifempty = "0") 23: => (string.IsNullOrEmpty(m))? ifempty : m; 24: 25: int getintvalue(string m, string ifempty = "0") 26: => int.Parse((string.IsNullOrEmpty(m)) ? ifempty : m); 27: 28: void onreceive(string m) 29: { 30: if (!string.IsNullOrEmpty(m)) 31: { 32: var ms = m.Split(","); 33: if (ms.Length < 5) new Exception(); 34: // jsonԽ 35: var ex ="{"+ $"\"press\":{getintvalue(ms[0])}," + 36: $"\"axisx\":{(float)getintvalue(ms[1])}," + 37: $"\"axisy\":{(float)getintvalue(ms[2])}," + 38: $"\"axisz\":{(float)getintvalue(ms[3])}," + 39: $"\"strength\":{getintvalue(ms[4])}" + 40: "}"; 41: //print(m+"\n"+ex); 42: try 43: { 44: history.Insert(0,JsonUtility.FromJson<DeviceContext>(ex)); 45: if (history.Count > MAXHISTORY) 46: history = history.GetRange(0,SAMPLESIZE); 47: //print(ex+ "\n" + average); 48: } 49: catch(Exception e) 50: { 51: Debug.Log($"format error ({e})\n{m}"); 52: } 53: } 54: } 55: 56: public Vector3 average 57: { 58: get 59: { 60: Vector3 t=Vector3.zero; 61: for (var i = 0; i < SAMPLESIZE; i++) t += history[i].axis; 62: var r = new Vector3(t.x/(float)SAMPLESIZE, 0f, t.z/(float)SAMPLESIZE); 63: return new Vector3( 64: (MINB > r.x || MINH < r.x)? r.x : 0f, 65: (MINB > r.y || MINH < r.y)? r.y : 0f, 66: (MINB > r.z || MINH < r.z)? r.z : 0f 67: ); 68: } 69: } 40
  42. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ 70: [Range(0f, 5f)]

    [SerializeField]float asobi = 0.5f; 71: float MINB => asobi * -1f; 72: float MINH => asobi; 73: [Range(1, 16)] 74: public int SAMPLESIZE = 3; 75: const int MAXHISTORY = 1024; 76: const float MAXVALUE = 1024f; 77: public List<DeviceContext> history 78: = new List<DeviceContext>() { default, default, default, default }; 79: public DeviceContext deviceinput => history.Count>0? history[0]:default; 80: public GameObject target; 81: } 82: [Serializable] 83: public struct DeviceContext 84: { 85: public PressButton press; 86: /// <summary> 87: /// Ճ଎౓͸ʶ2000 88: /// </summary> 89: public int axisx, axisy, axisz; 90: public int strength; 91: public string gesture; 92: public string[] gest_histry; 93: const float ANGLE = -1f; 94: const float ANGLEZ = -3f; 95: /// <summary> 96: /// ӈखܥ࠲ඪ͔Βࠨखܥม׵ 97: /// </summary> 98: public Vector3 axis { get { 99: return new Vector3( 100: ((float)axisy/1024f)*ANGLE, 0f, ((float)axisx/1024f)*ANGLEZ 101: ); 102: }} 103: public bool isA { get { return press.HasFlag(PressButton.A); } } 104: public bool isB { get { return press.HasFlag(PressButton.B); } } 105: public bool isLogo { get { return press.HasFlag(PressButton.LOGO); } } 106: 107: public override string ToString() 108: { 109: return $"{press} ... A:{isA}, B:{isB}, Logo:{isLogo}, " + 110: $"axis:{axis}, gesture:{string.Join(",",gest_histry)}"; 111: } 112: [Flags] 113: public enum PressButton 114: { 115: None = 0, 116: A = 1<<0, 117: B = 1<<1, 118: LOGO = 1<<2 119: } 120: } 41
  43. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ ͦͯ͠ SerialPortPlayer ΫϥεͰड৴ͨ͠ճస৘ใΛ

    GameObject ʹ༩͑Δ Airplane Ϋϥεɻ • b ϘλϯɿՃ଎ • a Ϙλϯɿݮ଎ • logo ϘλϯɿϦηοτ • ϐονʢඓઌͷ্ঢԼ߱ʣͱϩʔϧʢ͉࣠ճసʣʹಠཱͨ͠ speed ઃఆ Ϧετ 4.3: Ճ଎౓ηϯαड৴ΞϓϦ@C#ʢUnity ଆʣ ɾAirplane Ϋϥε 1: using System.Collections; 2: using System.Collections.Generic; 42
  44. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ 3: using UnityEngine;

    4: using System; 5: using static UnityEngine.GraphicsBuffer; 6: 7: public class Airplane : MonoBehaviour 8: { 9: [Range(1f, 1000f)] public float speed = 500f; 10: [Range(1f, 10f)] public float boostspeed = 5.0f; 11: [Range(-10f, 0f)] public float breakingspeed = -10f; 12: [Range(1f, 180f)] public float rotatespeed = 45f; 13: [Range(1f, 180f)] public float headupespeed = 66f; 14: [SerializeField] public Rigidbody rb; 15: [SerializeField] SerialPortPlayer player; 16: 17: [ContextMenu("Reset Rotation")] 18: void ResetRotation() => this.rb.rotation = Quaternion.identity; 19: [ContextMenu("Reset Transform")] 20: void ResetTransform() { 21: Debug.Log("reset trasf"); 22: rb.position = Vector3.up* 200f; 23: rb.rotation = Quaternion.identity; 24: rb.velocity = Vector3.zero; 25: rb.angularVelocity = Vector3.zero; 26: } 27: 28: // Start is called before the first frame update 29: void Start() 30: { 31: player = GameObject.FindObjectOfType<SerialPortPlayer>(); 32: rb = gameObject.GetComponent<Rigidbody>(); 33: } 34: 35: // Update is called once per frame 36: void FixedUpdate() 37: { 38: // logo reset 39: if (player.deviceinput.isLogo) 40: { 41: ResetTransform(); 42: return; 43: } 44: // A button ϒϨʔΩ, B button accel 45: float boost = player.deviceinput.isB && !player.deviceinput.isA ? 46: boostspeed: (player.deviceinput.isA? breakingspeed : 1f); 47: // rotation 48: if (player && player.history.Count >= player.SAMPLESIZE) 49: { 50: //Debug.Log(player.average); 51: Quaternion r = rb.rotation; 52: rb.rotation *= Quaternion.Euler( 53: 0f, 54: 0f, 55: player.average.z * this.rotatespeed * Time.deltaTime 56: ) 43
  45. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.3 Ճ଎౓ηϯαͰମݧܕήʔϜίϯτϩʔϥ 57: * Quaternion.Euler(

    58: player.average.x * this.headupespeed * Time.deltaTime, 59: 0f, 60: 0f 61: ); 62: } 63: // accel 64: #if true 65: rb.AddRelativeForce(Vector3.forward * speed * boost, ForceMode.Acceleration); 66: if (Vector3.Dot(rb.velocity,rb.transform.forward.normalized)<0f) 67: { 68: rb.velocity = transform.forward * speed; 69: } 70: #endif 71: } 72: } ࣮ߦ݁Ռ [YouTube ᶃճస͚ͩςετ] https://youtu.be/6SklthRLp44 [YouTube ᶄՃ଎͋Γ׬੒൛] https://youtu.be/tMFQ0KQosSc 44
  46. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.4 ϚΠίϯνοϓ୯ಠϛχήʔϜ੍࡞ 4.4 ϚΠίϯνοϓ୯ಠϛχήʔϜ੍࡞ ϓϩάϥϜΛసૹͯ͠ه࿥Ͱ͖Δ͜ͱͱɺઐ༻ి஑

    box Ͱڅి͢Ε͹ελϯυΞϩʔϯͷܞଳήʔ Ϝػͱͯ͠ػೳ͢Δ༁Ͱ͢ɻهԱ༰ྔ͸ V2 Ͱ Flash ROM 512KB ʗ RAM 128KB ͱ͍͏͜ͱͳ ͷͰϓϩάϥϜຊମ͚ͩͰ͋Ε͹͍ͩͿऩ·Δ༰ྔͷΑ͏Ͱ͢ɻ͓ࢼ͠ʹ୯ମͰಈͪ͘ΐͬͱʮ͓΋ ͠Ζ͍ʯήʔϜΛ࡞ͬͯΈ͍ͨͱࢥ͍·͢ɻ ήʔϜΠϝʔδ • 5x5dot མͪ΋ͷΞΫγϣϯήʔϜ • dot ͕গͳ͍͜ͱ͕ٯʹࣦഊ·Ͱͷ༛༧͕গͳ͓ͯ͘΋͠Ζͦ͏ • beep Ի͕໐ΔͱҰपճͬͯΫʔϧͳͷͰϓϨΠϑΟʔυόοΫͱͯ͠ੵۃతʹ໐Β͢ • མԼ଎౓͕೉қ౓ʹͳΓϓϨΠΛ੝Γ্͛Δ DROPGAME ࢓༷ • ԣ dot ҐஔΛϥϯμϜʹબग़͠ 1dot ͷো֐෺<obstacle>Λੜ੒ • ࠷্෦͔ΒҰఆ࣌ؒͰ 1dot ͣͭམԼʢbeepʣ • ߴ͞ 5dot Λ௒͑ͨΒ GameOverʢbeepʣ • ࠷Լߦʹ 1dot ͷ<player>Λ഑ஔ • ຊମϘλϯ a/b ͰࠨӈҠಈͯ͠<player>͕<obstacle>Λ৯΂ΒΕͨΒةػΛճආʢbeepʣ • 3 ͭ৯΂Δ͝ͱʹ LevelUp ͯ͠<obstacle>མԼ଎౓্͕͕Δ ήʔϜʹར༻͢Δ micro:bit ཁૉ • button_aʢࠨϘλϯʣ • button_bʢӈϘλϯʣ • display LED 5 x 5 dot 45
  47. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.4 ϚΠίϯνοϓ୯ಠϛχήʔϜ੍࡞ • speaker Ϧετ

    4.3: ϚΠίϯνοϓ DROPGAME@Python 1: from microbit import * 2: import random 3: MAX = 4 4: MAXLEVEL = 10 5: SCOREMAX = 3 6: x,y=0,0 7: px,py=int(2/MAX),MAX 8: x = random.randint(0,MAX) 9: steprate= [10,5,4,3,2,1,0.75,0.5,0.25,0.1] 10: level = 0 11: score = 0 12: def beep(pt): 13: pin_speaker.write_analog(10) 14: pin_speaker.set_analog_period_microseconds(pt) 15: sleep(100) 16: pin_speaker.write_analog(0) 17: 18: def gameover(): 19: print("game over") 20: for xx in range(MAX+1): 21: for yy in range(MAX+1): 22: display.set_pixel(xx,yy,9) 23: 24: while True: 25: display.clear() 26: display.set_pixel(x,y,5) 27: if button_a.is_pressed() or button_b.is_pressed(): 28: px += -1 if button_a.is_pressed() else 1 if button_b.is_pressed() else 0 29: px = max(0,min(MAX,px)) 30: display.set_pixel(px,py,9) 31: if px==x and py==y: 32: print("hit") 33: score +=1 34: if score>=SCOREMAX: 35: level += 1 36: level = min(MAXLEVEL,level) 37: score = 0 38: beep(880) 39: else: 40: beep(440) 41: 42: y = 0 43: x = random.randint(0,MAX) 44: else: 45: y+=1 46: if y>MAX: 47: beep(440*30) 48: gameover() 49: break 46
  48. ୈ 4 ষ micro:bit ͷ͓΋͠Ζ׆༻ߟࠪ 4.5 ऴΘΓʹ 50: beep(220) 51:

    sleep(100*steprate[level]) ࣮ߦ݁Ռ [YouTube] https://youtu.be/fbkDtBVP4Y0 4.5 ऴΘΓʹ ࠓճ͸ USB ઀ଓͰͷݕূͰ͕ͨ͠ɺຊମ੍ޚʹར༻ͨ͠ micro:bit αΠτͷ Python editor 3.0 ʹ͓͍ͯຊػʹରͯ͠ Bluetooth ͷൃ৴͕Ͱ͖ͳ͍Α͏ͩͬͨͨΊɺ࣌ظΛΈͯɺผͷखஈΛऔΔͳ Ͳͯ͠ Bluetooth ෳ਺୆઀ଓͰ΋ͬͱ͓΋͠Ζ͍࣮ݧΛͯ͠ΈΑ͏ͱࢥ͍·͢ɻ ࠓճར༻ͨ͠ Python ίʔυͱ Unity ϓϩδΣΫτ͸ҎԼͷ GItHub ʹެ։͍ͯ͠·͢ɻڵຯ͕ ͋Δํ͸ͥͻ͓ࢼ͍ͩ͘͠͞ɻ [GitHub] https://github.com/akira-tanabe/mb_serialport_app_1 47
  49. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠ σΞ 5.1 ChatGPT

    ͔Β GPT-4 ͕ϦϦʔε 2023 ೥ 3 ݄ 15 ೔ɺChatGPT Plus Ϣʔβʔ޲͚ʹɺGPT-4 Ϟσϧ͕ར༻Ͱ͖ΔΑ͏ʹͳΓ·͠ ͨɻGPT-4 ʹΑΔΞ΢τϓοτʹ౓؊Λൈ͔Εͨࢲ͸ɺຖ೔นଧͪ૬खͱͯ͠࢖͍ͬͯ·͢ɻฐࣾ Ͱ͸ QAASAʢQuality Assurance Advanced Support Agencyʣͱ͍͏ɺ෦ॺΛ௒͑ͨ QA Τϯδ χΞͲ͏͠ͷ׆ಈ͕͋ΔͷͰ͕͢ɺͦ͜Ͱ ChatGPT ΛͲͷΑ͏ʹ׆༻Ͱ͖Δ͔࿩͠߹͓͏ʂ ͱࢲ ͕੠Λ͔͚ɺΞΠσΞΛूΊ·ͨ͠ɻ ʢ2023 ೥ 4 ݄ݱࡏɺMIXI ͸ɺٕज़มֵʹΑΔߟ͑΍ൃ૝ͷΞ ϯϥʔχϯάʹ޲͚৽͍ٕ͠ज़ʹ׳Ε਌͠ΜͰ΋Β͏͜ͱΛ໨తʹɺ౰ࣾͷਖ਼ࣾһɺܖ໿ࣾһΛର ৅ʹ 2023 ೥ 4 ݄͔Β໿ 3 ϲ݄ؒʮChatGPT Plusʯͷֹ݄ར༻ྉΛิॿ͞Ε͍ͯ·͢ʣຊߘͰ͸ ChatGPT Λ QA ΤϯδχΞ͕࢖͏ͱͨ͠ΒɺͲͷΑ͏ͳ࢖͍ํ͕Ͱ͖ΔͷͩΖ͏͔ʁ ͱ͍͏ٙ໰ ͔Βੜ·ΕͨΞΠσΞɺͦΕʹ΋ͱ͍ͮͯࢲ͕࣮ફͨ͠ྫΛ঺հக͠·͢ɻ ͜ͷΑ͏ͳ࢖͍ํ͕Ͱ͖ͦ͏ʂ QAASA ͷ׆ಈͰ͸ҎԼͷΑ͏ͳΞΠσΞ͕ڍ͕͍ͬͯ·ͨ͠ɻ • Selenium ΁ͷೖ໳ฤͱͯ͠ɺϒϥ΢βͷ؆୯ͳςετΛॻ͍ͯ΋Β͏ • ϖΞϫΠζ๏Ͱ࠷খݶͷ૊Έ߹ΘͤͷύλʔϯΛ࡞ͬͯ΋Β͏ • ςετέʔεΛಡ·ͤͯɺςετ؍఺Λநग़ͯ͠΋Β͍ɺ͞ΒʹϚΠϯυϚοϓͱͯ͠ग़ྗ͠ ͯ΋Β͏ ࿩͠߹͍ΛਐΊ͍ͯ͘தͰɺςετϓϩηε͝ͱʹݕ౼ͨ͠ͱ͜ΖΞΠσΞ͕ൃࢄͨ͠ҝɺ߲࣍ʹ ͯৄ͘͠঺հக͠·͢ɻ 49
  50. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.2 ςετϓϩηε͝ͱͷ׆༻ΞΠσΞ 5.2

    ςετϓϩηε͝ͱͷ׆༻ΞΠσΞ ςετϓϩηεͷ͏ͪʮςετܭըʯ ʮςετ؅ཧʢϞχλϦϯάͱίϯτϩʔϧʣ ʯ ʮςετ෼ੳʯ ʮςετઃܭʯ ʮςετ࣮૷ʯ ʮςετ࣮ߦʯʹ͍ͭͯ࿩ΛਐΊ·͢ɻ ςετܭըͰͷ׆༻ ςετܭըͰ͸ɺ·ͣɺաڈͷϓϩδΣΫτ͕σʔλϕʔεԽ͞Ε͍ͯΕ͹ɺͦΕΛ׆༻ͯ͠ࠓճ ͷϓϩδΣΫτͱྨࣅͨ͠ϓϩδΣΫτΛ ChatGPT ʹݕࡧΛͤ͞Δ͜ͱ͕Ͱ͖ΔͷͰ͸ͳ͍͔ʁ ͱਪଌ͠·ͨ͠ɻྨࣅͷςετ໨త/ςετର৅ΛࢀরͰ͖Ε͹ɺࠓճͷϓϩδΣΫτʹ౰ͯ͸Ίͯɺ ඞཁͳ޻਺΍εέδϡʔϧɺςετΞϓϩʔνΛࡦఆ͢Δखॿ͚ʹͳΔ͸ͣͰ͢ɻ ςετ؅ཧͰͷ׆༻ ςετ؅ཧͰ͸ɺςελʔ͔Βͷద੾ͳใࠂΛଅ͢ͷʹ׆༻Ͱ͖ͦ͏ɺͱ͍͏ҙݟ͕͋Γ·ͨ͠ɻ Slack ͳͲͷνϟοτπʔϧͱ ChatGPT ͕࿈ܞ͞Εͯར༻Ͱ͖ΔΑ͏ʹͳΕ͹ɺAI ͷ bot ͔Βʮਐ ௙͸Ͳ͏Ͱ͔͢ʁ Կ͔ؾʹͳͬͨ͜ͱ͸͋Γ·͔͢ʁʯͷΑ͏ʹ࿩͔͚ͯ͠΋Β͏͜ͱ͕Ͱ͖ɺର ࿩Λ௨ͯ͡ࠓ͙͢Ϧʔμʔʹใࠂ͢Δ or ༦ձͰใࠂ͢Δɺͱ͍͏൑அ͕Ͱ͖Δͱྑͦ͞͏ɺͱ͍͏ ΞΠσΞͰ͢ɻ ςετ෼ੳͰͷ׆༻ ςετ෼ੳͰ͸ɺςετϕʔεʢ࢓༷ॻ΍ JIRA νέοτͷ಺༰ɺϛʔςΟϯάͷٞࣄ࿥ͳͲʣΛ ΋ͱʹͲͷΑ͏ͳςετ͕ඞཁ͔ݕ౼͠·͕͢ɺ͢ͰʹϦϦʔε͞Ε͍ͯΔαʔϏεͰ͋Ε͹ɺόά τϥοΩϯάγεςϜʢBTSʣͱ ChatGPT Λ࿈ܞͯ͠ɺӨڹൣғͷը໘ɾػೳͰൃੜͨ͠աڈͷෆ ۩߹΍໰୊ͷ·ͱΊΛग़ͯ͠΋Β͏͜ͱ͕Ͱ͖ΔͰ͠ΐ͏ɻ͔ͦ͜ΒɺରԠ͢΂͖ςετΛݕ౼͠΍ ͘͢ͳΔͱظ଴͍ͯ͠·͢ɻ ςετϕʔεΛ ChatGPT ʹಡΈࠐ·ͤΔ͜ͱ͕Ͱ͖Ε͹ɺ৽ػೳͷϢʔεέʔε΍Ϣʔβʔε τʔϦʔΛ࡞੒ͯ͠΋Β͏͜ͱ΋Ͱ͖·͢ɻ͔ͦ͜Βຊདྷͷཁٻʹద߹͍ͯ͠Δͷ͔֬ೝͨ͠Γɺ࢓ ༷ॻͰݴٴ͞Ε͍ͯͳ͍Օॴʹؾ෇͚ͨΓɺͱ͍ͬͨ͜ͱ΋Ͱ͖ΔͰ͠ΐ͏ɻ͞Βʹӡ༻ɾอकੑ΍ ηΩϡϦςΟͱ͍ͬͨඇػೳͷ؍఺Ͱ΋ ChatGPT ͷ׆༻͕ظ଴Ͱ͖·͢ɻ QA ͸ಠࣗͷςετ؍఺ϦετʢνΣοΫϦετʣΛ͍࣋ͬͯ·͢ɻͦͷϦετ͸͞·͟·ͳϢʔ εέʔεΛߟྀ͍ͯ͠·͢ɻैདྷ͸ͦͷϦετΛϓϥϯφʔʹڞ༗ͯ͠ݟͯ΋Β͏ͷΈͰ͕ͨ͠ɺ ChatGPT Λ׆༻͢Δ͜ͱͰಥ͖߹Θͤ·Ͱ࣮ࢪͰ͖Ε͹ɺ࢓༷ॻΛิ׬͠ɺ࣮૷ޙʹݕ౼࿙Ε͕ൃ ֮ͯ͠͠·͏ͱ͍͏ࣄނΛ๷͙͜ͱ͕ՄೳͱͳΓ·͢ɻ ςετઃܭͰͷ׆༻ ςετઃܭʹ͓͍ͯ΋ɺ΍͸Γࣗ෼ʹͳ͍ࢹ఺΍ح૝ఱ֎ͳΞΠσΞΛҾ͖ग़ͯ͠΋Β͏͜ͱΛظ ଴͍ͯ͠·͢ɻͨͱ͑͹ʮϢʔβʔ໊Λೖྗ͢Δʯͱ͍͏Ϣʔεέʔεͷ৔߹ɺChatGPT ʹʮ͜ͷ Ϣʔεέʔεʹ͍ͭͯςετ؍఺Λڍ͍͛ͯͩ͘͞ʯͱࢦࣔ͢Ε͹ɺ಺༰ʹԠͨ͡ػೳͷૢ࡞΍ը໘ 50
  51. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.2 ςετϓϩηε͝ͱͷ׆༻ΞΠσΞ ͷભҠͷύλʔϯΛڍ͛ͯ͘Ε·͢ɻ͞Βʹʮਖ਼ৗܥ͓ΑͼҟৗܥͷςετΛߟྀ͍ͯͩ͘͠͞ʯͱ

    ௥ՃͰࢦࣔ͢Ε͹؍఺Λ૿΍͢͜ͱ͕Ͱ͖·͢ɻ؍఺͕ͦΖ͖ͬͯͨΒɺ ʮϚΠϯυϚοϓͰݟΕΔ Α͏ʹ PlantUML Ͱग़ྗ͍ͯͩ͘͠͞ʯͱࢦࣔ͢ΔͱɺϚΠϯυϚοϓʹม׵ՄೳͳܗࣜͰग़ྗ͠ ͯ͘Ε·͢ɻ ςετઃܭ࣌ͷ੒Ռ෺ʢϚΠϯυϚοϓͳͲʣΛ ChatGPT ʹಡΈࠐ·ͤͯɺཁ໿Λ࡞੒ͯ͠΋Β ͑Ε͹ɺॏෳ΍ෆ଍͍ͯ͠ΔςετΛු͖ூΓʹ͢Δ͜ͱ͕ظ଴Ͱ͖·͢ɻ͜Ε͸ςετͷϨϏϡʔ Ͱ͋ΓɺChatGPT Λ 1 ਓ໨ͷϨϏϡΞʔͱͯ͠׆༻Ͱ͖·͢ɻ΋ͪΖΜςετ׆ಈͰ͸ਓؒʹ΋Ϩ Ϗϡʔͯ͠΋Β͍·͕͢ɺࠓ͙͢ʹ࣮ࢪͰ͖Δͱ͍͏఺ͰϝϦοτ͕͋Γ·͢ɻ ςετ࣮૷Ͱͷ׆༻ ςετ࣮૷Ͱ͸ɺςετσʔλͷੜ੒ʹ໾ཱͯΔ͜ͱ͕Ͱ͖·͢ɻμϛʔσʔλΛ࡞Γ͍ͨ৔߹ ͸ɺग़ྗΛ csv ܗࣜͰࢦఆ͠ɺϔομͱ஋ͱ஋ͷൣғ΋ࢦఆ͢Ε͹ɺ͙͢ʹͦΕΒ͍͠σʔλΛੜ੒ Ͱ͖·͢ɻQA ͸͓ख੡Ͱ Google εϓϨουγʔτͰσʔλϕʔεΛ࡞͍ͬͯΔ͜ͱ͕Α͋͘Γ· ͢ɻ ʢΩϟϥΫλʔҰཡɺΞΠςϜҰཡɺεςʔδҰཡͳͲɺ߈ུαΠτͷΑ͏ͳ৘ใΛهࡌ͍ͯ͠ ΔʣͦͷεϓϨουγʔτΛಡΈࠐ·ͤΔ͜ͱ͕Ͱ͖Ε͹ɺग़ྗ಺༰ͷࢦఆ΋༰қʹͳΔͰ͠ΐ͏ɻ ʢͨͩڥք஋ςετͳͲɺݫີʹ஋Λܾఆͯ͠ςετΛ͍ͨ͠৔߹ɺChatGPT ʹੜ੒ͤͨ͞σʔλ Ͱ͸ͦΕΛਫ਼ࠪ͢Δख͕ؒൃੜ͢ΔͨΊɺࣗ෼Ͱ࡞ͬͨํ͕ૣ͍ͱײ͡·͢ʣ ςετ؅ཧπʔϧΛ࢖ͬͯςετέʔεΛ࡞੒͢ΔࡍɺTestrail ͳͲπʔϧʹΑͬͯ͸ςετέʔ εҰͭҰͭʹରͯ͠ݸผͷλΠτϧΛ෇͚Δඞཁ͕͋Γ·͢ɻͦͷࡍɺChatGPT ʹςετखॱ΍ظ ଴݁ՌΛݩʹɺλΠτϧΛ࡞੒ͯ͠΋Β͑Δͱॿ͔Γ·͢ɻ ςετ࣮ߦͰͷ׆༻ ςετ࣮ߦͰ͸ɺෆ۩߹Λݟ͚ͭͨࡍʹɺͦͷෆ۩߹͕͢Ͱʹใࠂ͞Ε͍ͯΔ͔Ͳ͏͔ɺόάτ ϥοΩϯάγεςϜ্Ͱݕࡧ͢Δ͜ͱ͕Α͋͘Γ·͕͢ɺΩʔϫʔυ΍ΧςΰϦͳͲͰݕࡧͨ͠ࡍʹ ώοτ͠ͳ͍৔߹͕͋Γ·͢ɻ͜Εʹର͠όάτϥοΩϯάγεςϜͱ ChatGPT Λ࿈ܞ͢Δ͜ͱ Ͱɺ͍͋·͍ݕࡧ͕Ͱ͖ΔΑ͏ʹͳΔ͜ͱΛظ଴͍ͯ͠·͢ɻ ෆ۩߹Λىථ͢Δࡍʹ͸ɺChatGPT ʹจষΛϨϏϡʔͯ͠΋Β͏͜ͱ͕Ͱ͖·͢ɻಡΈखʹ఻Θ Δ಺༰ʹͳ͍ͬͯΔ͔ɺ࠶ݱखॱ΍؀ڥͷઆ໌ͷෆ଍͕ͳ͍͔ͳͲɺͰ͢ɻ ҎԼ͸ ChatGPT ͷ GPT-4 ʹόάϨϙʔτΛϨϏϡʔͤͨ͞ྫͰ͢ɻͳ͓ɺνΣοΫ߲໨͓Αͼ ϨϏϡʔର৅ͷόάϨϙʔτ΋ ChatGPT ʹߟ͑ͯ΋Β͍·ͨ͠ɻ user: νΣοΫϦετ: 1.λΠτϧ ɾΘ͔Γ΍͘͢؆ܿͰɺ۩ମతͳόά಺༰ɺػೳ໊ɺൃੜՕॴʢը໘΍γʔϯʣ ɺτϦΨʔ΍৚ؚ͕݅·Ε͍ͯΔ ͔ ɾλΠτϧ͚ͩͰόά಺༰͕ਪଌͰ͖Δ͜ͱ 2.ৄࡉͳઆ໌ ɾ࠶ݱखॱ΍৚͕݅໌֬ɺظ଴͢Δಈ࡞͕هࡌ͞Ε͍ͯΔ͔ 51
  52. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.2 ςετϓϩηε͝ͱͷ׆༻ΞΠσΞ ɾจষΛ؆ܿʹอͪɺ৘ใ͕੔ཧ͞Ε͍ͯΔ͜ͱ

    3.؀ڥ৘ใ ɾOSɺϒϥ΢βɺΞϓϦόʔδϣϯ͕هࡌɺσόΠε΍ωοτϫʔΫ؀ڥ͕ඞཁͰ͋Ε͹هࡌ͞Ε͍ͯΔ͔ ɾඞཁҎ্ͷ৘ใ͸هࡌ͠ͳ͍͜ͱ 4.৘ใͷ໌֬ੑ ɾ͢΂ͯͷ৘ใ͕໌֬Ͱ෼͔Γ΍͍͢ݴ༿Ͱهࡌ͞Ε͍ͯΔ͔ ɾҰൠతͰͳ͍༻ޠ΍ུޠ͕ආ͚ΒΕ͍ͯΔ͜ͱ ࢦࣔɿ ҎԼͷόάϨϙʔτΛɺ্هͷνΣοΫϦετʹ΋ͱ͍ͮͯϨϏϡʔ͍ͯͩ͘͠͞ɻ ෼͔ΓͮΒ͔ͬͨΓ۩ମతͰͳ͍هड़͕͋Ε͹ڭ͍͑ͯͩ͘͞ɻ όάϨϙʔτ಺༰: 1.λΠτϧ: ήʔϜதʹϓϨΠϠʔΩϟϥΫλʔ͕ফ͑Δόά͕ൃੜ͢Δ 2.ৄࡉͳઆ໌: ϓϨΠதʹɺϓϨΠϠʔΩϟϥΫλʔ͕ফ͑ͯ͠·͏όά͕ൃੜ͠·͢ɻ࠶ݱखॱ͸ҎԼͷ௨ΓͰ͢ɻ - ήʔϜΛىಈ͢Δɻ - ήʔϜதʹϓϨΠϠʔΩϟϥΫλʔΛૢ࡞͢Δɻ - ͠͹Β͘ϓϨΠ͢ΔͱɺϓϨΠϠʔΩϟϥΫλʔ͕ը໘͔Βফ͑ͯ͠·͏͜ͱ͕͋Δɻ ظ଴͢Δಈ࡞͸ɺϓϨΠϠʔΩϟϥΫλʔ͕ਖ਼ৗʹදࣔ͞ΕɺϓϨΠ͕εϜʔζʹਐߦ͢Δ͜ͱͰ͢ɻ 3.؀ڥ৘ใ: OS: Windows 10 ϒϥ΢β: Google Chrome ήʔϜόʔδϣϯ: 1.2.3 assistant: νΣοΫϦετʹ΋ͱ͍ͮͯϨϏϡʔΛߦ͍ɺҎԼͷϙΠϯτ͕վળ͞ΕΔͱΑΓ෼͔Γ΍͍͢όάϨϙʔτʹ ͳΓ·͢ɻ 1.λΠτϧ: λΠτϧ͸ɺ֓ͶΘ͔Γ΍͘͢؆ܿʹॻ͔Ε͍ͯ·͕͢ɺൃੜՕॴʢը໘΍γʔϯʣ ɺτϦΨʔ΍৚ؚ͕݅·Ε ͍ͯ·ͤΜɻҎԼͷΑ͏ʹमਖ਼͢ΔͱɺΑΓ۩ମతʹͳΓ·͢ɻ ྫ:ʮϝΠϯը໘ͰͷϓϨΠதɺҰఆ࣌ؒܦաޙʹϓϨΠϠʔΩϟϥΫλʔ͕ফ͑Δόάʯ 2.ৄࡉͳઆ໌: ࠶ݱखॱʹ͍ͭͯɺ۩ମతͳૢ࡞΍γʔϯɺ৚݅Λ௥Ճ͢Δͱɺ͞Βʹ໌֬ʹͳΓ·͢ɻͨͱ͑͹ɺҎԼͷΑ͏ ʹमਖ਼Ͱ͖·͢ɻ - Ͳͷεςʔδ΍γʔϯͰൃੜ͢Δͷ͔ - ಛఆͷૢ࡞΍ΞΠςϜΛ࢖༻͍ͯ͠Δ࣌ʹൃੜ͢Δͷ͔ - ϓϨΠϠʔΩϟϥΫλʔ͕ফ͑ΔલʹԿ͔ಛఆͷݱ৅΍ΤϑΣΫτ͕͋Δͷ͔ 3.؀ڥ৘ใ: ؀ڥ৘ใ͸ɺඞཁͳ৘ใ͕ద੾ʹهࡌ͞Ε͍ͯ·͢ɻσόΠε΍ωοτϫʔΫ؀ڥ͕ؔ܎͍ͯ͠Δ͔Ͳ͏͔ʹͭ ͍ͯ΋ɺ֬ೝ͠௥ه͢Δͱྑ͍Ͱ͠ΐ͏ɻ 4.৘ใͷ໌֬ੑ: ৘ใ͸֓Ͷ໌֬Ͱ෼͔Γ΍͍͢ݴ༿Ͱهࡌ͞Ε͍ͯ·͢ɻͨͩ͠ɺ࠶ݱखॱ΍৚݅ʹ͍ͭͯ͸ɺ͞Βʹ۩ମతͳ ৘ใΛఏڙ͢Δ͜ͱͰɺ։ൃऀ͕όάΛಛఆ͠΍͘͢ͳΓ·͢ɻ 52
  53. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.3 ৼΓฦΓͰͷ׆༻ΞΠσΞ 100

    ఺ຬ఺Ͱਓؒͷग़Δນ͸ͳ͍ʂ ͱ͍͏݁ՌͰ͸͋Γ·ͤΜ͕ɺ͜ͷΑ͏ͳϨϏϡʔΛؾܰʹɺ ԿճͰ΋ར༻Ͱ͖Δͱ͍͏఺Ͱߟ͑Ε͹ɺδϡχΞϨϕϧͷςελʔ͸େॿ͔ΓͰ͠ΐ͏ɻ ·ͨόάϨϙʔτͷλΠτϧΛ୹͍ͨ͘͠৔߹͕͋Γ·͢ɻ ʢόάτϥοΩϯάγεςϜʹΑͬͯ ͸จࣈ਺੍ݶ͕͋ͬͨΓ͠·͢ʣͦͷ৔߹͸ҎԼͷΑ͏ʹࢦࣔ͢Δ͜ͱͰɺςΩετΛվળͯ͘͠Ε ·͢ɻ user: ҎԼͷจষ͸όάνέοτͷλΠτϧͰ͢ɻίϯςΩετΛਖ਼֬ʹ఻͑ΔͨΊɺ෼͔Γ΍͘͢໌ྎͳจষ΁Ϧϥ Πτ͍ͯͩ͘͠͞ɻ ϓϨΠϠʔ͕͋ΔότϧΛऴΘΒͤΑ͏ͱͨ࣌͠ɺຯํ͕ಟͷঢ়ଶҟৗʹ͔͔͍ͬͯͯΤϑΣΫτ͕ग़͍ͯΔ৔ ߹ɺήʔϜ͕͍͖ͳΓΫϥογϡͯ͠͠·͍ɺότϧ͸ΫϦΞͨ͜͠ͱʹͳ͍ͬͯͳ͍ assistant: ϓϨΠϠʔ͕ότϧऴྃ࣌ɺຯํ͕ಟঢ়ଶΤϑΣΫτதͷ৔߹ɺήʔϜ͕ಥવΫϥογϡ͠ɺότϧΫϦΞ͕ະ ׬ྃʹͳΔ ͜ͷΑ͏ͳ࢖͍ํ͸ɺόάϨϙʔτʹݶΒͣνϟοτ΍ϝʔϧͳͲจࣈίϛϡχέʔγϣϯશൠͰ ׆༻Ͱ͖·͢ɻࢲ͸ ChatGPT Λར༻͢Δࡍ͸Ի੠ͰςΩετೖྗ͍ͯ͠·͢ɻಠΓݴΛͨ͘͞Μ ͨ͠ͷͪɺͦΕΛਖ਼͍͠೔ຊޠʹ௚͠ɺ৑௕ͳදݱΛ࡟ͬͯ΋Β͏ɺͱ͍͏ܗͰ׆༻͍ͯ͠·͢ɻ 5.3 ৼΓฦΓͰͷ׆༻ΞΠσΞ ςετҎ֎ͷ׆ಈʹ໨Λ޲͚ΔͱɺϛʔςΟϯά͕͋Γ·͢ɻৼΓฦΓͰ ChatGPT ͕׆༻Ͱ͖ Δͱࢥ͍·͢ɻ ChatGPT ͱͷ 1on1 ৼΓฦΓ͸ 1 εϓϦϯτɺ1 όʔδϣϯͱ͍ͬͨઅ໨Ͱ։࠵͞Ε·͕͢ɺৼΓฦΓͷϛʔςΟϯά ·ͰʹɺࠓճԿ͕͚͋ͬͨͬʜͱࢥ͍ฦ͢४උ͕ඞཁͰ͢ɻ͜ͷ࣌ࣗ໰ࣗ౴͢Δ୅ΘΓʹ ChatGPT ʹ࣭໰Λͯ͠΋Β͏ํ๏͕͋Γ·͢ɻͭ·Γ ChatGPT ͱͷ 1on1 Ͱ͢ɻͨͱ͑͹ҎԼͷΑ͏ͳϓϩ ϯϓτʢChatGPT ʹೖྗ͢ΔςΩετʣΛຖ೔ۀ຿ऴྃલʹ࢖༻͠·͢ɻ user: #ϧʔϧ ChatGPT͸ϝϯλʔͱͯ͠ৼΔ෣͍ɺࢲͷࠓ೔ͷۀ຿ͷ੒ՌΛฉ͍͍ͯͩ͘͞ɻ ࢲͷճ౴͸ޙ೔ৼΓฦΓͰར༻͢Δ͜ͱ͕͋Γ·͢ɻ ΠϯτϩμΫγϣϯͷ௨Γʹ։࢝͠ɺ࠷ॳͷ࣭໰Λ͍ͯͩ͘͠͞ɻ ࢲͷճ౴Λฉ͍ͯɺϙδςΟϒͳϑΟʔυόοΫΛฦͭͭ͠ɺ ந৅తͳՕॴΛਂ۷Γͯ࣍͠ͷ࣭໰Λ͍ͯͩ͘͠͞ɻ ࣭໰ͷΩʔϫʔυ͸͋͘·ͰྫͰ͢ɻࢲͷճ౴ͷ಺༰ʹԠͯ͡దٓมߋor௥Ճ͍ͯͩ͘͠͞ɻ 53
  54. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.4 ࣮ફʂ ެࣜαΠτͷ͓஌ΒͤνΣοΫ

    #ΠϯτϩμΫγϣϯ ࠓ೔΋Ұ೔͓ർΕ༷Ͱͨ͠ɻࠓ೔ͷৼΓฦΓΛ͠·͠ΐ͏ɻ #ձ࿩ͷऴྃ৚݅ ɾ࣭໰ͷճ౴͕3ճߦΘΕΔ ·ͨ͸ ɾࠓ೔͸΋͏্͕Γ·͢ͱࢲ͕એݴ͢Δ #ऴྃޙͷϓϩηε ճ౴Λཁ໿͠ɺՕ৚ॻ͖Ͱฒ΂Δ #࣭໰ͷΩʔϫʔυ ࠓ೔΍ͬͨ͜ͱɹλεΫɹ׆ಈɹୡ੒ɹ೉͔ͬͨ͜͠ͱɹ՝୊ɹ໰୊ɹίϛϡχέʔγϣϯɹײ৘ɹײँɹށ࿭ ͍ɹݒ೦ɹײͨ͜͡ͱɹվળ఺ɹ஫ҙ఺ ͜ͷϓϩϯϓτͷ࠷ऴग़ྗ݁Ռ͸ҎԼͰ͢ɻ assistant: ৽͍͠ϛʔςΟϯά΁ͷট଴΍ػࡐ؅ཧʹؔ͢Δํ਑ͷܾఆ͸ɺϓϩδΣΫτͷਐ௙ʹͱͬͯେ੾ͳ৘ใͰ͢ Ͷɻ͓ർΕ༷Ͱͨ͠ɻ ͦΕͰ͸ɺࠓ೔ͷճ౴Λཁ໿͠ɺՕ৚ॻ͖Ͱฒ΂·͢ɻ ։ൃதͷήʔϜͷςετϓϨΠΛ࣮ࢪ͠ɺճ෮ΞΠςϜͷճ෮ྔ͕গͳ͍ͱײ͡ΔϑΟʔυόοΫΛఏڙɻ େ͖ͳ໰୊͸ݟ͔ͭΒͣɺ։ൃ͕ॱௐʹਐΜͰ͍Δɻ Ϧʔμʔͱͷ1on1ͰίϛϡχέʔγϣϯΛਤΓɺ৽͍͠ϛʔςΟϯάΛઃఆ͢Δɻ ػࡐ؅ཧʹؔ͢Δํ਑͕ܾఆɻ ࠓ೔΋͓ർΕ༷Ͱͨ͠ɻ·ͨ࣍ճͷৼΓฦΓͰ͓ձ͍͠·͠ΐ͏ɻ ࣗ෼Ͱࢦ͍ࣔͯͯ͠΋ɺ͍͟ϙδςΟϒͳ൓Ԡ͕ฦͬͯ͘Δͱؾ෼͕ྑ͍Ͱ͢ɻݻఆͷ࣭໰Ͱ͸ͳ ͍ҝɺࣗ෼͕औΓ૊Μͩ׆ಈͰͷؾ෇͖ʹ͍ͭͯɺChatGPT ʹΑͬͯ૝ىͤ͞ΒΕΔͷͰ͢ɻࣗ෼ ͕ൃݴͨ͠಺༰ΛՕ৚ॻ͖Ͱཁ໿ͯ͠΋Β͏͜ͱͰɺৼΓฦΓ࣌ʹͦͷ··ར༻Ͱ͖ΔͰ͠ΐ͏ɻ 5.4 ࣮ફʂ ެࣜαΠτͷ͓஌ΒͤνΣοΫ ۩ମతͳ࣮ફྫΛ঺հக͠·͢ɻϞϯελʔετϥΠΫެࣜαΠτͷ͓஌Βͤϖʔδ͔Βɺ৽Πϕ ϯτ৘ใͷϖʔδΛର৅ʹɺΠϕϯτ಺༰ͷνΣοΫΛ ChatGPT ʹ࣮ࢪͯ͠΋Β͍·͢ɻ ˝νΣοΫର৅ͷ͓஌Βͤ 2023.03.30 ৽Πϕϯτʮઓࠃ෩Ӣֆר-רϊ۝-ʯ͕ελʔτʂ ௒ϋϧۄ&ॳճ 24 ˋ CP ର৅ʂ https://www.monster-strike.com/news/20230330_5.html 54
  55. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.4 ࣮ફʂ ެࣜαΠτͷ͓஌ΒͤνΣοΫ

    ҎԼ͸ϓϩϯϓτͰ͢ɻ࣮ࡍʹ͸#͓஌Βͤͷཝʹɺ͓஌Βͤͷ಺༰Λ͢΂ͯίϐʔ&ϖʔετͰ هࡌ͠·͕͢ɺຊߘͰ͸লུ͍ͯ͠·͢ɻ user: #ࢦࣔ ҎԼ͸ϞϯελʔετϥΠΫͷެࣜαΠτʹ͋Δ͓஌Βͤ಺ɺ৽Πϕϯτͷϖʔδͷ಺༰Ͱ͢ɻ Πϕϯτ಺༰શମΛɺϚΠϯυϚοϓͷ༷ʹϩδοΫπϦʔܗࣜͰϦετͰ੔ཧ͍͚ͯͨͩ͠·͔͢ɻͨͩ͠ɺ ա౓ͳཁ໿Λͤͣɺৄࡉͳ৘ใΛ࡟Βͳ͍Α͏ʹ஫ҙ͍ͯͩ͘͠͞ɻ ·ͨɺࠓճͷΠϕϯτͷ಺༰Λ࣌ܥྻͰฒ΂͍ͯͩ͘͞ɻ࣌ܥྻ͸ݟ΍͘͢͢ΔͨΊදܗࣜͰɺ׌ͭ೔࣌ͱΠϕ ϯτ಺༰Λਖ਼֬ʹग़ྗ͍ͯͩ͘͠͞ɻ #͓஌Βͤ Πϕϯτ 2023.03.30 ৽Πϕϯτʮઓࠃ෩Ӣֆר-רϊ۝-ʯ͕ελʔτʂ ௒ϋϧۄ&ॳճ24ˋCPର৅ʂ ৽Πϕϯτ͕4݄2೔ʢ೔ʣΑΓొ৔ʂ ৄࡉ͸ɺຊϖʔδ಺ΛνΣοΫʂ ஫ҙ఺ͱͯ͠ɺChatGPT ʹҰ౓ʹೖྗͰ͖Δจࣈ਺ͷ੍ݶ಺ʹऩ·Γ͖Βͳ͍৔߹͕͋Γ·͢ɻ ͦͷ৔߹͸͓஌ΒͤΛ෼͚ͯೖྗ͠ɺ user: Πϕϯτ಺༰ʹ͍ͭͯ௥Ճ͠·͢ɻ ҎԼͷ಺༰ͱ্هͷग़ྗ݁Ռͱ߹Θͤͯɺ࠶౓ϩδοΫπϦʔͱ࣌ܥྻͷग़ྗΛ͓ئ͍͠·͢ɻ #͓஌Βͤ ʨ͜͜ʹ͓஌ΒͤΛهࡌ͢Δʩ ͱͭͳ͙͜ͱͰɺग़ྗ݁ՌΛ݁߹Ͱ͖·͢ɻͦͯ͠ҎԼ͕࠷ऴग़ྗ݁ՌͰ͢ɻ assistant: ʲϩδοΫπϦʔʳ - ઓࠃ෩Ӣֆר-רϊ۝- - Ψνϟ - ௒ϋϧۄ - 10࿈Ψνϟແྉ - ˒5Ҏ্ΩϟϥΫλʔഉग़֬཰ 24ˋ - ॳճγϯάϧΨνϟ & ॳճ10࿈Ψνϟ - ˒5Ҏ্ΩϟϥΫλʔഉग़֬཰ 24ˋ 55
  56. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.4 ࣮ફʂ ެࣜαΠτͷ͓஌ΒͤνΣοΫ

    - ৽ΩϟϥΫλʔ - ෱ౡਖ਼ଇ (ਫଐੑ) - ͶͶ (໦ଐੑ) - ౡࠨۙ (ޫଐੑ) - ৽Ωϟϥ֬ఆΨνϟˍΦʔϒ - Ձ֨: 4,900ԁ - ಺༰: ৽Ωϟϥ֬ఆΨνϟ1ճˍΦʔϒʷ50 - ߪೖ੍ݶ: ͓ͻͱΓ༷1ճݶΓ - ৽ΠϕϯτΫΤετ - ඈͼग़͠ةݥʂ ѱྶ͕੗·͏Ҫށ (˒5 ڰࠎ) - ऺਓΛ࿭Θ͢ڊนͷո໎࿏ (˒5 ృน) - ౮ΓΛܝ͛͠ྶࠢͷҊ಺ਓ (˒5 ηϯϙΫΧϯϙΫ) - ফඅελϛφݮগˍεϖγϟϧϘʔφε - ফඅελϛφݮগ - ܹڀۃɿ50ˠ40 - ڀۃɿ45ˠ36 - εϖγϟϧϘʔφε - ֫ಘϙΠϯτ5ഒ - υϥʔχΞग़ݱ - ΠϕϯτΫΤετΫϦΞͰग़ݱ - ϚϧνϓϨΠͰۚཛυϩοϓ - ϥοΫϘʔφε༏଴Ωϟϯϖʔϯ - ۚཛ֬ఆഉग़ - ظؒݶఆϛογϣϯ - τΫۄ֫ಘ - τΫۄΨνϟར༻ظݶ ʲ࣌ܥྻʳ - 2023೥4݄2೔ 12:00 - Πϕϯτ։࢝ - Ψνϟ։࢝ʢ৽Ωϟϥ֬ఆΨνϟˍΦʔϒൢച։࢝ʣ - ৽ΠϕϯτΫΤετొ৔ - ফඅελϛφݮগˍεϖγϟϧϘʔφε։࢝ - υϥʔχΞग़ݱ։࢝ - ϥοΫϘʔφε༏଴Ωϟϯϖʔϯ։࢝ - ظؒݶఆϛογϣϯ։࢝ - 2023೥4݄15೔ 11:59 - Πϕϯτऴྃ - Ψνϟऴྃʢ৽Ωϟϥ֬ఆΨνϟˍΦʔϒൢചऴྃʣ - ফඅελϛφݮগˍεϖγϟϧϘʔφεऴྃ - υϥʔχΞग़ݱऴྃ - ϥοΫϘʔφε༏଴Ωϟϯϖʔϯऴྃ - ظؒݶఆϛογϣϯऴྃ - 2023೥4݄18೔ 3:59 - ظؒݶఆϛογϣϯใुडऔظݶ - 2023೥4݄18೔ 23:59 - τΫۄΨνϟར༻ظݶ 56
  57. ୈ 5 ষ ChatGPT Λ QA ͕࢖͍͜ͳ͢ҝͷΞΠσΞ 5.5 ࠓޙͷల๬ ChatGPT

    ͸ཁ໿΍ิ׬Λͯ͘͠ΕΔ͜ͱ͕ར఺Ͱ͕͢ɺࠓճͷΑ͏ͳνΣοΫͰ͸ͳΔ΂͘ؾΛ ར͔ͤͳ͍Α͏ʹͯ͠΋Β͏͜ͱ͕ϙΠϯτͰ͢ɻ࣌ܥྻͰฒ΂ͯ΋Β͏͜ͱͰɺτΫۄ͕֫ಘͰ͖ ΔϛογϣϯΑΓૣ͘τΫۄΨνϟ͕ऴΘͬͯ͠·͍ͬͯͳ͍͔ɺͱ͍͏͜ͱ΋ࣝผ͠΍͍͢Ͱ͢ɻ ͜ͷϓϩϯϓτʹ͞ΒʹνΣοΫ߲໨Λ௥Ճͨ͠Γɺ࣌ܥྻҎ֎Ͱͷํ๏Ͱ৘ใΛฒ΂ͯ΋ΒͬͨΓ ͱɺ޻෉ͷ༨஍͸·ͩ·ͩ͋Γͦ͏Ͱ͢ɻ 5.5 ࠓޙͷల๬ ChatGPT ʹυϝΠϯ஌ࣝΛ༩͍͑ͨ લड़ͷϞϯελʔετϥΠΫͷ͓஌ΒͤͷνΣοΫ΋ɺϞϯελʔετϥΠΫʹؔ͢Δ஌ࣝΛඞཁ ͱ͠ͳ͍ఔ౓ͷνΣοΫ·Ͱ͔͠པΉ͜ͱ͕Ͱ͖·ͤΜɻͨͱ͑͹ɺ͓஌Β͕ͤҎԼͷΑ͏ͳ಺༰ ͩͬͨ৔߹ ChatGPT ͸ؾ෇͚ΔͰ͠ΐ͏͔ʁ • ৽ΨνϟͰഉग़͞ΕΔ˒ 4 ΩϟϥΫλʔͷਐԽૉࡐʹʮ्ਆۄʯ͕͋Δ • Ψνϟͷऴ͕ྃ࣌ؒ 23:59 ʹͳ͍ͬͯΔ • υϥʔχΞͷग़ݱʹؔ͢Δهࡌ͕ͳ͍ ϞϯελʔετϥΠΫΛϓϨΠ͍ͯ͠Δɺ·ͨ͸։ൃʹܞΘ͍ͬͯΔਓؒͰͳ͍ͱؾ෇͘͜ͱ͸Ͱ ͖·ͤΜɻͨͩࣾ͠಺ͷυΩϡϝϯτΛ༩͑ɺϞϯελʔετϥΠΫͷυϝΠϯ஌ࣝΛ࣋ͨͤΔ͜ͱ ͕Ͱ͖Ε͹ɺ ʮ͍ͭ΋ͷ৽Πϕϯτͱҧ͏ͱ͜Ζ͕͋Ε͹ڭ͍͑ͯͩ͘͞ʯͱฉ͚ͩ͘ͰࡁΈ·͢ɻ কདྷۀ຿Ͱར༻Ͱ͖ΔΑ͏ʹͳΔ͜ͱΛظ଴͠ɺࠓ೔΋಺লͷҝʹ ChatGPT ͱձ࿩͠ͳ͕Βɺຊ ߘΛకΊ͘͘Γ͍ͨͱࢥ͍·͢ɻ 57
  58. ஶऀ঺հ ߐാ ୓࠸ (ୈ 1 ষ୲౰, GitHub: @MokkeMeguru, @MeguruMokke) TIPSTAR

    ͱ͍͏ڞ༡ܕεϙʔπϕοςΟϯάαʔϏεͷ։ൃɾӡ༻Λߦ͍ͬͯ·͢ɻιγϟ ήͷ՝͕ۚࢭ·Βͳ͍ͷ͕࠷ۙͷ೰ΈͰ͢ɻEmacs Ͱ Clojure Λॻ͍ͯੜ͖͍ͯ·͢ɻ দݪ ৴஧ (ୈ 2 ষ୲౰) ॴଐ͸ϞϯεταʔόνʔϜͰ Ruby ΍ Go Λॻ͍ͯΔɻϓϩάϥϛϯά͕޷͖Ͱɺීஈ͸ਪ ͠ݴޠͷ Haskell Ͱ༡ΜͩΓɺ৽͍͠ϓϩάϥϛϯάݴޠΛษڧͨ͠Γ͍ͯ͠ΔɻHaskell-jp ΍ Elm-jp Ͱগ͚ͩ͠׆ಈ΋͍ͯ͠Δɻ ٢઒ ༐ଠ࿠ (ୈ 3 ষ୲౰) 2021 ೥৽ଔೖࣾɻιʔγϟϧϕοςΟϯάࣄۀຊ෦ ։ൃࣨ ΫϥΠΞϯτάϧʔϓॴଐɻ WebGL ৮ΔͷͱΠϯυΧϨʔ͕޷͖Ͱ͢ɻ ాಹล ً (ୈ 4 ষ୲౰) ։ൃຊ෦ CTO ࣨॴଐɻιϑτ΢ΣΞΤϯδχΞͱͯ͠ήʔϜ։ൃͱӡӦɺͦΕ͔Βऩӹੑ΍ ήʔϜੑͱ UX ໘౳ʑΫϦΤΠςΟϒʹ΋ܞΘ͖ͬͯ·ͨ͠ɻϓϩάϥϛϯάڭҭʹ͍ͭͯ ͷֶशιϑτͱΧϦΩϡϥϜΛࣗࣾ಺Ͱ࡞Γɺதɾߴߍੜʹ޲͚ͯϓϩάϥϛϯάߨ࠲ͷߨࢣ Ͱ΋׆ಈதɻ΄͔ࣾ಺ R&D ۀ຿΋ࢀՃɻ ౉ᬒ ݩً (ୈ 5 ষ୲౰, Twitter: @motokiwatanabe2) Asym Altered Axis ͱ͍͏։ൃதͷήʔϜͷ QA Λ୲౰͍ͯ͠·͢ɻϝΠϯδϣϒ͸ֶऀͰ ͢ɻChatGPT ͸ӳձ࿩ͷ࿅शͰ࢖͏ͱେมศརͰָ͍͠Ͱ͢ɻ 59
  59. MIXI TECH NOTE #09 2023 ೥ 5 ݄ 20 ೔ɹॳ൛ୈ

    1 ࡮ɹൃߦ ஶɹऀ גࣜձࣾ MIXI ༗ࢤ ൃߦॴ גࣜձࣾ MIXI ҹ࡮ॴ ೔ޫاը ɹ ˜ MIXI