- ãã£ãã
- FunctionalOptionPattern
- MethodChaining
- Error ãã£ã¼ã«ãã®åé¡ç¹ã¯æ¬å½ã«åé¡ãªã®ã?
- ã©ã¡ãã使ãã¹ããªã®ã?
- ã¾ã¨ã
ãã£ãã
ãã®è¨äºãæ¸ããã£ããã¯ä»¥ä¸ã®ããã°ã§ãMethodChaining ã®ä»£ããã« FunctionalOptionPattern ãå©ç¨ããã¨ããè¨äºã
https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/
ãã®è¨äºã¯ @ono_matope ããã®ãã¤ã¼ãã§ç¥ã£ãã
Goã®ã¡ã½ãããã§ã¼ã³ã¯ã¨ã©ã¼ããã¾ãæ±ããªãã¨ãã観ç¹ããã®ORMã¸ã®Functional Option Patternã®é©ç¨ãã»ã«ãããã³ãå ¥ã£ã¦ããã©ããã®ä¾ã§ã¯First()ãã¨ã©ã¼è¿ãã°ãã話ã ã¨æããç¾ç観ç¹ããã¯ä¼¼ã⦠https://t.co/RiMoH1XEkW
— å°éããã (@ono_matope) 2018å¹´2æ25æ¥
ãã®ãã¤ã¼ãã«ãªãã¤ã¼ãããçµæã
@hnakamur2 ãããå ããã3人ã§ã¡ãã£ã¨ããè°è«ãããã
è°è«ã®å 容ã«ã¤ãã¦ã¯ä»¥ä¸ã追ã£ã¦ããããã°ã¨æãã
https://twitter.com/ono_matope/status/967788305830985728
ï¼æ¬ä½å士ã§é¢èããªãæ¹ã ã¨ãããã£ãè°è«ãã§ãããããããã¤ãã¿ã¼ã£ã¦ä¾¿å©ã§ããã
ãã£ãããªã®ã§ã
ä¸è¨ã®ãã¤ãã¿ã¼ä¸ã§ã®ããã¨ããæ´çãã¦ã
èªåãªãã®çµè«ãæ¸ãã¦ã¿ããã¨æãã
FunctionalOptionPattern
ããã«ã¤ãã¦ã¯ç¹ã«ä½ãè¨åãããã¨ã¯ãªããFunctionalOptionPattern ã«ã¤ãã¦ã¯ä»¥ä¸ãèªãã¨ããã
https://qiita.com/weloan/items/56f1c7792088b5ede136
ãã®è¨äºã«ããã¨åå
¸ã¯ä»¥ä¸ãªã®ã§ã2014å¹´ãããã£ããã¿ã¼ã³ã¿ããã
https://commandcenter.blogspot.jp/2014/01/self-referential-functions-and-design.html
MethodChaining
ãããããæ¬é¡ã以ä¸ã®è¨äºã¯ golang 㧠MethodChaining ã®ä»£ããã« FunctionalOptionPattern ãå©ç¨ããã¨ããå
容ã«ãªã£ã¦ããã
https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/
ããããã¯èªåã®èãã交ãã¦ä¸è¨ã®è¨äºã説æãã¦ããã®ã§ã
è¨äºä¸ã«è¼ã£ã¦ããªãå
容ãæ¸ãããã
è¼ã£ã¦ããå
容ãæ¸ããªãã£ããããããããã¾ããã
å
è¨äºãèªãã§ããèªã¿é²ããæ¹ãããã¨æãã¾ãã
MethodChaining ã®åé¡ç¹
ãªã MethodChaining ã®ä»£ããã« FunctionalOptionPattern ãå©ç¨ãããã¨è¨ãã¨ãgolang ã®æ»ãå¤ã§ã¨ã©ã¼ãè¿ãã¨ããè¨èªä»æ§ã¨MethodChainingã®ç¸æ§ãæªãããã
java ãªã©ã®ä¾å¤ãåå¨ããè¨èªã§ããã°ã以ä¸ã®ããã«ã¡ã½ããããã§ã¤ã³ãããã¨ãã§ããã
User user = new User.Builder() .name("Michael Scott") .email("[email protected]") .role("manager") .nickname("Best Boss") .build();
ããããgolang ã®å ´åã¯æ»ãå¤ã§ã¨ã©ã¼ãè¿ãã®ã§ã¡ã½ããããã§ã¤ã³ã§ããªãã
以ä¸ã®ããã«æ¯åã¨ã©ã¼ãã§ãã¯ãããå¿
è¦ãããã
var db *gorm.DB var err error db, err = db.Where("id = ?", 123) if err != nil { ... } db, err = db.Where("email = ?", "[email protected]") if err != nil { ... }
ãã®ããã« golang ã®ã¨ã©ã¼ãã³ããªã³ã°ã®è¨èªä»æ§ã¨ MethodChaining ã®ç¸æ§ãæªãã¨ããç¹ãåé¡ã¨ãªã£ã¦ããã
Error ãã£ã¼ã«ãã«ãã解決æ¹æ³
golang ã®è¨èªä»æ§ã¨ MethodChaining ã®ç¸æ§ãæªãã¨ããç¹ã¯ãããã®ã®ãstruct ã« Error ãã£ã¼ã«ããæããããã¨ã§ã
ããã£ã½ãå®è£ ãããã¨ãã§ããã
è¨äºä¸ã§ä¾ã¨ãã¦æ±ããã¦ããã®ã¯ GORM ã
GORM 㯠gorm.DB ã¨ãã struct ã« Error ãã£ã¼ã«ããæããã
MethodChainingã«ããã¨ã©ã¼ãæ ¼ç´ãã¦ãããããã
https://github.com/jinzhu/gorm/blob/48a20a6e9f3f4d26095df82c3337efec6db0a6fc/main.go#L15
MethodChainingãå®äºããã¿ã¤ãã³ã°ã§ã
DB.Error ã nil ãã©ããããã§ãã¯ãããã¨ã§ã
ã¨ã©ã¼ãè£è¶³ã§ããããã«ãªã£ã¦ããã
http://gorm.io/docs/error_handling.html#Error-Handling
DB.Error ã®ãããã§åã¡ã½ãã㧠error ãè¿ãå¿
è¦ããªãã
ã¡ã½ããããã§ã¤ã³ãããã¨ãã§ããã
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil { // error handling... }
Error ãã£ã¼ã«ãã«ãã解決æ¹æ³ã®åé¡
ããããError ãã£ã¼ã«ãã«ãã解決æ¹æ³ã«ãåé¡ãããã1. åã¡ã½ããã§ã¨ã©ã¼ãçºçããªããããªå°è±¡ãåãã
DB.Error ãã¨ã©ã¼ãæ ¼ç´ããã®ã§ããã§ã¤ã³å¯¾è±¡ã®åã¡ã½ãã㯠error ãè¿ããªãã
ãã®ããããã®ã¡ã½ããã«å¯¾ãã¦ã¨ã©ã¼ã«ãªããªãæä½ã®ãããªå°è±¡ãåããã
ããããå®éã¯ã¨ã©ã¼ãçºçããå¯è½æ§ãããã
ããããã«è¨ãã¨ã
ã¨ã©ã¼ãçºçããã¨ããå±æ©æãèãã¦ãã¾ãã
2. ã¨ã©ã¼ãã§ãã¯ãå¿ããã ãã®1
golang ã®ã¨ã©ã¼ãã³ããªã³ã°ã¯æ»ãå¤ã§ã¨ã©ã¼ãè£è¶³ããã®ã§ãMethodChainingå¾ã« DB.Error ã®ã¨ã©ã¼ãã§ãã¯ãããã®ãå¿ãããã
3. ã¨ã©ã¼ãã§ãã¯ãå¿ããã ãã®2
gorm 㯠Open() ããé㯠error ãè¿ããfunc Open(dialect string, args ...interface{}) (db *DB, err error) { //çç¥ }
https://github.com/jinzhu/gorm/blob/48a20a6e9f3f4d26095df82c3337efec6db0a6fc/main.go#L44
ããããDB.Error ã®ã¨ã©ã¼ãã§ãã¯ãå¿
è¦ãªã®ã§ã
ãDB.Error ã«ã¯ãgorm.Open() æã®ã¨ã©ã¼ãæ ¼ç´ãããã¯ããã¨ããæãè¾¼ã¿ãããã¨ã
gorm.Open() æã«çºçããã¨ã©ã¼ããã³ããªã³ã°ããã
çµæçã«ä¸å
·åã«ã¤ãªããã
éã« DB.Error ã®ãã§ãã¯ãä¸è¦ãªå ´åã§ããã§ãã¯ãããããªã³ã¼ããæ¸ãã¦ãã¾ããã¨ãããã
ã¡ãªã¿ã«ã
gorm.Open() ã§çºçããã¨ã©ã¼ã DB.Error ã«æ ¼ç´ããããã©ããã¯èª¿ã¹ã¦ãã¾ããã
ããã¾ã§ãDB.Error ã«ã¯ gorm.Open() ã®ã¨ã©ã¼ãæ ¼ç´ãããªããã¨ä»®å®ãã話ã§ãã
FunctionalOptionPattern ã«ãã解決æ¹æ³
FunctionalOptionPattern ãå©ç¨ããã¨ã以ä¸ã®ãããªæ¸ãæ¹ã«ãªããMethodChaining ã®åé¡ç¹ã¯è§£æ¶ããã¦ããã¯ãã
var user User err = db.First(&user, Where("email = ?", "[email protected]"), Where("id = ?", 2), ) if err != nil { panic(err) } fmt.Println(user)
MethodChaining ã¨ãã¦ã®è§£æ±ºæ¹æ³
è¨äºã®å 容ã¨ãã¦ã¯ãFunctionalOptionPattern ã使ããã£ã¦ããå 容ãªãã ãã©ãè¨äºä¸ã«ã¯ä»¥ä¸ã®è¨è¼ãããã
Note: One way to fix this would be to update methods like First and Find in GORM to return both the gorm.DB and an error when called, but Iâm not 100% sure how this would affect the rest of the library. Instead we are going to explore an alternative approach that I prefer anyway
First(), Find() ã¨ããã¡ã½ããã gorm.DB 㨠error ãè¿ãããã«ããä¿®æ£æ¹æ³ããã ã¨ã®ãã¨ã
ããã¯ããããã以ä¸ã®ã¤ã¡ã¼ã¸ã ã¨æãã
db, _ := db.Open() db, err := db.Where().Where().Find() if err != nil { panic() }
å®è£
ã¯ä»¥ä¸ã
MethodChainingã®æå¾ã« Find() ãå®è¡ãããã®ã§ã
Find() ã ãã error ãè¿ãã°ããã
package db func Open() (*DB, error) { return DB{}, nil } type DB struct { err error } func (d *DB) Where() *DB { if xxx { d.err = errors.New("error!") return d } return d } func (d *DB) Find() (*DB, error) { return d, d.Err }
ã¯ã¨ãªã®æ§ç¯ã§ããã°ã
Build() 㧠error ãè¿ãããã«ãã¦ã
Find() ã¯ãã§ã¤ã³ã§ããããã«ãã¦ãããã¨æãã
func (d *DB) Find() *DB { return d } func (d *DB) Build() (*DB, error) { return d, d.err }
ã¾ããã©ã¡ãã«ããããã§ã¤ã³ã®æå¾ã§ error ãè¿ãããã«ãã¦ãããã°ããã¯ãã
ããã«ãã£ã¦ãMethodChainingãå©ç¨ããã±ã¼ã¹ã§ãã
Error ãã£ã¼ã«ãã®åé¡ç¹ã¯è§£æ±ºãããã¨ãã§ããã
Error ãã£ã¼ã«ãã®åé¡ç¹ã¯æ¬å½ã«åé¡ãªã®ã?
å è¨äºã«ãã Error ãã£ã¼ã«ãã®åé¡ç¹ã¯ãããããåé¡ãªã®ã ããã?以ä¸ã§ã¯ãstruct ã« Error ãã£ã¼ã«ããæããããã¨ã§ã
ã¨ã©ã¼ãã§ãã¯ã®ç¹°ãè¿ããé¿ãããã¯ããã¯ãç´¹ä»ããã¦ããã
https://blog.golang.org/errors-are-values
ä¸è¨ã®è¨äºã§ãç´¹ä»ããã¦ããããã«ã
æ¨æºããã±ã¼ã¸ã® scan 㯠Error ãã£ã¼ã«ããæã£ã¦ããã
https://github.com/golang/go/blob/f7ac70a56604033e2b1abc921d3f0f6afc85a7b3/src/bufio/scan.go#L38
ã¨ã©ã¼ããã§ãã¯ããããã®ã¡ã½ãããæä¾ãã¦ããã
https://github.com/golang/go/blob/f7ac70a56604033e2b1abc921d3f0f6afc85a7b3/src/bufio/scan.go#L90
ã¨ã©ã¼ãæ»ãå¤ã§è¿ãããããåããããããã©ãã? ã¨ãã観ç¹ã ã¨ã
å£ããããããªããã
å°ãªãã¨ã Error ãã£ã¼ã«ããæãããå®è£
ãã¢ã³ããã¿ã¼ã³ã¨ããããã§ã¯ãªãã¯ãã
ãªã®ã§ãããããåé¡ã§ã¯ãªãã®ãããããªãã
å
è¨äºã®çè
ã ããè¯ãæ¹æ³ã¯ FunctionalOptionPattern ã ã ã¨è¨ã£ã¦ããã ãã§ã
MethodChainingãå¦å®ãã¦ããããã§ã¯ãªãã¨æãã
ï¼ãããããã©ã»ã»ã»
ã©ã¡ãã使ãã¹ããªã®ã?
æ£ç´ã好ã¿ã®åé¡ãªã®ããªã¼ã¨æã£ã¦ãããFunctionalOptionPattern ã¯ãªãã·ã§ã³ã®å®è£
ã« interface ãå©ç¨ãã¦ããã®ã§ã
ã©ã¤ãã©ãªãå©ç¨ããå´ãç¬èªã®å®è£
ãé©ç¨ããããã¨ãã§ããã
ãªã®ã§ãä¸ç¹å®å¤æ°ãå©ç¨ããã©ã¤ãã©ãªã§ããã°ã FunctionalOptionPattern ã®æ¹ãé©ãã¦ããæ°ãããã
ããããMethodChaining ãã¡ã½ããã®æåã interface ã«ãã£ã¦å·®ãæ¿ãããããªå®è£
ã«ãããã¨ã§ã
åããããªãã¨ãå¯è½ãªã®ã§ã
å®è£
ã®å·®ãæ¿ãã¯æ±ºå®æã«ã¯ãªããªããªã¼ã¨ããã®ãæ£ç´ãªã¨ããã
FunctionalOptionPattern ã®æ¹ãå®è£
ãè¥å¹²é¢åãªæ°ããããã©ã
MethodChaining ã« interface ãå°å
¥ããå ´åã
ã©ã¡ãã大ãã¦å¤ãããªãã¨æãã
å人çã«ã¯ã
MethodChaining = ãªãã¸ã§ã¯ããçµã¿ç«ã¦ãããã®å®è£
ãã¿ã¼ã³
FunctionalOptionPattern = ãªãã·ã§ã³ãæå®ããããã®å®è£
ãã¿ã¼ã³
ã¨ããèªèãããã
ã©ã¡ãã使ã£ã¦ãç®çã¯éæã§ãããã
ããããç¨éãç°ãªãããªã¼ã¨æã£ã¦ããã®ã§ã
ã¨ãããããä¸è¨ã®èªèéãã«ä½¿ãåãã¦ãããããªã¼ã¨æã£ã¦ããã
ããã¦ãMethodChaining ãå©ç¨ããå ´åã
MethodChaining ã¨ãã¦ã®è§£æ±ºæ¹æ³ ãé©ç¨ãããã©ãããæ°ã«ãªã£ã¦ãããã
ãããã©ã£ã¡ã§ãããã¨æãã
ãã ãå人çã«ã¯ãæ»ãå¤ã§æ»ã£ã¦ããæ¹ãåãããããããªã¼ã¨æãã®ã§ã
é©ç¨å¯è½ã§ããã°é©ç¨ããããªã¼ã¨ããã¨ããã
ã¾ã¨ã
FunctionalOptionPattern or MethodChaining ãæ©ããã ã£ããããã£ã¨ä»ã«æ©ãã¹ãã³ã¼ãããããããªã®ã§ã
ãã£ã¡ãåªå ããæ¹ãããã¨æãã