Slide 1

Slide 1 text

 4VO ۀ຿ͰʂRubyΛʂ
 ΩϝΔʂ ෋ࢁ3VCZձٞ ˏ෋ࢁࠃࡍձٞ৔େखொϑΥʔϥϜ Active Record, CSV, and RuboCop ҏ౻ߒҰ&4. *OD

Slide 2

Slide 2 text

!LPJD w 3VCP$PQίϛολʔ w "30SBDMFFOIBODFE BEBQUFSίϛολʔ w Ӭ࿨γεςϜϚωδϝϯτ
 ίϛϡχςΟϚωʔδϟ

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

#VOEMFS 1SZ 34QFD 3VCP$PQ CZFCVH 3VCZ,BJHJ %3&$0.͞Μϒʔεʹͯ

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

IUUQTIFJTFJSCHJUIVCJPLBJHJ

Slide 8

Slide 8 text

IUUQTIFJTFJSCHJUIVCJPLBJHJ

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

8&"3&)*3*/( ͷ஥ؒͨͪ ӡӦ -5 -5 ࢀՃऀ ࢀՃऀ ෋ࢁ3VCZձٞʹू·ͬͨ ߨԋ

Slide 11

Slide 11 text

044ίϛϡχςΟͱͷڞੜΛࢧԉ Support coexistence with OSS community

Slide 12

Slide 12 text

ࠓ೔ͷ࿩

Slide 13

Slide 13 text

ୡਓϓϩάϥϚʔ΁ͷجૅٕज़ ςεςΟϯά %FWFMPQFS5FTUJOH ࣗಈԽ 1SPKFDU"VUPNBUJPO όʔδϣϯ؅ཧ 7FSTJPO$POUSPM

Slide 14

Slide 14 text

ୡਓϓϩάϥϚʔ΁ͷجૅٕज़ ςεςΟϯά %FWFMPQFS5FTUJOH ࣗಈԽ 1SPKFDU"VUPNBUJPO όʔδϣϯ؅ཧ 7FSTJPO$POUSPM

Slide 15

Slide 15 text

͜ͷߨԋͰಘΒΕΔ͔΋͠Εͳ͍͜ͱ w 伱͋Β͹3VCZΛ࢖͏ߟ͑ํͱ͍͏ ͔ࣥ೦Έ͍ͨͳ΋ͷ w ;ͩΜͷΞϓϦέʔγϣϯ։ൃͰ͸ ͋·Γ࢖ͬͯͳ͍͔΋͠Εͳ͍"1* ͷ஌ࣝ w 3VCP$PQͷअಓͳ࢖͍ํ

Slide 16

Slide 16 text

 4VO ۀ຿ͰʂRubyΛʂ
 ΩϝΔʂ ෋ࢁ3VCZձٞ ˏ෋ࢁࠃࡍձٞ৔େखொϑΥʔϥϜ Active Record, CSV, and RuboCop ,PJDIJ*50&4. *OD

Slide 17

Slide 17 text

͝ଘ஌ʜͰ͔͢ʁ ۀ຿ͱ&YDFM͸ ͣͬͱ༑ୡͩΑʜ

Slide 18

Slide 18 text

ػೳ࣮૷Ͱͳ͍ۀ຿͓୊ྫ w σʔλϕʔεεΩʔϚͷҰཡͷ &YDFM͕ཉ͍͠ w ಛఆͷҙຯ߹͍ͷ͋ΔΧϥϜʹ͸
 ϚʔΩϯά͕ཉ͍͠ w TDIFNBSC΍%%-ͷϑΥʔϚοτ Ͱ͸ͳ͘ॴఆͷ&YDFMϑΥʔϚοτ Ͱཉ͍͠ w ࠓिதʹཉ͍͠

Slide 19

Slide 19 text

ਅ࣮ɿ༏Εͨιϑτ΢ΤΞɾ ΤϯδχΞϦϯάʹԊͬͯϓϩ άϥϜΛ։ൃ͢Δͱɺอक͸ݮ Βͣɺ͔͑ͬͯ૿͑Δɻ ιϑτ΢ΣΞΤϯδχΞϦϯά ιϑτ΢ΣΞ։ൃͷਅ࣮ͱͷ΢ι ϩόʔτɾ-ɾάϥε

Slide 20

Slide 20 text

