본문 바로가기
메타인지

코딩 잘하는 3가지 팁 (현직 개발자 추천)

by 디지털노마더 2021. 4. 30.

개발을 오랫동안 진행하다보면, 자주 겪게 되는 현상이 있습니다.

하나의 함수를 만들었는데, 나중에 보니 비슷한 함수가 이미 만들어져 있는 경우입니다. (함수 중복)

 

생각의 흐름대로 코드를 작성하다보면, 하나의 함수에 많은 기능을 포함시키거나

안드로이드 개발 시, onCreate() 함수에서 자동로그인 확인, 사용자 정보 불러오기 (네트워크 통신) 기능을 구현하여

코드 유지보수 과정에서 복잡하게 보여지는 경우가 많습니다.

 

개발자라면 누구나 쉽게 파악이 가능한 코드를 만들고 싶어합니다. 

이를 실현하기 위해서는 3가지 원칙을 지키면 됩니다.


▷ DRY: Don't Repeat Yourself

 - '반복하지 마라' 원칙
 - 시스템에서 지식과 로직은 단 한곳에서 명확하고 신뢰할 수 있도록 존재해야 한다.
 - 여러 모듈에 걸쳐 동일한 로직을 반복적으로 작성한다면, 로직이 변경이 생겼을 때 모듈의 갯수만큼 수정해야 한다.
 - 로직을 한 모듈에 작성하고 이를 참조하는 방식으로 작성하면 재사용성과 유지보수 효율성이 높아진다.

하나의 모듈에 정의하여 재사용.

* DRY 관련 예제소스

/** DRY **/

// Bad Case
// 문제점: middleName을 필요로 할 때, 모든 함수에 user.middleName을 추가해줘야 한다.
function greetings(user) {
    return 'Hi ${user.firstName} ${user.lastName}';
}

function goodbye(user) {
    return 'See you next time ${user.firstName} ${user.lastName}';
}


// Good Case
// 개선안: User 클래스를 생성하여, 내부함수로 정의하여 사용
function greetings(user) {
    return 'Hi ${user.fullName()};
}

function goodbye(user) {
    return 'See you next time ${user.fullName()}';
}

class User {
    fullName() {
        return '${user.firstName} ${user.middleName} ${user.lastName}'
    }
}

 

 

 

 

 

 

▷ KISS: Keep It Simple, Stupid

 - '심플하고 멍청하게 유지하자' 원칙
 - 대부분의 시스템은 심플하게 구성되어 있을 때 최고로 잘 동작한다.
 - 불필요한 복잡성은 피해야 한다.
 - 클래스와 함수는 하나의 책임과 역할만을 담당해야 한다.
 - View에 비지니스 로직은 포함하지 않고, UI와 관련된 역할만 수행해야 한다.
 - Service는 여러가지 기능을 담당하기 보다는, 개별적인 기능만 담당하도록 만들어야 한다.

 

* KISS 관련 예제소스

/** KISS **/
// Bad Case
// 문제점: 하나의 함수에 2가지 기능(return)이 정의
function getFirst(array, isEven) {
    if(isEven) {
        return array.find(x=> x % 2 === 0);
    }else {
        return array.find(x=> x % 2 !== 0);
    }
}

// Good Case
// 개선안: 함수를 원하는 용도에 맞게 별도로 구성
function getFirstOdd(array) {
    return array.find(x=> x % 2 !== 0);
}

function getFirstEven(array) {
    return array.find(x=> x % 2 === 0);
}

 

// Bad Case
// 문제점: 하나의 클래스에 "사용자, 주문, 결제"에 대한 많은 기능이 포함
class UserOrderService {
    userDb;
    orderDb;
    paymentClient;
    processUserOrder(userId, orderId) {
        const user = userDb.select(/* db query*/);
        if(!user) {
            throw Error('...');
        }
        const order = orderDb.select(/* db query*/);
        if(!order) {
            throw Error('...');
        }
        paymentClient
            .connect(/* url */)
            .then(/* process payment */)
            .catch(/* retry */);
        orderDb.updateOrder(order, PAID);
    }
}


