Skip to content

Latest commit

Β 

History

History
466 lines (345 loc) Β· 12.2 KB

File metadata and controls

466 lines (345 loc) Β· 12.2 KB

General

[ Basic rules ]

βœ“ 무엇을 μ„ μ–Έν•  λ•ŒλŠ” 기본적으둜 κ°€μ‹œμ„±μ΄ κ°€μž₯ 쒁게 μ„ μ–Έν•œλ‹€.

πŸŒŸλ­λ“ μ§€ μš°μ„  μ•ˆλ˜κ²Œ ν•˜κ³  λ‚˜μ€‘μ— ν•„μš”ν•  λ•Œ λ˜κ²Œν•˜λΌ. 🌟

  • λ³€μˆ˜/ν•¨μˆ˜λ₯Ό μ„ μ–Έν•  경우 μŠ΅κ΄€μ μœΌλ‘œ private λ₯Ό λΆ™μ—¬ μ„ μ–Έν•˜κ³  이후 μ™ΈλΆ€μ—μ„œ ν•„μš” μ‹œ public 으둜 μ „ν™˜ν•œλ‹€.

  • 클래슀의 경우 기본적으둜 internal 을 λΆ™μ—¬ μ„ μ–Έν•œλ‹€.

  • μœ„μ²˜λŸΌ ν•  경우 μžμ‹ μ΄ μ§  μ½”λ“œμ˜ λ³€μˆ˜μ— private κ°€ μ—†μœΌλ©΄ λ‹€λ₯Έ κ°œλ°œμžκ°€ μžμ‹ μ˜ μ½”λ“œλ₯Ό λ³Ό λ•Œ ν•΄λ‹Ή λ³€μˆ˜λŠ” λ‹€λ₯Έ κ³³μ—μ„œ 참쑰되고 μžˆλ‹€λŠ” 것을 μžμ—°μŠ€λŸ½κ²Œ μ•Œ 수 있게 λœλ‹€.

    • μ½”ν‹€λ¦°μ—μ„œ κΈ°λ³Έ ν΄λž˜μŠ€κ°€ 상속이 μ•ˆλ˜κ³  상속이 λ˜κ²Œν•˜λ €λ©΄ open 을 λΆ™μ΄λ„λ‘ν•˜λŠ” 것은 μœ„ 🌟 ν‘œμ‹œμ˜ μ² ν•™κ³Ό λΉ„μŠ·ν•˜λ‹€.
😰 
val badVarible = 0

class BadClass

😍
private val goodVariable = 0

internal class GoodClass

βœ“ CamelCase base

  • 기본적으둜 Camel case λ₯Ό μ‚¬μš©ν•œλ‹€.
  • ν•˜μ§€λ§Œ μ•„λž˜μ™€ 같은 μ˜ˆμ™ΈλŠ” μžˆλ‹€.
    • ν…ŒμŠ€νŠΈ μ½”λ“œμ˜ μ‹€μ œ ν…ŒμŠ€νŠΈ ν•¨μˆ˜λͺ…은 snake case 둜 μ‚¬μš©ν•œλ‹€.
    • ν…ŒμŠ€νŠΈ μ½”λ“œλŠ” ν•œκΈ€λ‘œ μž‘μ„±ν• κΉŒ κ³ λ € 쀑..
      fun this_function_return_true() { ... }
    • ν…ŒμŠ€νŠΈ μ½”λ“œ 쀑 setUp κ³Ό tearDown ν•¨μˆ˜λŠ” Camel case λ₯Ό μ‚¬μš©ν•œλ‹€.
      @Before
      fun setUp() { ... }
      
      @After
      fun tearDown() { ... }

βœ“ static / const ν•„λ“œλŠ” μ „λΆ€ λŒ€λ¬Έμžλ‘œ μž‘μ„±ν•˜λ©° snake case λ₯Ό μ‚¬μš©ν•œλ‹€.

😰
companion object {
  private const val badConstVariable = 1
}

😍
companion object {
  private const val GOOD_CONST_VARIABLE = 1
}