ੵΈॏͳΔσʔλϕʔεεΩʔϚ w ੵΈॏͳΔεΩʔϚఆٛʹΑͬͯɺ
 ςʔϒϧҎ্ ΧϥϜ Ҏ্ w ͜ΕΛॴఆͷϑΥʔϚοτʹͯ͠ &YDFMఏग़

Slide 21

Slide 21 text

৬ਓͷஆ͔ͳख࡞ۀ͸٧Ή w ॻ͘ͷ΋ϨϏϡʔ͢Δͷ΋͠ΜͲ͍ w Ծʹ෼Ͱ࡞੒ͯ͠ɺਓ͕෼͔͚ͯ
 ϨϏϡʔ͢Δͱ෼ͷूதྗ͕ඞཁ w ϚϯύϫʔۀͰർΕͯͦͷ೔͕ऴΘΔ

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

"XBZPG&4. *OD

Slide 24

Slide 24 text

Ͳ͏͢Ε͹ಘҙྖҬʹͳΔ͔ߟ͑Δ w ΫϥΠΞϯτ͕ཉ͍͠΋ͷ͸ɺ7JFX ࠐΈͷ&YDFMγʔτͳͷ͔ʁ&YDFM γʔτʹ૊ΈࠐΉσʔλͳͷ͔ʁ w ϚΫϩ͕૊·Ε֦ͨுࢠYMTNͰ͋Ε ͹ͱ΋͔͘ɺϚΫϩͳ͠Ͱ͋Ε͹߲໨ ॱʹྻڍͨ͠$47Ͱௐ੔ΛࢼΈͯΈΔ w ຊฤʹొ৔͠ͳ͍͕ཁ݅࣍ୈͰ SVCZ9-΍TQSFBETIFFUͱ͍ͬͨ HFN͕ొ৔

Slide 25

Slide 25 text

&YDFM͸$47ͷϥούʔ ͷͱ͖͕͋Δ

Slide 26

Slide 26 text

ୡਓϓϩάϥϚʔ΁ͷجૅٕज़ ςεςΟϯά %FWFMPQFS5FTUJOH ࣗಈԽ 1SPKFDU"VUPNBUJPO όʔδϣϯ؅ཧ 7FSTJPO$POUSPM

Slide 27

Slide 27 text

$47ੜ੒εΫϦϓτΛ࡞Δ w 3FWJFXBCMF ϨϏϡʔՄೳ  w 3VOOBCMF ࣮ߦՄೳ  w 3FQFBUBCMF ࠶࣮ߦՄೳ  w 3FQSPEVDJCMF ࠶ݱՄೳ  w 'SPN(VUTUP'VO

Slide 28

Slide 28 text

࿩ͷத֩

Slide 29

Slide 29 text

֯୩ޠ࿥

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

ίʔυΛॻ͘લʹු͔ΜͩΞΠσΞ w "DUJWF3FDPSEΛ࢖ͬͯ
 σʔλϕʔεεΩʔϚ৘ใΛݩʹ $47Λ࡞੒͢Δ w 3VCP$PQΛ࢖ͬͯ
 ECTDIFNBSCΛݩʹ
 $47Λ࡞੒͢Δ w ͙͢ු͔Μͩͷ͸͜ͷೋ୒

Slide 32

Slide 32 text

݁࿦Λઌʹ w "DUJWF3FDPSEͰ͸ͳ͘ 3VCP$PQΛ࢖࣮ͬͨ૷Λͨ͠ w ECTDIFNBSC͸σʔλϕʔεͱ ಉظͯ͠ϦϙδτϦʹೖΕ͍ͯΔ w σʔλϕʔεʹܨ͛ͣʹ࣮ߦͰ͖Δ w ΫϦςΟΧϧͳ΋ͷͰ͸ͳ͍ͷͰɺ "45ϓϩάϥϛϯάͷՄೳੑΛࢼ͠ ͯΈΑ͏ͱࢥͬͨ

Slide 33

Slide 33 text

͋ͱ͔Βࢥ͑͹TFEίϚϯυ Λ࢖͑͹ྑ͔ͬͨΑ͏ͳؾ͕ ͢ΔͷͰ͕͢ɺͦΕͩͱ࿩͕ ऴΘͬͯ͠·͏ͷͰࠓ೔ͷͱ ͜Ζ͸3VCZͰͻͱͭ ݁࿦Λઌʹ

