처음부터 완벽하게 하긴 어렵겠지만
수도코드를 정확하고 구체적으로 작성해라.
타입에도 마찬가지로 적용된다.
type entries []*ldap.Entry
func (r entries) getFirst() *ldap.Entry {
return r[0]
}
func (r entries) getFirstAttributeValue(value string) string {
return r.getFirst().GetAttributeValue(value)
}
func (r entries) getFirstAttributeValueList(value string) []string {
return r.getFirst().GetAttributeValues(value)
}
userEntries := entries(userInfo.Entries)
hospitalEntries := entries(hospital.Entries)
EmployeeNumber := userEntries.getFirstAttributeValue("employeeNumber")
UserId := userEntries.getFirstAttributeValue("uid")
Departments := userEntries.getFirstAttributeValueList("departments")
DefaultService := userEntries.getFirstAttributeValue("defaultService")
Roles := strings.Split(userEntries.getFirstAttributeValueList("roles")[0], ",")
Services := hospitalEntries.getFirstAttributeValueList("services")
http response 등등
이때 golang의 reflect 패키지는 피하자. generic type을 활용하자.
제일 먼저 가장 크고 굵직한 로직(비즈니스로직)을 코드로 나타낸다.
구조체에 필드가 많은 경우 별도의 타입을 정의하자.
//예시: 로그인에 사용할 타입
type TokenPayload struct {
OrgId string `mapstructure:"orgId"`
UserId string `mapstructure:"userId"`
Employeenumber string `mapstructure:"employeeNumber"`
Departments []string `mapstructure:"departments"`
DefaultService string `mapstructure:"defaultService"`
Services []string `mapstructure:"services"`
Roles []string `mapstructure:"roles"`
Cn string `mapstructure:"cn"`
Sn string `mapstructure:"sn"`
}
인증과 관련된 모듈은, 환경변수를 사용하는 경우가 많기 때문에 별도의 패키지를 만들어서 분리하는 것이 좋다. (토큰 발급과 검증, 비밀번호 해싱과 검증 등등…)
reflect는 불확정성을 만드는 기능의 집합 패키지라고 한다.
문맥상의 일관성을 유지하자
조건문마다 return했다면 마지막 부분에도 return하자.
11.21 토큰 리프레시 로직 핸들러가 필요 없는 이유~
사용자가 액세스 ,리프레시 쿠키 모두 함께 보내게 되는데 크라켄디에서 다음을 이용하여 각 토큰에 대한 서명키를 auth/validator에 모두 명시하게 되면…
Token validation with multiple Identity Providers
순수함수는 제외.
순수함수란 같은 인자를 전달하는 조건에서 언제 어디서 실행하든, 항상 동일한 결과를 리턴하며, 외부 환경에 절대로 영향(부수효과)을 주지 않는 함수다.
예
func add (a, b int) int {
return a + b
}
//외부의 어떤 변수나 함수에도 영향을 주지 않는다.
//인자만 일정하다면 언제 어디서 실행하든 같은 결과
다음은 순수 함수가 아니다
var c = 10
func add (a, b int) int {
c = b
return a + b
}
//외부 변수 c의 값을 변경하였으므로 순수함수가 아님
//또한 c 값이 변경되면 함수 결과값도 변한다는 점에서 순수함수가 아니다.
//c가 상수라면 순수함수다.
func sub (a, b int) int {
b = c
return b
}
// var n int
// sub(7,n) ---> n의 값은 10이 됨.(순수함수가 아님)
type m struct{
val int
}
var obj1 = m{10};
func add4(obj, b int){
obj.val += b;
}
var obj1 = {val : 10};
func add5(obj, b){
return { val: obj.val + b }// obj의 val만 참조만 할 뿐 변경없음.
}
fmt.Println(obj1.val);//변경 전 10
var obj2 = add5(obj1,5);
fmt.Println(obj1.val);//변경 후 10
fmt.Println(obj2.val);//15
11.22 여기서부터!
반복이 되는 내용은 함수로 만든다. 단 가독성을 해치지 않는 선에서 하자
c.JSON(http.StatusBadRequest, gin.H{
"message": "최대 로그인 횟수를 초과했습니다",
})
함수 클로저를 사용하는 경우:
⇒ 테스트 mocking을 위해 사용할 경우 구조가 매우 복잡해진다. 일반 func 구조로 작성해야한다.
var DialAndBind = func(bindUsername, bindPassword string) (*ldap.Conn, error) {
l, dialError := ldap.Dial("tcp", FQDN)
if dialError != nil {
fmt.Println(dialError)
return nil, dialError
}
err := l.Bind(bindUsername, bindPassword)
if err != nil {
fmt.Println(err)
return nil, err
}
Connect = l
return l, nil
}
에러 처리는 그 즉시 이루어져야 한다.
http 요청을 보내기 위해 marshaling이 필요한 경우, 반드시 예외 처리가 필요하다.
매우 크고 긴 복잡한 로직이라면 func로 분리하자.
문맥의 일관성을 유지하자. 모두 리턴 처리를 하고 있다면 리턴을 하자.