77호. 마르셀 포시오트가 생각하는 간결한 코드, 그리고 실전 예시 free

2019-10-22

마르셀 포시오트가 블로그에 Embracing simplicity in your code 라는 제목으로 글을 올렸습니다. 간결한 코드를 작성하자는 것인데요. 간단히 요약해봤습니다.


예제 코드의 간단함에 속지 말것


우선 간결함에 대해 독자와 공감대를 형성하고자 했습니다. 포시오트는 강연이나 비디오 코스 등에서 실제 프로젝트에서는 사용하기 어려운 간단한 코드를 예제로 사용한다고 합니다. 목적은 가르치고자 하는 내용을 효과적으로 전달하기 위해서이죠. 유효성 검사나 예외처리는 실제 프로젝트에는 당연히 필요하지만 그것이 직접적인 교육의 대상이 아니면 제거하는 것이죠. 사실 이는 포시오트 외에 다른 사람들도 마찬가지 입니다. 현실 프로젝트 처럼 하기엔 너무 귀찮고, 집중도가 흐트러져버리기 때문에 교육 목적에 해당하지 않는 코드는 작성하지 않죠. 따라서, 이 글에서 말하고자 하는 간단한 코드는 강의나 튜토리얼에서 보는 간략해진 코드를 의미하지 않습니다. 오히려 이런 코드를 복사해서 사용하거나 따라하면 실전에서는 크게 낭패를 볼 수 있죠.


간결한 코드란



  • 표현력이 있습니다(Simple code is expressive): 마치 프로그램 코드가 아닌 평범한 글 처럼 읽힙니다.

  • 놀랍지 않습니다(Simple code is unsurprising): 특별하지 않고, 읽는데 오래 걸리지 않습니다.

  • 투명합니다(Simple code is transparent): 무엇을 왜 하는지가 투명하게 보입니다.

  • 유지보수할 맛이 납니다(Simple code is fun to maintain)


간결한 코드의 특징이 아닌 것


간결한 코드가 작성하기도 쉬운 건 아닙니다. 간결한 코드를 작성하는 건 시간이 오래 걸리고, 여러 번의 수정이 필요할 수 있습니다.


어디서 부터 시작할 것인가


포시오트는 '간결한 코드가 어떻게 생겼는지 아는 것'에서 시작하면 좋다고 이야기합니다. 아래는 수년 전에 포시오트가 토이 프로젝트에 작성했던 코드 원본과 이번에 리팩토링한 코드입니다. 두 코드의 차이를 느껴보세요.


Before


public function handle()
{
$players = Player::all();
foreach ($players as $player) {
if (!is_null($player->refresh_token)) {
$token = APIHelper::getNewAccessTokenForPlayer($player);
$command = "python pokecli.py -a google -u " . $token;
} else {
$command = "python pokecli.py -a ptc -u " . Crypt::decrypt($player->ptc_username) . " -p ". Crypt::decrypt($player->ptc_password);
}
$process = new Process($command, base_path('bin/pgoapi'));
$process->run();

$output = @json_decode($process->getOutput(), false, 512, JSON_BIGINT_AS_STRING);

$profile = $output->responses->GET_PLAYER->profile;
// Save player
$pokecoins = collect($profile->currency)->where('type', 'POKECOIN')->first();
$stardust = collect($profile->currency)->where('type', 'STARDUST')->first();
$profileData = [
'item_storage' => $profile->item_storage,
'pokecoin' => isset($pokecoins->amount) ? $pokecoins->amount : 0,
'stardust' => isset($stardust->amount) ? $stardust->amount : 0,
'poke_storage' => $profile->poke_storage,
'team' => isset( $profile->team ) ? $profile->team : -1,
];
$player = Player::updateOrCreate([
'username' => $profile->username,
'auth_type' => 'google',
'creation_time' => strftime("%Y-%m-%d %H:%M:%S", ($profile->creation_time/1000))
], $profileData);

\Cache::forget('player_details.'.$player->getKey());
APIHelper::updateStatistics($player, $output);

$this->info('Updated player ' . $player->username);
}
}

After


public function handle()
{
Player::query()->each(function (Player $player) {
$output = $this->getLatestPokemonProfileFromApi($player);

$profile = $output->responses->GET_PLAYER->profile;

$player = $this->updatePlayerWithPokemonProfile($profile);

APIHelper::updateStatistics($player, $output);

$this->info('Updated player ' . $player->username);
});
}

어떤가요? 리팩토링을 거친 코드가 더 표현력있고, 놀랍지 않고, 투명하고, 유지보수할 맛이 나게 보이나요? 친절하게도 리팩토링 과정을 영상으로 첨부해주었습니다. 다른 사람의 리팩토링 과정을 보는 것 만으로도 실력 향상에 도움이 되는 것 같습니다. 길지 않은(11분) 영상이니 시간 내셔서 한 번 시청해보시기 바래요.


1일 1식 라라벨 77호

2019년 10월 22일


이현석

메쉬 코리아 개발자. 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 2020년에 출간될 Laravel Up & Running 2nd Edition을 번역하고 있습니다.