Slide 34

Slide 34 text

"DUJWF3FDPSEͰͷ࣮૷Ҋ w ίʔυʹ͠ͳ͔ͬͨҊ͕ͩͲ͏͍ͬͨ͜ͱΛߟ ͍͔͑ͯͨ౰࣌ͷࢥߟΛμϯϓ͢Δ w ࠷ॳͷൃ૝Ͱɺաڈʹ࡞ͬͨ(FNͷ࣮૷Λݩ ʹߟ͑ͯΈ࣮ͨ૷Ҋ

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

4DSFBNFSTHFN w ೥͘Β͍લʹ࡞ͬͨΧϥϜܕҠߦͷ HFN w 3BJMTͰͷ0SBDMFͰ%"5&ܕ ͔Β5*.&45".1ܕʹมߋ͞Εͨͱ ͖ʹ࡞ͬͨ w 3BJMTͰJEΧϥϜ͕JOUFHFSܕ͔Β
 CJHJOUܕʹͳͬͨέʔεʹ΋࢖͑Δ͔΋ w 0SBDMF͸/6.#&3ܕͳͷͰෆ࢖༻

Slide 37

Slide 37 text

શ෦Λ஌Δඞཁ͸ͳͯ͘ $47Λߏ੒͢Δςʔϒϧ ໊ͱΧϥϜ໊ΛಘΔ෦෼ ΛݟͯΈΔ ໨త͸ςʔϒϧ໊ͱΧϥϜ໊ΛಘΔ͜ͱ

Slide 38

Slide 38 text

IUUQTHJUIVCDPNLPJDTDSFBNFSTCMPCWMJCTDSFBNFSTDPMVNO@DPMMFDUPSSC $PSF

Slide 39

Slide 39 text

ղઆ

Slide 40

Slide 40 text

IUUQTHJUIVCDPNLPJDTDSFBNFSTCMPCWMJCTDSFBNFSTDPMVNO@DPMMFDUPSSC AR::Base.connection.tables Ͱςʔϒϧ໊ͷҰཡΛऔಘ͢Δ

Slide 41

Slide 41 text

IUUQTHJUIVCDPNLPJDTDSFBNFSTCMPCWMJCTDSFBNFSTDPMVNO@DPMMFDUPSSC ςʔϒϧ໊Λeach_with_object ͢Δ

Slide 42

Slide 42 text

IUUQTHJUIVCDPNLPJDTDSFBNFSTCMPCWMJCTDSFBNFSTDPMVNO@DPMMFDUPSSC "table_names".classifyͰ
 Ϋϥε໊ͷจࣈྻΛऔಘ͢Δ

Slide 43

Slide 43 text

IUUQTHJUIVCDPNLPJDTDSFBNFSTCMPCWMJCTDSFBNFSTDPMVNO@DPMMFDUPSSC Module.const_get(class_name) ͰΫϥε໊ͷఆ਺Λऔಘ͢Δ

Slide 44

Slide 44 text

IUUQTHJUIVCDPNLPJDTDSFBNFSTCMPCWMJCTDSFBNFSTDPMVNO@DPMMFDUPSSC Model.columns.map(&:name)
 ͰΧϥϜ໊ͷҰཡΛऔಘ͢Δ

Slide 45

Slide 45 text

$47Λ૊ΈཱͯΒΕΔ
 ؾ͕͠·͢ΑͶʁ

Slide 46

Slide 46 text

͋ͱ͸खΛಈ͔͚ͩ͢ ͳͷͰɺ͜ͷ͋ͨΓͰ ଞͷҊΛߟ͑ͯΈΔ

Slide 47

Slide 47 text

3VCP$PQͰͷ࣮૷Ҋ w ೔ࠒϝϯςφϯε͍ͯ͠Δ044ͷ஌ݟΛݩʹ ߟ͑ͯΈ࣮ͨ૷Ҋ w 3VCP$PQͷ"45΁ͷΠϕϯτυϦϒϯΛ
 ར༻ͨ͠3VCP$PQͷࣼΊ্ͷ࢖͍ํ
 अಓฤ

Slide 48

Slide 48 text