βœ“ table-like line-up (tllu)

  • μƒμ„±μžμ— arguments κ°€ λ§Žμ•„μ Έ μ½”λ“œκ°€ κΈΈμ–΄μ§ˆ 경우 가독성을 높이기 μœ„ν•΄ μ•„λž˜λ₯Ό μ°Έμ‘°ν•΄ μ½”λ“œλΌμΈμ˜ 정렬을 λ§žμΆ˜λ‹€.
    • μ˜ˆμ™Έ) μƒμ„±μžκ°€ μ•ˆμ˜ arguments κ°€ 1-3 개일 경우 그리고 κ·Έλ ‡κ²Œ κΈΈμ§€ μ•Šμ„ κ²½μš°λŠ” ν•œ μ€„λ‘œ 써도 λ¬΄λ°©ν•˜λ‹€.
    • μ˜ˆμ™Έ) μΌλ°˜ν•¨μˆ˜ ν˜Ήμ€ μ½”ν‹€λ¦° secondary μƒμ„±μžμ—μ„œλŠ” λ„ˆλ¬΄ κΈΈμ§€ μ•Šμ€ 이상 μ›¬λ§Œν•΄μ„  ν•œ μ€„λ‘œ 쓰도둝 ν•œλ‹€.
😰 
internal class BadLineUpConstructor constructor(private val resource: Resources, private val weakContext: WeakReference<Context>, private val repository: RepositoryApi, private val remoteAction: RemoteActionApi) : ParentClass { 

  ...

}

😍
internal class GoodLineUpConstructor constructor(
    private val resource: Resources, 
    private val weakContext: WeakReference<Context>, 
    private val repository: RepositoryApi, 
    private val remoteAction: RemoteActionApi
    
) : ParentClass {

    ...

}
  • λ…Όλ¦¬μ μœΌλ‘œ μœ μ‚¬ν•œ μž‘μ—…μ„ ν•˜λŠ” μ½”λ“œλΌμΈλ“€μ„ λΆ™μ—¬μ„œ μž‘μ„±ν•  경우 μ•„λž˜λ₯Ό μ°Έμ‘°ν•΄ μ½”λ“œλΌμΈμ˜ 정렬을 λ§žμΆ˜λ‹€.
    • μ˜ˆμ™Έ) 라인사이에 곡백라인이 μžˆμ„ 경우 tllu ν•˜μ§€ μ•ŠλŠ”λ‹€. 즉, tllu ν•˜κΈ° μ‹«λ‹€λ©΄ 라인사이에 곡백을 λ„£λŠ”λ‹€.
😰
//case 1
private val badLineUp = PublishRelay<Int>.create()
private val badLineUpSecondRelay = PublishRelay<Int>.create()
private val badLineUpThirdRelay = PublishRelay<Int>.create()

//case 2
private val alsoBadLineUp            = PublishRelay<Int>.create()

private val alsoBadLineUpSecondRelay = PublishRelay<Int>.create()

private val alsoBadLineUpThirdRelay  = PublishRelay<Int>.create()

😍
//case 1
private val goodLineUp            = PublishRelay<Int>.create()
private val goodLineUpSecondRelay = PublishRelay<Int>.create()
private val goodLineUpThirdRelay  = PublishRelay<Int>.create()

//case2
private val alsoGoodLineUp = PublishRelay<Int>.create()

private val alsoGoodLineUpSecondRelay = PublishRelay<Int>.create()

private val alsoGoodLineUpThirdRelay = PublishRelay<Int>.create()
  • kotlin ν•¨μˆ˜ μ½œμ—μ„œ hint 도 μ•„λž˜λ₯Ό μ°Έμ‘°ν•΄ 정렬을 λ§žμΆ˜λ‹€.
😰
loginRepository.requestLogin(
  id = id,
  password = password,
  token = token
)

😍
loginRepository.requestLogin(
  id       = id,
  password = password,
  token    = token
)

βœ“ λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈ μ‚¬μ΄μ˜ 곡백은 ν•œμΉΈμ„ μ‚¬μš©ν•œλ‹€. 두칸 이상 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.

😰
private val someVariable = 0
                                        /** 이곳에 곡백라인이 두칸이면 */
                                        /** μ•ˆλœλ‹€. */
private fun someFunction1() {
  ...
}
                                        /** 이곳에 곡백라인이 두칸이면 */
                                        /** μ•ˆλœλ‹€. */
private fun someFunction2() {
  ...
}

😍
private val someVariable = 0
                                        /** ν•œμΉΈμ˜ 곡백라인만 !*/
private fun someFunction1() {
  ...
}
                                        /** ν•œμΉΈμ˜ 곡백라인만 !*/
private fun someFunction2() {
  ...
}

