2022/6/22 @ MoneyForward 勉強会 で実施した A Philosophy of Software Design の話です。
A philosophy ofsoftware design (ޙ)2022/6/22 @ MoneyForward ษڧձ
View Slide
Twitter: @yosuke_furukawaGithub: yosuke-furukawa
A philosophy of softwaredesign• 2018ʹॳ൛͕ϦϦʔε͞Ε• 2020ʹୈೋ൛͕ϦϦʔε͞Εͨ• Ͱ͍͏ͱʮιϑτΣΞઃܭͷֶʯhttps://www.amazon.co.jp/dp/B07N1XLQ7D/
A philosophy of softwaredesign• ஶऀδϣϯɾΦʔελʔϋτ͞Μ• Stanford େֶͷίϯϐϡʔλαΠΤϯεڭत• Sprite OS (OS), Tcl.Tk(ϓϩάϥϛϯάݴޠ),RAMCloud (ΫϥυγεςϜ) ͳͲͳͲɺ੍࡞ଟhttps://web.stanford.edu/~ouster/cgi-bin/home.php
A philosophy of softwaredesign લ·ͱΊ• Tactical Programming ΊΑ͏• Strategic Programming Λਪ• ෳࡶ͞ґଘͱᐆດ͔͞Βى͖Δ• ෳࡶ͞มߋ૿େɺೝෛՙɺΑ͘Βͳ͍͜ͱΛ૿Ճͤ͞Δ• Strategic Programming ͜ΕΒΛߟ͑ͨ͢ΊͷҰॿͱͳΔͷ• ࢿϚΠϯυͰߟ͑ͯϓϩάϥϛϯά͢Δ• ԿͳΒೋճઃܭͯ͠ΈΖɺͦ͏͢Εྑ͍ઃܭ͕Ͱ͖ΔΑ͏ʹͳΔ
ޙ࣮ફΑΓ
ίϝϯτʹ͍ͭͯ
ʮྑ͍ίʔυͳΒίϝϯτ͍Βͳ͍ΑͶʯʮίϝϯτͬͯॻ͘ͷ͔͔࣌ؒΔΑͶʯʮͦΕʹίϝϯτݹ͘ͳΔΑͶʯ
ίϝϯτ͍Βͳ͍ΑͶ
൱
ίϝϯτʹ͍ͭͯ• ʮΑ͘ઃܭ͞Ε͍ͯΔ࣮ʹίϝϯτཁΒͳ͍ʯ• ͜Εʮʮʮ͍᠘ʯʯʯͰ͋Δ• ʮΞΠεΫϦʔϜ࣮݈߁ʹྑ͍ʯͱݴΘΕͯΔͷͱҰॹͩͱ͍͏ओு
ίϝϯτʹ͍ͭͯ• ίϝϯτͰ͔͠දݱͰ͖ͳ͍ͷ͋Δ• ίʔυͷཧղΛॿ͚ΔΑ͏ͳίϝϯτઈରॏཁ• Ͳ͏ͤॻ͘ͱͯ͠શମͷ͏ͪ10%ఔ͔ͩΒॻ͍ͨ΄͏͕ྑ͍• ίϝϯτ͕ݹ͘ͳΔʁؾ͍ͮͨΒ͍͍ͤ
ίϝϯτʹ͍ͭͯ• ίϝϯτͰ͔͠දݱͰ͖ͳ͍ͷ͋Δ• ίʔυͷཧղΛॿ͚ΔΑ͏ͳίϝϯτઈରॏཁ• Ͳ͏ͤॻ͘ͱͯ͠શମͷ͏ͪ10%ఔ͔ͩΒॻ͍ͨ΄͏͕ྑ͍• ίϝϯτ͕ݹ͘ͳΔʁؾ͍ͮͨΒ͍͍ͤετϩϯάελΠϧ
͡Ό͋Ͳ͏͍͏ίϝϯτΛॻ͚͍͍ͷ͔
͡Ό͋Ͳ͏͍͏ίϝϯτΛॻ͘ͷ͕ྑ͍ͷ͔• ίʔυنͱಉ͘͡ίϝϯτʹنΛ࡞Ζ͏• Don't Repeat the Code ͷݪଇΛकΖ͏• ΠϯλϑΣʔεͷίϝϯτͱ࣮ͷίϝϯτ͚Α͏
ίϝϯτن• ίϝϯτʹҰ؏ੑ͕ͳ͍ͱ͍͚ͳ͍• ͬͪ͜ͷϞδϡʔϧʹίϝϯτ͕͋Δ͚Ͳɺͬͪ͜ʹͳ͍Έ͍ͨͳҰ؏ੑ͕อͨΕ͍ͯͳ͍ͱζϧζϧָͳํʹྲྀΕͯॻ͔Εͳ͘ͳΔ• ಛʹݴޠʹυΩϡϝϯςʔγϣϯͷπʔϧ͕͍͍ͯΔͷ͋Δɻͦͷ߹πʔϧͷنʹඞͣै͏ʢྫ: Javadoc, godoc, Doxygenʣɻ
Don't Repeat the Code ͷݪଇ• ίʔυʹॻ͍ͯ͋Δ͜ͱΛͨͩͦͷ··ίϝϯτʹॻ͘͜ͱΛ͠ͳ͍// Add a horizontal scroll barhScrollBar = new JScrollBar(JScrollBar.HORIZONTAL);add(hScrollBar, BorderLayout.SOUTH);// Add a vertical scroll barvScrollBar = new JScrollBar(JScrollBar.VERTICAL);add(vScrollBar, BorderLayout.EAST);// Initialize the caret-position related valuescaretX = 0; caretY = 0; caretMemX = null;
Don't Repeat the Code ͷݪଇ• ίʔυʹॻ͍ͯ͋Δ͜ͱΛͨͩͦͷ··ίϝϯτʹॻ͘͜ͱΛ͠ͳ͍// Add a horizontal scroll barhScrollBar = new JScrollBar(JScrollBar.HORIZONTAL);add(hScrollBar, BorderLayout.SOUTH);// Add a vertical scroll barvScrollBar = new JScrollBar(JScrollBar.VERTICAL);add(vScrollBar, BorderLayout.EAST);// Initialize the caret-position related valuescaretX = 0; caretY = 0; caretMemX = null;͜͏͍͏ίʔυΛݟͨΒٯʹո͠Ή
ΠϯλϑΣʔεͷίϝϯτ• ΘΕํͷ࣮ྫ• ͏্Ͱͷҙࣄ߲• நԽ͞ΕͯΔσβΠϯͷৄࡉΛॻ͘ʢLinkedListͰ࣮͞Ε͍ͯΔʣ
ΠϯλϑΣʔεͷίϝϯτ• ͍ํ͏্Ͱͷҙࣄ߲͕ॻ͍ͯ͋Δ/*HTTP ͷαʔόͱΫϥΠΞϯτͷ࣮Λఏڙ͢ΔΠϯλϑΣʔεGet, Head, Post ͳͲͷ HTTP ϦΫΤετΛૹΔ߹ɺԼهͷํ๏ͰૹΔresp, err := http.Get("http://example.com/")...listenAndServeؔΛ࣮ߦͨ͠ࡍʹطʹಉ͡ϙʔτΛlisten͍ͯͨ͠߹FatalΤϥʔͱͳΓɺىಈʹࣦഊ͢Δɻ*/
࣮ͷίϝϯτ• Կނ͜͏͔ͨ͠ʢWhyʣ• ԿΛ͍ͯ͠Δ͔ͷతઆ໌ʢWhatʣ• (Don't Repeat the Code ʹͳΒͳ͍Α͏ʹ)
࣮ͷίϝϯτ• ΤϥʔճආͷͨΊͷϫʔΫΞϥϯυ (Why)try {} catch(e) {// ຊདྷ͜͜ͰΩϟον͢Δ͖Ͱͳ͍͕ϥΠϒϥϦ͕ xxx Error Λ// throw ͢ΔͨΊɺҰ࣌తʹΩϟον͠ɺਖ਼ৗॲཧʹ͢ɻ// ຊମͷ Issue 12345 ͕औΓࠐ·ΕͨΒຊॲཧෆཁ}
࣮ͷίϝϯτ• ҰൃͰԿͬͯΔ͔Θ͔Βͳ͍࣌ͷղઆ// ೋ࣍ݩྻͷ֤ྻ͝ͱͷฏۉΛऔΔlet mut averages = vec![];for col in 0..len {let mut sum = 0;for row in 0..nums[col].len() {sum += nums[col][row];}averages.push(sum / nums[col].len());}
ΈΜͳ͕͏Α͏ͳϞδϡʔϧͳΒURLΛίϝϯτʹॻ͘ͷ͋Γ/*xxx ϩάͷਖ਼نԽΛߦ͏ؔlog.format("%s", foobarbaz);σβΠϯͷৄࡉԼهͷURLΛࢀর͢Δ͜ͱhttps://example.com/foobarbaz*/
ίϝϯτ͍ͭॻ͔͘૪• Ͱ͖ΕΠϯλϑΣʔεͷίϝϯτ࣮લʹͪΌΜͱॻ͘ͷ͕·͍͠ͱͷ͜ͱ• நԽ͢ΔͨΊͷσβΠϯϓϩηεͷҰ෦ͩͱଊ͑ͯ࠷ॳʹΔ͖• ࣮ͨ͠ΒมΘΔ͔ΒΓͨ͘ͳ͍ͱ͍͏ਓσβΠϯϓϩηε͕ෆेͳͷͩͱΓࣺͯΔ
ίϝϯτ͍ͭॻ͔͘૪• ޙʹ׳ΕͳΔ΄Ͳਏ͘ͳΔΜ͔ͩΒࠓॻ͜͏• චऀίϝϯτΛॻ͍ͯΔͱ͖͕Ұ൪ָ͍࣌ͩ͠ͱࢥ͍ͬͯΔͱͷ͜ͱ• తͰ໌շͳίϝϯτ͕ॻ͚ͨ ≒ ઃܭ͕͏·͘ݴͬͯΔূڌ• ٯʹ্ख͘ίϝϯτ͕ॻ͚ͳ͍ͱ͍͏͜ͱઃܭ͕͏·͘ߦͬͯͳ͍ͷ͔͠Εͳ͍• ͜͏͍͏ࢥ͍Λ࣋ͪͳ͕ΒίϝϯτΛָ͠ΜͰॻ͖·͠ΐ͏
໊લ͚ʹ͍ͭͯ
໊લ͚େࣄ• චऀ͕ੲͱ͋Δʹ block ͱ͍͏มΛ͚ͨ• ͦͷϒϩοΫϋʔυσΟεΫͷཧϒϩοΫͷҙຯͰ͚͍ͯͨɻ• ͔͠͠ɺଞͷॴͰཧϒϩοΫʹಉ͡มblock ͕͍͍ͭͯͨɻ• ͜ΕʹΑΓɺΑ͘Θ͔Βͳ͍όά͕ੜ·Ε͍ͯͨ
ؓٳ• ཧϒϩοΫͱཧϒϩοΫ• ཧϒϩοΫσΟεΫίϯτϩʔϥ͕ಡΈॻ͖͢Δ࣌ͷϒϩοΫͷ͜ͱ• ཧϒϩοΫͦΕΒΛ·ͱΊͨܗͰΧʔωϧ͕ѻ͏ϑΝΠϧಡΈॻ͖ͷࡍͷϒϩοΫ
໊લ͚େࣄ• ྑ໊͍લਖ਼֬͞ͱҰ؏ੑΛ࣋ͭ• Ұ؏ੑ• ಉ͡ҙຯͷͷʹಉ໊͡લ͕͍͍ͭͯΔ͜ͱ• ҧ͏ҙຯͷͷʹಉ໊͡લ͕͍͍ͭͯͳ͍͜ͱʢblockͷྫ͜ͷ݅ҧʣ
໊લ͚େࣄ• ਖ਼֬͞• ҙຯ͕ेʹڱ͍ํ͕ྑ͍• ᐆດͰ͍ҙຯ͕औΕͯ͠·͏ͱਖ਼͕ࣦ֬͞ΘΕΔ• blockͷྫҙຯ͕ᐆດͩͬͨ
໊લ͚େࣄ• ͡Ό͋ͷ͍͘͢͝ͱΑ͍ͷ͔ͱ͍͏ͱͦ͏Ͱͳ͍• ಡΉଆ͕ཧղͰ͖Δ͔ʁΛ࠷ॳʹߟ͑Δ• ॻ͘ଆͷ߹Ͱ͍͖ͳΓΘʔͬͱॻ͘ͷμϝɺಡΉଆͷઢͰߟ͑Δඞཁ͕͋Δ
ͪͳΈʹҰจࣈมʹ͍ͭͯ• iͱ͔jͱ͔ϧʔϓͷมͳΒڞ௨ೝࣝͳͷͰ͍͍ͬͯ• ͨͩ Go จԽతʹ͍มΛΉ͕ɺಡΉଆ͕ͦΕͰेʹཧղͰ͖Δ͔ʁΛߟ͑Δ͖Ͱ͋Δͱචऀओு͢Δ• ॻ͘ଆͷ߹Ͱ1จࣈͷมʹ͢ΔͷͰͳ͘ɺಡΉଆ͜ΕͰཧղͰ͖Δͱࢥ͏ͳΒՄೳͩͱ͍͏ཧ
طଘίʔυΛमਖ਼͢Δ࣌
طଘίʔυͷमਖ਼• ࠷ॳ͔Βਖ਼͍͠σβΠϯͷͷଘࡏ͠ͳ͍• ண࣮ʹमਖ਼͍ͯ͘͠ඞཁ͕͋Δ• adhoc ʹ tactical ͳίʔυΛॻ͘ͷͰͳ͘ɺ strategic ʹઃܭΛͪΌΜͱ͠ͳ͕ΒίʔυΛॻ͖ɺͦΕΛܧଓ͢Δ• ίʔυίϝϯτͳΔͪ͘ΌΜͱॻ͘• ίϝϯτநԽͨ͠ͷ༻ҙ͠ɺσβΠϯυΩϡϝϯτͳͲʹө͓͖ͯ͠ɺͲ͔͜ΒͰݟΕΔΑ͏ʹ͓ͯ͘͠
ίʔυΛ໌շʹͤΑ
ίʔυΛ໌շʹͤΑ• ໌շ͞ΛอͭͨΊͷςΫχοΫ• ඞཁͳใ͚ͩʹߜͬͨίʔυΛॻ͘• ίʔυنΛकΔ• ॏཁͳใΛϋΠϥΠτ͢Δ
ίʔυΛ໌շʹͤΑ• ඞཁͳใ͚ͩʹߜͬͨίʔυΛॻ͘• ୯Ұͷݪଇ• ͰෳࡶͳॲཧΛ͠ͳ͍͜ͱʢKeep ItSimpleʣ• நԽϨΞέʔεͷߟྀΛߜΔ
ίʔυΛ໌շʹͤΑ• ίʔυنΛकΔ• ۭനվߦΛͪΌΜͱकΔ• ίϝϯτ͕ඞཁͳՕॴʹͪΌΜͱೖΕΔ• ݱͳΒ linter / formatter ͕උΘͬͯΔݴޠ͋ΔͷͰɺͦΕͰ͋Γ
ίʔυΛ໌շʹͤΑ• ॏཁͳใʹϋΠϥΠτ͢Δ• ίϝϯτΛॻ͘• Ϡό͍ͱ͖Ϡό͍͜ͱ͕ҰൃͰΘ͔ΔΑ͏ͳ໋໊ʹ͢Δ• dangelouslySetInnerHTML• SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
ιϑτΣΞτϨϯυͱͷൺֱ
͜Ε·ͰͷτϨϯυͱ͜ͷຊͱͷཱͪҐஔൺֱ• ޙͷҰ൪໘ന͍ճ• ͜Ε·Ͱग़͖ͯͨιϑτΣΞͷτϨϯυʹରͯࣗ͠ͷཱΛ໌֬ʹ͢ΔՕॴ• ͳΜͱͳ͘ޙॻ͖ίϝϯτײ͕͋ͬͯҰ൪͖ͳՕॴ• ٯʹஶऀͷओ؍తͳ෦ͳͷͰɺʹฉ͍͓ͯ͘ͷ͕ྑͦ͞͏
ΦϒδΣΫτࢦϓϩάϥϛϯά
ΦϒδΣΫτࢦϓϩάϥϛϯά• ෳࡶ͞ղফͷͨΊʹੜ·Εͨͱ͞Ε͍ͯΔ͕ຊ࣭తʹෳࡶ͞ͷղফอূͯ͘͠Εͳ͍ͱࠅධ͍ͯ͠Δ• ෳࡶͳ࣮͕Ӆṭ͞ΕΔͱ͍͏ΑΓෳࡶͳ··ʹͳΔ• ಛʹܧঝෳࡶ͞ΛӅṭͰ͖ͣɺ෦ͷঢ়ଶ͕ݟ͑ΔΑ͏ʹͳΔݴޠ͕ଟ͍ɺ݁Ռ࣮͕ΑΓෳࡶʹͳΔ
ΞδϟΠϧ։ൃ
ΞδϟΠϧ։ൃ• εέδϡʔϧΛࡉ͔ͬͯ͘ΠςϨʔγϣϯΛճͯ͠։ൃ͢Δ෦ධՁ͍ͯ͠Δ• ҰํͰػೳʹ͞Ε͍͗ͯ͢Δ• நԽͨ͠ઃܭΛ͢Δ࣌ؒΛอূͯ͘͠ΕΔΘ͚Ͱͳ͍• Ή͠Ζ࣮͢Δํʹ༠ಋ͞Ε͕ͪͳͷͰ݁Ռ tacticalprogramming ʹͳΓ͕ͪ
Ϣχοτςετ
Ϣχοτςετ• ࣗͷΠϯλϑΣʔεΛςετͨ͠ΓɺϦϑΝΫλϦϯάΛॿ͚ͯ͘ΕΔͱ͍͏ҙຯͰߴ͘ධՁ͍ͯ͠Δ• ͔͠͠ɺςετۦಈ։ൃɺಛʹςετϑΝʔετͳߟ͑ํʹؔͯ͠࠷ॳ͔Βࡉ෦Λදݱ͠Α͏ͱ͍͗ͯͯ͢͠ɺߴϨϕϧͳઃܭͷݟ͠ʹͳΓʹ͍͘ͱ͍͏Λ൷͍ͯ͠Δ
σβΠϯύλʔϯ
σβΠϯύλʔϯ• σβΠϯΛύλʔϯԽͯ͠ݴޠԽͨ͜͠ͱߴ͘ධՁ͍ͯ͠Δ• ҰํͰɺશͯΛύλʔϯʹΊΑ͏ͱͯ͠͠·͏ਓ͕ͨͪଟ͘ͳΔࣄΛݒ೦͍ͯ͠Δ• ύλʔϯແཧʹ͏ͷͰͳ͍ɻ• ϋϚΔͷ͕͋ͬͨΒ͑Α͍͠ɺϋϚΒͳ͍ͳΒແཧʹΘͳͯ͘Α͍ɻ
ιϑτΣΞτϨϯυ• ৽͍͠τϨϯυ͕͋ͬͨΒɺ·ͣҎԼͷࣄΛߟ͑ͯ΄͍͠• ιϑτΣΞ։ൃͷෳࡶ͞ΛͲ͏ͬͯղফ͠Α͏ͱ͍ͯ͠Δͷ͔• Ͳ͕͜લͷτϨϯυͱൺֱͯ͠ྑ͘ͳΔͷ͔• ࣗͷߟ͑ํΛ͜Ε·ͰͷτϨϯυͱൺ্ֱͨ͠Ͱਂ͘ߟ͑Δ͜ͱ
࠷ޙʹ
චऀ͕͍͑ͨ͜ͱ• σβΠϯͷೳྗͱʮԿ͕ॏཁͰԿ͕ॏཁ͡Όͳ͍͔ΛऔࣺબͰ͖ΔೳྗʯͰ͋Δ• ؒҧ͑Δ͜ͱ୭Ͱ͋ΔɺͰͦΕΛͪΌΜͱݟ͢͜ͱɺ͘ਂ͘ߟ͑ͯࣗͰऔࣺબ͢Δ͜ͱ• ͦΕ͕ͦ͜ྑ͍ιϑτΣΞΤϯδχΞʹͳΔϓϩηεͰ͋Γɺྑ͍σβΠϯೳྗΛʹ͚ͭΔํ๏Ͱ͋Δ
·ͱΊ• ίϝϯτΛͪΌΜͱॻ͜͏• ໋໊Ұ؏ੑ͕͋ͬͯਖ਼֬ʹ• ίʔυنʹैͬͯ໌շͳίʔυΛॻ͘• ιϑτΣΞτϨϯυΛࣗͷߟ͑ͱൺֱ͠Α͏• ࣗͰߟ͑ͯࣗͰৼΓฦΔɺͦͷ্Ͱऔࣺબ͕Ͱ͖ΔΑ͏ʹͳΖ͏