ਖ਼ಓͱअಓ w ਖ਼ಓͱͳΔ3VCP$PQͷ࢖͍ํ͸"45ΛḷΓ ͭͭɺॴఆͷϧʔϧʹԊͬͨίʔσΟϯά͕͞ Ε͍ͯͳ͚Ε͹ܯࠂΛొ࿥͢Δ"1*Λݺͼग़͢ w ࠓճͷअಓฤͰ͸"45ΛḷΓͭͭॴఆͷϊʔ υͱͦͷ஋Λݕग़ͨ͠ΒɺϑΝΠϧγεςϜ΁ ͷॻ͖ࠐΈͱ͍͏෭࡞༻Λ࢖ͬͨࣼΊ্ͷ׆༻

Slide 49

Slide 49 text

$47Λߏ੒͢Δ ςʔϒϧ໊ͱΧϥϜ໊ ΛಘΑ͏ ॳ৺๨Δ΂͔Βͣ

Slide 50

Slide 50 text

%BUB 4USVDUVSFT "MHPSJUINT

Slide 51

Slide 51 text

%BUB 4USVDUVSFT

Slide 52

Slide 52 text

σʔλߏ଄ΛಘΔ w σʔλߏ଄ʹର͢ΔΞϧΰϦζϜΛ ߟ͑Δॳखͱͯ͠ɺ
 ECTDIFNBSCͷ"45ΛಘΔ w "45ͷσʔλߏ଄Λݟͯɺςʔϒϧ ໊ͱΧϥϜ໊͕Ͳͷϊʔυʹଘࡏ͠ ͍ͯΔ͔֬ೝ͢Δ

Slide 53

Slide 53 text

·ͣECTDIFNBSC Λύʔε͠·͢ % ruby-parse db/schema.rb

Slide 54

Slide 54 text

%&.0

Slide 55

Slide 55 text

ECTDIFNBSC ActiveRecord::Schema.define( version: 2018_11_23_153926 ) do create_table "articles", force: :cascade do |t| t.integer "author_id", null: false t.string "title", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false end end

Slide 56

Slide 56 text

ECTDIFNBSCͷ"45 s(:block, s(:send, s(:const, s(:const, nil, :ActiveRecord), :Schema), :define, s(:hash, s(:pair, s(:sym, :version), s(:int, 20181123153926)))), s(:args), s(:block, s(:send, nil, :create_table, s(:str, "articles"), s(:hash, s(:pair, s(:sym, :force), s(:sym, :cascade)))), s(:args, s(:arg, :t)), s(:begin, s(:send, s(:lvar, :t), :integer, s(:str, "author_id"), s(:hash, s(:pair, s(:sym, :null), s(:false)))), s(:send, s(:lvar, :t), :string, s(:str, "title"), s(:hash, s(:pair, s(:sym, :null), s(:false)))), s(:send, s(:lvar, :t), :datetime, s(:str, "created_at"), s(:hash, s(:pair, s(:sym, :null), s(:false)))), s(:send, s(:lvar, :t), :datetime, s(:str, "updated_at"), s(:hash, s(:pair, s(:sym, :null), s(:false)))))))

Slide 57

Slide 57 text

ղઆ

Slide 58

Slide 58 text

"DUJWF3FDPSE4DIFNBEFpOF WFSTJPO@@@ s(:block, s(:send, s(:const, s(:const, nil, :ActiveRecord), :Schema ), :define, s(:hash, s(:pair, s(:sym, :version), s(:int, 20181123153926)))), s(:args),

Slide 59

Slide 59 text

DSFBUF@UBCMFBSUJDMFT  GPSDFDBTDBEFEPcUc s(:block, s(:send, nil, :create_table, s(:str, "articles"), s(:hash, s(:pair, s(:sym, :force), s(:sym, :cascade)))), s(:args, s(:arg, :t)), CMPDLΛϒϩοΫҾ਺Uͱ Ұॹʹड͚औΔ DSFBUF@UBCMFϝιουΛ ఆٛͨ͠CMPDLϊʔυ )FSF

Slide 60

Slide 60 text

UJOUFHFSBVUIPS@JE OVMM GBMTF s(:begin, s(:send, s(:lvar, :t), :integer, s(:str, "author_id"), s(:hash, s(:pair, s(:sym, :null), s(:false)))), UJOUFHFS UTUSJOH ͱ͍ͬͨΧϥϜఆٛͷTFOE ϊʔυΛଋͶͨCFHJOϊʔυ )FSF