βœ“ λΆˆν•„μš”ν•œ μ½”λ©˜νŠΈλŠ” ν”Όν•œλ‹€.

  • μ•„λž˜μ™€ 같은 κ²½μš°μ—λ§Œ μ½”λ©˜νŠΈλ₯Ό μž‘μ„±ν•˜λ©° μ½”λ©˜νŠΈλŠ” // κ°€ μ•„λ‹Œ /** ... */ λ₯Ό μ‚¬μš©ν•œλ‹€.
    • μ½”λ“œκ°€ ν•˜λŠ” μž‘μ—…μ΄ λ³€μˆ˜λͺ…μ΄λ‚˜ λ©”μ†Œλ“œλͺ…λ§ŒμœΌλ‘œλŠ” κ·Έ 의미λ₯Ό μ „λ‹¬ν•˜κΈ° 맀우 νž˜λ“€ 경우.
    • λΆˆκ°€ν”Όν•˜κ²Œ λ§€μ§μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜κ²Œ λ˜μ–΄ κ·Έ μƒμˆ˜μ˜ 의미λ₯Ό 전달할 ν•„μš”κ°€ μžˆμ„ λ•Œ.
    • μ½”λ“œλ§ŒμœΌλ‘œλŠ” μ„€λͺ…ν•  수 μ—†λŠ” History κ°€ μžˆμ„ 경우. (ex: 이 μ½”λ“œλŠ” ~이슈 λ•Œλ¬Έμ— μ΄λ ‡κ²Œ μ§°κ³  ~ν•΄μ„œ μž‘λ™ν•œλ‹€)
    • μΌλ°˜μ μ΄μ§€μ•Šμ€ 데이터 처리의 경우. (ex: 이 λ°μ΄ν„°λŠ” ~ν•˜κ²Œ 였기 λ•Œλ¬Έμ— ~ν•΄μ„œ μ²˜λ¦¬ν•΄μ•Όν•œλ‹€)
      • 예) onMeaure의 parameter듀은 μ—¬λŸ¬ 정보가 bitwise 돼 λ‹΄κ²¨μ˜€κΈ° λ•Œλ¬Έμ— View.MesureSpec 둜 unpack ν•΄μ„œ μ‚¬μš©ν•΄μ•Όν•œλ‹€.
😰 // Bad Comment 

😍 /** Good Comment */

βœ“ Numeric literal 의 suffix λŠ” λŒ€λ¬Έμžλ₯Ό μ‚¬μš©ν•œλ‹€.

😰 private val badFloat = 1f

😍 private val goodFloat = 1F

βœ“ 10만 μ΄μƒμ˜ Numeric literal 을 ν‘œν˜„ν•  λ•ŒλŠ” underscore λ₯Ό μ‚¬μš©ν•œλ‹€.

😰 private val badNumber = 111111

😍 private val goodNumber = 1_111_111

βœ“ Brace λ₯Ό μ΅œλŒ€ν•œ μ‚¬μš©ν•œλ‹€.

😰 
if(condition) 
  Log.d(TAG, "bad!") 
else 
  Log.d(TAG, "also bad!")

😍 
if(condition) {
  Log.d(TAG, "GOOD!") }
else {
  Log.d(TAG, "also GOOD!")
}

βœ“ μ½”λ“œμ˜ 흐름은 κ°€λ‘œλ³΄λ‹€λŠ” μ„Έλ‘œμ˜ νλ¦„μœΌλ‘œ μž‘μ„±ν•œλ‹€.

  • if, switch, when, for 문등은 κ°€λ‘œλ‘œ ν•œ μ€„λ‘œ μ“°κΈ°λ³΄λ‹€λŠ” μ„Έλ‘œλ‘œ μž‘μ„±ν•œλ‹€.
  • μ˜ˆμ™Έ)
    • rx operator μ•ˆμ—μ„œλŠ” λ‚΄λΆ€ 둜직이 ν•œ μ€„λ‘œ μž‘μ„±μ΄ κ°€λŠ₯ν•  경우 ν•œμ€„λ‘œ μž‘μ„±ν•œλ‹€.
    • lamda/closure μ—μ„œλŠ” λ‚΄λΆ€ 둜직이 ν•œ μ€„λ‘œ μž‘μ„±μ΄ κ°€λŠ₯ν•  경우 ν•œμ€„λ‘œ μž‘μ„± κ°€λŠ₯ν•˜λ‹€.(두쀄도 κ°€λŠ₯)
😰 
if(condition) { Log.d(TAG, "bad!") }

