플레이스토어 출시도 끝났겠다. 정리정돈을 좀 하자.
앞으로 다양한 기능을 추가하기 전에 코드를 좀 더 간결하게 하기 위해 리팩터링을 진행해보려 한다. 지난 프로젝트로 배운 것은 리팩터링 작업은 선택이 아니라 필수라는 점이다. 물론 처음부터 완벽한 코드를 작성하는 고수분들은 다르시겠지만, 나 같은 경우에는 한 번에 완벽한 코드를 작성하기 쉽지 않다. 그렇다고 기능 구현만 간신히 되는 코드를 방치하면 나중에는 얽히고 섥혀서 기능을 확장하는 게 어려워진다. 여유가 될 때마다 기능 구현에 필요한 시간을 너무 잡아먹지 않는 선에서 코드를 개선하는 것이 좋아보인다. 그럼 어떤 의식의 흐름으로 리팩터링하는지 알아보도록 하자.
// 이게 바로 문제의 코드이다.
class EditorViewModel(private val databaseRepository: DatabaseRepository) : ViewModel() {
private val lineNumberModel = LineNumber("")
var statementEditView = MutableLiveData<EditText>()
val lineNumberView = MutableLiveData<String>()
// Activity_editor.xml과 data binding #EditText의 afterTextChanged()
fun onStatementChanged() {
val editText = statementEditView.value
val layout = editText?.layout
layout?.let {
lineNumberModel.content = generateLineNumber(it.lineCount)
lineNumberView.value = lineNumberModel.content
}
}
// Activity_editor.xml과 data binding #버튼 클릭시 실행
fun execStatement(): Any? {
return statementEditView.value?.let {
if (isQueryStatement(statementEditView.value.toString())) {
databaseRepository.execQuery(it.text.toString())
} else {
databaseRepository.execStatement(it.text.toString())
}
}
}
// SQL문이 쿼리인지 검증. 즉 SELECT로 시작하는지 확인
private fun isQueryStatement(statement: String): Boolean {
return statement.startsWith("SELECT") or statement.startsWith("select")
}
// Line Count를 입력받으면 Line Number을 생성.
private fun generateLineNumber(count: Int): String {
val stringBuilder = StringBuilder()
for (i in 1..count) {
stringBuilder.append("$i\n")
}
return stringBuilder.toString()
}
}
코드를 하나하나 뜯어보면서 어떤 점이 마음에 안 드는지 정리해보자. 내가 생각해는 좋은 코드에 대한 질문을 하나씩 던지면서 어떤 점이 문제인지 찾아보도록 하겠다.
접근지정자와 변수명
private val lineNumberModel = LineNumber("")
var statementEditView = MutableLiveData<EditText>()
val lineNumberView = MutableLiveData<String>()
EditText 변화 탐지 함수 : onStatementChanged()
// Activity_editor.xml과 data binding #EditText의 afterTextChanged()
fun onStatementChanged() {
val editText = statementEditView.value
val layout = editText?.layout
layout?.let {
lineNumberModel.content = generateLineNumber(it.lineCount)
lineNumberView.value = lineNumberModel.content
}
}
SQL문 실행 함수 : execStatement()
// Activity_editor.xml과 view binding #버튼 클릭시 실행
fun execStatement(): Any? {
return statementEditView.value?.let {
if (isQueryStatement(statementEditView.value.toString())) {
databaseRepository.execQuery(it.text.toString())
} else {
databaseRepository.execStatement(it.text.toString())
}
}
}
쿼리문 검증 함수 : isQueryStatement()
// SQL문이 쿼리인지 검증. 즉 SELECT로 시작하는지 확인
private fun isQueryStatement(statement: String): Boolean {
return statement.startsWith("SELECT") or statement.startsWith("select")
}
Line Number 생성 함수 : generateLineNumber()
// Line Count를 입력받으면 Line Number을 생성.
private fun generateLineNumber(count: Int): String {
val stringBuilder = StringBuilder()
for (i in 1..count) {
stringBuilder.append("$i\n")
}
return stringBuilder.toString()
}
가독성
객체지향
자원 낭비
의도 실패
가독성
자원 낭비
관심사
기능 구현에 너무 화이팅이 넘친 나머지 상당히 엉망인 코드가 탄생했다. 그 중 상당 부분은 개발 당시에도 문제점을 알았지만 시간에 쫓기는 바람에 수정하지 못했다. 다음 포스팅을 통해서 문제를 하나 하나 수정해보도록 하자! Repository의 실제 Refactoring Issue가 궁금하다면 아래의 참고를 확인하는 걸 추천한다 :)