Slide 61

Slide 61 text

UTUSJOHUJUMF OVMMGBMTF s(:send, s(:lvar, :t), :string, s(:str, "title"), s(:hash, s(:pair, s(:sym, :null), s(:false)))), ͜ΕΒϩʔΧϧม਺U΁ͷ ϝιουݺͼग़͠Λද͢ TFOEϊʔυ͕ଓ͘

Slide 62

Slide 62 text

ECTDIFNBSC ࠶ܝ ActiveRecord::Schema.define( version: 2018_11_23_153926 ) do create_table "articles", force: :cascade do |t| t.integer "author_id", null: false t.string "title", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false end end

Slide 63

Slide 63 text

% ruby_ast_visualizer db/schema.rb

Slide 64

Slide 64 text

"MHPSJUINT

Slide 65

Slide 65 text

SEQBSUZDPQΛ࣮૷

Slide 66

Slide 66 text

w 3VCP$PQʹ͸3VCP$PQࣗମͷ ಺෦ϧʔϧΛऔΓక·Δ෦ॺ͕͋Δ JOUFSOBMBGGBJSTʜ಺੓ɺࠃ಺ࣄ৘ ͲͷσΟϨΫτϦʹ഑ஔ͢Δʁ )FSF

Slide 67

Slide 67 text

ͲͷσΟϨΫτϦʹ഑ஔ͢Δʁ w 3VCP$PQࣗମͷ಺෦ϧʔϧʹ͍ͭ ͯऔΓక·Δ෦ॺ໊Λഈआͯ͠Έͨ w 3BJMTΞϓϦͰ΋ಉ༷ʹ3BJMTSPPU ௚ԼͷMJCσΟϨΫτϦʹ഑ஔ͍ͯ͠ Δ w ڞ༗ϥΠϒϥϦͱͯ͠நग़ͯ͠ଞϓϩ δΣΫτͰͷར༻΋ݕ౼Ͱ͖Δ͜ͱ͔ ΒMJC͸ѱ͘ͳ͍બ୒ͩͱࢥ͍ͬͯΔ

Slide 68

Slide 68 text

$PQΫϥεΛܧঝ͢Δ module RuboCop module Cop module InternalAffairs class SchemaToCsv < Cop end end end end HFNSVCPDPQ
 ͳͲͰ3VCP$PQΠϯεί ͞ΕͯΕ͹࢖͑Δ"1*

Slide 69

Slide 69 text

PO@YYYͰର৅ϊʔυΛϋϯυϦϯά module RuboCop module Cop module InternalAffairs class SchemaToCsv < Cop def on_block(node) end end end end end

Slide 70

Slide 70 text

DSFBUF@UBCMFϝιουͷΈର৅ def on_block(node) table = node.children.first # Get table node return if table.method_name == :create_table

Slide 71

Slide 71 text

DSFBUF@UBCMFϝιουͷΈର৅ def on_block(node) table = node.children.first return unless table.method_name == :create_table Ұக

Slide 72

Slide 72 text

DSFBUF@UBCMFϝιουͷΈର৅ def on_block(node) table = node.children.first return unless table.method_name == :create_table Ұக ෆҰக

Slide 73

Slide 73 text

ςʔϒϧ໊Λऔಘ͢Δ def on_block(node) table = node.children.first return unless table.method_name == :create_table table_name = table.first_argument.str_content

Slide 74

Slide 74 text

ΧϥϜϊʔυΛऔಘ͢Δ def on_block(node) table = node.children.first return unless table.method_name == :create_table table_name = table.first_argument.str_content columns = node.children.detect(&:begin_type?)

Slide 75

Slide 75 text

ΧϥϜϊʔυΛऔಘ͢Δ def on_block(node) table = node.children.first return unless table.method_name == :create_table table_name = table.first_argument.str_content columns = node.children.detect(&:begin_type?) UJOUFHFS UTUSJOH ͱ͍ͬͨΧϥϜఆٛͷTFOE ϊʔυΛଋͶͨCFHJOϊʔυ )FSF

Slide 76

Slide 76 text

$47Λ։͘ columns = node.children.detect(&:begin_type?) CSV.open('tmp/schema.csv', 'a') do |csv| end

Slide 77

Slide 77 text