private val badOpeartorStyle = Observable.just(1, 2, 3)
  .filter {
    it == 1
  }
  .map {
    it + SOME_VALUE
  }

😍 
if(condition) {
  Log.d(TAG, "GOOD!") 
} else {
  Log.d(TAG, "also GOOD!")
}

private val goodOperatorStyle = Observable.just(1, 2, 3)
  .filter { it == 1 }
  .map { it + SOME_VALUE }
  
good_lamda.setOnClickListener { doSomething() }

also_good_lamda.setOnClickListener {
  doSomething()
}

βœ“ λ©”μ†Œλ“œ μ–΄λ…Έν…Œμ΄μ…˜μ€ μ„Έλ‘œλ‘œ μž‘μ„±ν•œλ‹€.

😰 
@Provides @PerActivity
fun badAnnotating(): String { ... }

😍
@Provides 
@PerActivity
fun goodAnnotating(): String { ... }

βœ“ ν•„λ“œ μ–΄λ…Έν…Œμ΄μ…˜μ€ λ„ˆλ¬΄ κΈΈμ–΄μ§€μ§€ μ•ŠλŠ” 이상 기본적으둜 κ°€λ‘œλ‘œ μž‘μ„±ν•œλ‹€.

😰 
@Inject 
@field:Bad
lateinit var badAnnotating: String

😍
@Inject @field:Good lateinit var goodAnnotating: String

βœ“ Builder νŒ¨ν„΄μ˜ μ½”λ“œλ₯Ό λΆ€λ₯Ό λ•Œμ—λŠ” λ©”μ†Œλ“œλ₯Ό μ„Έλ²ˆμ΄μƒ λΆ€λ₯Ό λ•Œ LF ν•œλ‹€.

😰 
badBuilder.setInt(1)
  .build()
  
badBuilder.setInt(1).setBoolean(false).build()

😍
goodBuilder.setInt(1).build()
  
goodBuilder
  .setInt(1)
  .setBoolean(false)
  .build()

βœ“ μΆ•μ•½μ–΄λ₯Ό μ“°μ§€ μ•ŠλŠ”λ‹€.

😰 
private val usr = User() /** bad variable */

private val std = Student() /** bad variable */

private val probIndex = 0 /** bad variable */

😍
private val user = User() /** good variable */

private val student = Student() /** good variable */

private val problemIndex = 0 /** good variable */

βœ“ λ³€μˆ˜λͺ…은 κ·Έ λ³€μˆ˜κ°€ μ–΄λ–€ 의미λ₯Ό κ°–λŠ”μ§€ μ•Œ 수 μžˆλ„λ‘ μΆ©λΆ„νžˆ 길게 μ§“λŠ”λ‹€.

  • λ³€μˆ˜μ˜ μ˜λ―Έμ „λ‹¬ λ•Œλ¬Έμ— λ„ˆλ¬΄ κΈΈμ–΄μ§ˆ κ²½μš°λŠ” μ λ‹Ήν•œ μ„ μ—μ„œ μž‘μ„±ν•œλ‹€. 3~30 자 λ‚΄μ™Έ
  • flag λΌλŠ” μ΄λ¦„μ˜ λ³€μˆ˜λͺ…은 μ ˆλŒ€ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.
😰 
private val index = 0 /** bad naming */

private val isCorrect = false /** bad naming */

private val isLoginDataAndNewUpdateCheckDataAndNextDataFetched = false /** bad naming */

private val flag = false /** bad naming */

😍
private val mainProblemIndex = 0 /** good naming */

private val isMainProblemCorrect = false /** good naming */

private val isAllDatasFetched = false /** good naming */

βœ“ 맀직{λ„˜λ²„|슀트링|...}(은)λŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€. μƒμˆ˜λ‘œ 의미λ₯Ό μ •μ˜ν•΄μ„œ μ“΄λ‹€.

😰 
if(currentProblemNumber == 10) { /** bad magic number */
  completeLesson()
  navigateToResult()
}

if(problemType == "N") { /** bad magic string */
  hideHintTip()
}

😍
companion object {
  private const val MAX_PROBLEM_NUMBER = 10
  
  private const val NORMAL_PROBLEM_TYPE_PROVIDED_BY_SERVER = "N"
}

if(currentProblemNumber == MAX_PROBLEM_NUMBER) { /** good */
  completeLesson()
  navigateToResult()
}

if(problemType == NORMAL_PROBLEM_TYPE_PROVIDED_BY_SERVER) { /** good */
  hideHintTip()
}