// Good Case
// 개선안: 하나의 기능별로 담당하도록 개별 클래스 분리
class UserService {
    userDb;
    getUser() {
        return userDb.select(/* db query*/);
    }
}

class OrderService {
    orderDb;
    createOrder(user, product) {}
    getOrder(orderId) {
        return orderDb.select(/* db query*/);
    } 
    updateOrder(order) {
        orderDb.updateOrder(order, PAID);
    }
}

class PaymentService {
    paymentClient;
    processUserOrder(orderRequest) {
        return paymentClient
            .connect(/* url */)
            .then(/* process payment */)
            .catch(/* retry */);
    }
}

 

 

 

 

 

 

// Bad Case
// 문제점: UI 요소에 네트워크 통신 로직도 섞여서 표현되어 있다.
class LoginView {
    display() {
        // display view..
    }

    onLoginButtonClick() {
        fetch("https://server.com")
        .then(data => data.json())
        .then(data => {
            if(data.token) {
                localStorage.setItem('TOKEN', data.token);
                // update UI elements
            }else {

            }
        });
    }
}

// Good Case
// 개선안: UI와 관련없는 요소는 별도의 클래스화
class LoginView {
    constructor(userPresenter) {
        this.userPresenter = userPresenter;
    }

    display() {
        // display view..
    }

    // View에서는 사용자에게 보여지는 화면요소를 컨트롤하는 것만 담당
    onLoginButtonClick() {
        this.userPresenter
            .login()
            .then(result => {
                // update text UI element with result.displayMessage
                // update button UI element with result.buttonText
            });
    }
}

class UserPresenter {
    userService;
    login() {
        this.userService
            .login()
            .then(result => {

                if(result.success) {
                    localStorage.setItem('TOKEN', data.token);
                    return {
                        displayMessage: result.message,
                        buttonText: 'Go Home'
                    };
                }else{
                    return {
                        displayMessage: 'Unable to login',
                        buttonText: 'Ok'
                    }
                }
                
            })
            .catch(error => {
                // Something really went wrong!!
            });
    }
}

 

 

▷ YAGNI: You Ain't Gonna Need It

 - '필요하지 않는, 필요하지 않는, 미래지향적인 기능은 없애자' 원칙
 - 깨끗하게 / 변경이 쉽게 / 유지보수 용이하게 코드를 만들자는 취치.

 

* YANGI 관련 예제소스

/** YAGNI **/
// Bad Case
// 문제점: 미래 지향적인 SoftDelete 기능을 임의로 추가
function deleteUser(id, SoftDelete = false) {
    if(SoftDelete) {
        // DB에서 삭제되지 않고, 단순히 삭제마크만 표시
        return this._softDelete(id);
    }

    return db.removeById(id);
}


// Good Case
// 개선안: 하나의 함수에서는 단일기능만 담당해야 한다.
function deleteUser(id) {
    return db.removeById(id);
}

 

끝으로 드림코딩 엘리님의 "코딩 잘하는 팁 세가지(이걸 알면 코드가 깔끔해진다.)

영상을 첨부해드립니다.

 

 

▶ 개발자로 성장하는 더 많은 꿀팁이 궁금하시다면?

  (최연소 팀장급 개발자로 성장하는 노하우를 PDF로 정리했습니다.)

 

 

지방대 출신 팀장급 개발자로 성장하는 노하우를 드립니다. | 10000원부터 시작 가능한 총 평점 5

1개 총 작업 개수 완료한 총 평점 5점인 슬기로운자기계발의 취업·투잡, 전자책·노하우 서비스를 1개의 리뷰와 함께 확인해 보세요. 취업·투잡, 전자책·노하우 제공 등 10000원부터 시작 가능한

kmong.com

 

댓글