ΧϥϜϊʔυΛFBDI͢Δ columns = node.children.detect(&:begin_type?) CSV.open('tmp/schema.csv', 'a') do |csv| columns.child_nodes.each do |column| end end

Slide 78

Slide 78 text

JOEFYͩͬͨΒεΩοϓ͢Δ columns = node.children.detect(&:begin_type?) CSV.open('tmp/schema.csv', 'a') do |csv| columns.child_nodes.each do |column| next if column.method_name == :index end end

Slide 79

Slide 79 text

ΧϥϜ໊ΛಘΔ columns = node.children.detect(&:begin_type?) CSV.open('tmp/schema.csv', 'a') do |csv| columns.child_nodes.each do |column| next if column.method_name == :index column_name = column.first_argument.str_content end end

Slide 80

Slide 80 text

͋ͱ͸$47ʹ͍͍ײ͡ʹग़ྗ͢Δ columns = node.children.detect(&:begin_type?) CSV.open('tmp/schema.csv', 'a') do |csv| columns.child_nodes.each do |column| next if column.method_name == :index column_name = column.first_argument.str_content write_csv_row(csv, table_name, column_name) end end

Slide 81

Slide 81 text

$47Λ૊ΈཱͯΒΕΔ
 ؾ͕͠·͢ΑͶʁ

Slide 82

Slide 82 text

w SFRVJSFͱPOMZΦϓγϣϯ % bundle exec rubocop \ --cache false --require ./lib/rubocop/cop/ internal_affairs \ --only InternalAffairs/ SchemaToCsv \ db/schema.rb > /dev/null ͓·͚ ࣮ߦͷ౾஌ࣝ

Slide 83

Slide 83 text

w ීஈ͸ࢦఆෆཁͳDBDIFΦϓγϣϯ % bundle exec rubocop \ --cache false --require ./lib/rubocop/cop/ internal_affairs \ --only InternalAffairs/ SchemaToCsv \ db/schema.rb > /dev/null ͓·͚ ࣮ߦͷ౾஌ࣝ --cache falseʹ͠ͳ͍ͱҰ౓ ղੳͨ͠db/schema.rbʹ͍ͭͯ ͸Ωϟογϡ͞Εͯॲཧ͞Εͳ͍ (΍͍ͬͯΔ͜ͱ͕अಓͳূ͔΋)

Slide 84

Slide 84 text

෣୆ཪͱͦͷޙ w JEΧϥϜ͸ग़ྗ͞Ε͍ͯͳ͍ͷͰɺ DSFBUF@UBCMFUBCMF@OBNF  JEGBMTFҎ֎͸ରԠ͓ͯ͘͠ඞཁ ͕͋Δ w ࣗಈԽੜ੒ͨ͠ϑΝΠϧʹɺखಈม ߋΛೖΕΔͱࣗಈԽෆೳʹͳΔͷͰ ͦͷ͋ͨΓ͸ؔ܎ऀͱཁௐ੔

Slide 85

Slide 85 text

ۀ຿Ͱʂ3VCZΛʂΩϝΔʂ w 伱͋Β͹3VCZΛΩϝΔਫ਼ਆ w ࣗ෼ͷ࢓ࣄΛ଀Ήʹ͸ਓੜ͸༨Γʹ ΋୹͍ w ΦϨͬͯ͹͛͢ʔײΛಘΔ w 3VCZΛΩϝΔͱؾ͍͍࣋ͪ w 伱͋Β͹3VCZΛΩϝΔਫ਼ਆ

Slide 86

Slide 86 text

ࣗΒͷٕज़ʹؔ৺Λ࣋ͭ͜ͱ ͋ͳͨͷ࢓ࣄʹ͍ͭͯߟ͑Δ͜ͱʂ ܅͸ֶͿ͜ͱ͕৺͔Β޷͖ͩ ܅͸ιϑτ΢ΣΞͷ͜ͱΛେ੾ʹࢥ͍ͬͯΔ ΞδϟΠϧαϜϥΠ "HJMF4BNVSBJ +POBUIBO3BTNVTTPO ୡਓϓϩάϥϚʔ 5IF1SBHNBUJD1SPHSBNNFS %BWJE5IPNBT "OESFX)VOU ࠜݯͷӔ Stairway to the pragmatic programmer

Slide 87

Slide 87 text

4UBZIVOHSZ  4UBZGPPMJTI ʵ4UFWF+PCT