βœ“ 0λΆ€ν„° μ‹œμž‘ν•˜λŠ” λ³€μˆ˜λŠ” index λΌλŠ” λ³€μˆ˜λͺ…을 μ‚¬μš©ν•˜κ³  1λΆ€ν„° μ‹œμž‘ν•˜λŠ” λ³€μˆ˜λŠ” order/number/sequence λΌλŠ” λ³€μˆ˜λͺ…을 μ‚¬μš©ν•œλ‹€.

βœ“ if 쑰건에 μ—¬λŸ¬κ°œ(3개 이상)의 쑰건이 ν•„μš”ν•  경우 μ•„λž˜μ™€ 같이 μž‘μ„±ν•œλ‹€.

😰 
if(badIfCondition && badIfCondition1 && badIfCondigion2) {
  ...
}

😍
if(goodIfCondition &&
    goodIfCondition1 && 
    goodIfCondition2) {
  ...
}

βœ“ {outer|inner|nested|sealed}클래슀/μΈν„°νŽ˜μ΄μŠ€μ˜ μ‹œμž‘κ³Ό 끝 곡백라인 첨가 μ—¬λΆ€λŠ” μ•„λž˜ 룰을 λ”°λ₯Έλ‹€.

  • μ΅œμƒμœ„ outer 클래슀만 클래슀의 μ‹œμž‘κ³Ό 끝에 곡백을 λ„£κ³  λ‚˜λ¨Έμ§€λŠ” 곡백을 λ„£μ§€ μ•ŠλŠ”λ‹€.
😰 
internal class BadOuterClass {
  private val context: Context? = null /** μœ— 라인에 곡백라인이 μžˆμ–΄μ•Όν•¨ */
  
  class BadNestedClass {
  
    private val myVarialble: Int = 0 /** μœ„ μ•„λž˜ 곡백라인이 μ—†μ–΄μ•Ό 함 */
  
  } 
} /** μœ— 라인에 곡백라인이 μžˆμ–΄μ•Όν•¨ */

internal interface BadInterface {

  fun doSomething() /** μœ„ μ•„λž˜ 곡백라인이 μ—†μ–΄μ•Ό 함 */

}

😍
internal class GoodOuterClass { /** outer ν΄λž˜μŠ€μ΄λ―€λ‘œ μ‹œμž‘κ³Ό 끝에 곡백라인이 있음 */

  private val context: Context? = null
  
  class GoodNestedClass { /** nested ν΄λž˜μŠ€μ΄λ―€λ‘œ μ‹œμž‘κ³Ό 끝에 곡백라인이 μ—†μŒ */
    private val myVarialble: Int = 0 
  }
  
}

internal interface GoodInterface { /** interface μ΄λ―€λ‘œ μ‹œμž‘κ³Ό 끝에 곡백라인이 μ—†μŒ */
  fun doSomething()
}

internal sealed class GoodSealedClass { /** sealed class μ΄λ―€λ‘œ μ‹œμž‘κ³Ό 끝에 곡백라인이 μ—†μŒ */
  class Class1( /** nested class μ΄λ―€λ‘œ μ‹œμž‘κ³Ό 끝에 곡백라인이 μ—†μŒ */
    val variable: Int,
    val variable1: Int,
    val variable2: Int,
  ) : GoodSealedClass()
  
  class Class2(val variable: Int) : GoodSealedClass()
}

βœ“ ν•¨μˆ˜/λžŒλ‹€|클둜져의 μ‹œμž‘κ³Ό λμ—λŠ” 곡백라인을 λ„£μ§€ μ•ŠλŠ”λ‹€.

😰
private fun badFunction() {
                                        /** λΆˆν•„μš”ν•œ 곡백라인! */
  doSomething()
                                        /** λΆˆν•„μš”ν•œ 곡백라인! */
}

private fun alsoBadFunction() {
                                        /** λΆˆν•„μš”ν•œ 곡백라인! */
  doSomething()
}

private fun alsoAlsoBadFunction() {
  doSomething()
                                        /** λΆˆν•„μš”ν•œ 곡백라인! */
}

bad_lamda.setOnClickListener {
                                        /** λΆˆν•„μš”ν•œ 곡백라인! */
  doSomething()
  doNextThing()
                                        /** λΆˆν•„μš”ν•œ 곡백라인! */
}

😍
private fun goodFunction() {
  doSomething()
  doNextThing()
}

good_lamda.setOnClickListener {
  doSomething()
  doNextThing()
}