> For the complete documentation index, see [llms.txt](https://sois-organization.gitbook.io/today-i-learned/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sois-organization.gitbook.io/today-i-learned/clean-code/03..md).

# 함수

### SPR : 함수의 역할은 하나만 할당한다.

* 하나의 함수에 역할이 많아지면 오류 발생 가능성이 커지고, 가독성이 떨어지며 테스트를 진행하기 어렵다.
* 따라서 하나의 함수에 많은 로직을 넣지 말자.

```swift
// as-is
func createUser(email, password) -> Bool {
    if email.contains("@") || password.contains("@") {
        //error
        return false
    }

    var user = User()
    user.email = email
    user.password = password

    database.add(user)

    emailClient = EmailClient()
    emailClient.setConfig()
    emailClient.send(email, "회원가입이 완료되었습니다")
    
    return true
}
    
```

```swift
// to-be
func createUser(email: String, password: String) -> Bool { // 주요 로직 실행 함수
    validateCreateUser(email, password)

    user = BuildUser(email, password)

    saveUser(user)
    sendEmail(email)
    return true
}

// 역할 별로 함수를 작성한다.
func validateCreateUser(_ email: String, _ password: String) { }

func Builduser() { }

func saveUser(_ user: User) { }

```

### DRY (Don’t repeat yourself) : 반복하지 말자

* 반복되는 코드가 많아지면, 전체 코드가 많아진다.
* 특정 부분에 변경사항이 생기면, 공통적인 모든 부분을 변경해줘야한다.
* 이에 관심사를 잘 분리하고 의존성을 줄이기 위해 반복되는 코드를 하나의 함수로 만들어서 사용하자.

```swift
// as-is

func createUser(email: String, password: String) {
    if email.contains("@") || password.contains("@") {
        //error
        return false
    }

    // code...
}

func updateUser(email: String, password: String) {
        if email.contains("@") || password.contains("@") {
        //error
        return false
    }

    // code...
}
```

```swift
// to-be
func validateCreateUser(_ email: String, _ password: String) -> Bool {
    if email.contains("@") || password.contains("@") {
        //error
        return false
    }
}

func createUser(email, password) {
    guard validateCreateUser(email, password) else { ... }
    // code..
}

func updateUser(email, password) {
    guard validateCreateUser(email, password) else { ... }
    // code..
}
```

### **파라미터 수는 적게 유지하자**

```swift
// as-is
func saveUser(userName: String, email: String, password: String, createAt: Int) {
    ...
}

// to-be
func saveUser(user: User) {
    ...
}
```

### **사이드 이펙트를 잘 핸들링하자**

* 사이드 이펙트란? (Side Effect)

  * 함수가 실행되었을 때, 함수 이외의 어떤 것들에 변화를 주는 것을 의미한다.
  * 이를 잘 다루지 못하면 예측하지 못하는 문제가 발생할 수 있다.
  * A, B, C, D라는 함수가 있을 때, A 실행시 B또는 C함수에도 영향을 주는 경우가 Side Effect라고 한다.

  ```swift
  // 사이드 이펙트가 없는 경우
  func getUser(email, password) -> User {
      let user = User(email, password)
      return user
  }

  // 사이드 이펙트가 있는 경우
  func updateUser(user) {
      var user = getUser(user.email, user.password)
      user.eail = "newEmail" // 인자로 받은 user 객체를 업데이트한다
      return user
  }

  // 사이드 이펙트가 있는 경우
  func createUser(email, password) {
      let user = User(email, password)
      dbSession() // 외부 DB 세션에 변화를 준다.
  }
  ```
* 사이드 이펙트 핸들링하는 방법
  * 코드를 통해 사이드이펙트를 예측할 수 있도록 네이밍을 잘 해야한다.
    * update, set 등 직관적인 prefix를 붙여 암시한다.
  * 함수의 사이드 이펙트가 있는 부분과 없는 부분으로 나누어 관리한다.
    * 명령과 조회를 분리하는 CQRS 방식이 존재한다.
      * 명령(Command) : 사이드이펙트가 존재
      * 조회(Read) : 사이드 이펙트가 없다
    * 하나의 함수에 명령과 조회 모두가 실행된다면, 사이드이펙트 덩어리가 된다. 이를 함수나 클래스로 영역을 나누어 분리시킨다.
  * 순수함수 형태로 사용하여 직관적으로 표현하고, 에러를 방지한다.

    * update 함수를 남발하지 않는다.

    ```swift
    // as-is
    var carts = [Cart]()

    // 사이드이펙트 발생
    func addCart(product: Cart) {
        casts.append(product)        // 외부에 있는 carts의 변경
    }

    product = Product()
    addCart(product: product)
    ```

    ```swift
    // to-be
    var carts = [Cart]()

    // 사이드이펙트가 없는 순수함수
    func getAddCart(product: Cart) -> [Cart] {
        return carts + product
    }

    carts = getAddCart(product)                // carts를 재선언한다.
    ```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sois-organization.gitbook.io/today-i-learned/clean-code/03..md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
