Skip to content

๐Ÿง‘๐Ÿปโ€๐Ÿ’ป Conventions

JunHyeong Lee edited this page Jan 3, 2023 · 10 revisions

์•ˆ๋“œ๋กœ์ด๋“œ ์ปจ๋ฒค์…˜

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ

  • Fragment ๋˜๋Š” Activity ์ฝ”๋“œ ์ตœ์†Œํ™”๋ฅผ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ ์ง€ํ–ฅ
  • ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ ๋ทฐ ์•„์ดํ…œ์˜ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋Š”ย XxxItem, xml์˜ ๋ฐ”์ธ๋”ฉ ๋ณ€์ˆ˜๋Š”ย itemย ์‚ฌ์šฉ
  • xml viewModel ๋ฐ”์ธ๋”ฉ ๋ณ€์ˆ˜๋Š” viewModel

๋ทฐ ID ๋„ค์ด๋ฐ

  • ๊ธฐ๋ณธ ํ˜•์‹:ย [what]\_[where]\_[des]ย ex) tv_addCalendar_titleHeader
    • ์„น์…˜์„ ํ™•์‹คํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์–ธ๋”๋ฐ”๋กœ ๊ตฌ๋ถ„๋˜์–ด ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ๊ณจ๋ผ ์ฝ๊ธฐ ํŽธํ•˜๋‹ค.
    • des๋ฅผ ์ฝ์„ ๋•Œ์—๋Š” ๊ตฌ๋ถ„ํ•ด์„œ ์ฝ์„ ์ผ์ด ์—†๋‹ค.
  • ๊ฐ ์ ˆ์—์„œ ๋‘ ๋‹จ์–ด ์ด์ƒ์ด ํ˜ผ์šฉ๋  ๋•Œ๋Š” camel case๋กœ ์ž‘์„ฑ.
  • ์นด๋ฉœ ์ผ€์ด์Šค๋กœ ๊ตฌ๋ถ„๋˜์ง€ ์•Š๋Š” ๋ทฐ(switch, toolbar, ...)๋Š” ํ’€ ๋„ค์ž„์„ ์‚ฌ์šฉ.
  • ์ ‘๋‘์‚ฌ๋Š” simple style(textView -> tv)
Prefix ํ’€๋„ค์ž„
layout LinearLayout, ConstraintLayout,include ...
custom CustomView
tv TextView
btn Button
img ImageView
rv RecyclerView
cb CheckBox
cg CheckGroup
switch Switch
view View
toolbar Toolbar
๊ทธ ์™ธ CamelCase ์•ž๊ธ€์ž ๋”ฐ์„œ ์ง“๊ธฐ

Drawable

์ฐธ๊ณ :ย ํ—ค์ด๋”œ๋Ÿฌ drawable ๊ฐ€์ด๋“œ

  • <WHAT>(_<WHERE>)_<DESCRIPTION>(_<SIZE>)
  • ์ด๋ฏธ์ง€๊ฐ€ ์—ฌ๋Ÿฌ๊ตฐ๋ฐ์—์„œ ํ™œ์šฉ๋  ๊ฒฝ์šฐ,ย <WHERE>๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ๊ฐ€ 1๊ฐœ๋ฐ–์— ์—†๋Š” ๊ฒฝ์šฐ,ย <SIZE>๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

What

Prefix ์„ค๋ช…
btn_ ๋ฒ„ํŠผ์œผ๋กœ ์“ฐ์ด๋Š” ์ด๋ฏธ์ง€
ic_ ์•„์ด์ฝ˜, ๋ฒกํ„ฐ์— ์‚ฌ์šฉํ•˜๋Š” ์ด๋ฏธ์ง€
bg_ ๋ฒ„ํŠผ์ด ์•„๋‹Œ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š” ์ด๋ฏธ์ง€
img_ ์‹ค์ œ์‚ฌ์ง„์ด๊ฑฐ๋‚˜ ์•„์ด์ฝ˜ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ์ผ๋Ÿฌ์ŠคํŠธํ˜•ํƒœ์˜ ์ด๋ฏธ์ง€
div_ divider๋กœ ํ™œ์šฉ๋˜๋Š” ์ด๋ฏธ์ง€
color_ color selector

Selector

  • ๋ฐฐ๊ฒฝ์ด๋‚˜ ๋ฒ„ํŠผ์—์„œ View์˜ ์ƒํƒœ์— ๋”ฐ๋ผ์„œ drawable์ด ๋ณ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ด๋ฆ„์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
์ƒํƒœ Suffix
Normal _normal
Pressed _pressed
Focused _focused
Disabled _disabled
Selected _selected
Activated _activated

Background

  • ๋ฐฐ๊ฒฝ์ƒ‰์ด pressed์ƒํƒœ์— ๋”ฐ๋ผ์„œ white -> sky_blue๋กœ ๋ณ€ํ•˜๋Š” ๊ฒฝ์šฐ๋Š”ย bg_white_to_sky_blue.xml๋กœ ํ•œ๋‹ค.
  • ๋ฐฐ๊ฒฝ์ด white์ƒ‰์˜ 24dp๋กœ ํ…Œ๋‘๋ฆฌ๋ฅผ ๊ทธ๋ฆฌ๋Š” ๊ฒฝ์šฐ๋Š”ย bg_white_radius_24dp.xml๋กœ ํ•œ๋‹ค.
  • ๋ฐฐ๊ฒฝ์ด ํˆฌ๋ช…ํ•˜๋ฉฐ ๋ฐฐ๊ฒฝ์˜ ์„ ๋งŒ์„ sky_blue์ƒ‰์˜ 8dp๋กœ ํ…Œ๋‘๋ฆฌ๋ฅผ ๊ทธ๋ฆฌ๋Š” ๊ฒฝ์šฐ๋Š”ย bg_stroke_sky_blue_radius_8dp.xml๋กœ ํ•œ๋‹ค.
  • ์˜ˆ์‹œ
    • btn_call_normal.png: ์ „ํ™”๊ฑธ๊ธฐ ๋ฒ„ํŠผ ์ด๋ฏธ์ง€
    • btn_call_pressed.png: ์ „ํ™”๊ฑธ๊ธฐ ๋ฒ„ํŠผ ๋ˆŒ๋ ธ์„๋•Œ์˜ ์ด๋ฏธ์ง€
    • btn_call.xml: ์ „ํ™”๊ฑธ๊ธฐ ๋ฒ„ํŠผ ์ด๋ฏธ์ง€์˜ selector xml
    • ic_dealer_gift.png: ๋”œ๋Ÿฌ๊ฐ€ ๋ณด๋‚ด์ค€ ๊ธฐํ”„ํ‹ฐ์ฝ˜์„ ๋ณด์—ฌ์ค„๋•Œ ํ‘œ์‹œ๋˜๋Š” ์ด๋ฏธ์ง€
    • img_splash_chart.png: ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์—์„œ ๋ณด์—ฌ์ง€๋Š” ์ฐจํŠธ ์ด๋ฏธ์ง€

๋ ˆ์ด์•„์›ƒ prefix

  • item_<what>: ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ ๋ทฐ ์•„์ดํ…œ ๋ ˆ์ด์•„์›ƒ์— ์‚ฌ์šฉ
  • view_<what>: ์ปค์Šคํ…€ ๋ทฐ ๋ ˆ์ด์•„์›ƒ์— ์‚ฌ์šฉ

๋ฆฌ์†Œ์Šค ๋„ค์ด๋ฐ

Color

<!--color ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ-->
<color name="light_gray">#E4E4E4</color>
<color name="gray">#8D8D8D</color>
<color name="gray_alpha_30">#30000000</color>

<!--์ƒ‰ ๋ณ€์ˆ˜ wHeRe_wHAt. ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด where ์ƒ๋žต ๊ฐ€๋Šฅ.-->
<color name="saveSchedule_titleText">@color/light_gray</color>
<color name="yearCalendarView_titleText">@color/gray</color>
<color name="close_background">@color/gray_alpha_30</color>

description์€ ํ…Œ๋งˆ ์†์„ฑ์œผ๋กœ ๋ถ„๋ฆฌ

<item name="titleTextColor">@color/yellow_500</item>

๋ ˆ์ด์•„์›ƒ์—์„œ ์‚ฌ์šฉ์€ ํ…Œ๋งˆ ์†์„ฑ์„ ์ฐธ์กฐ

 style="@style/Theme.titleTextColor"

Dimensions ์ปจ๋ฒค์…˜

Mnemonic ์‚ฌ์šฉ

๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ margin/padding 16dp = โ€˜์ผ๋ฐ˜ ์น˜์ˆ˜ ํฌ๊ธฐ์˜ 100% ์‚ฌ์šฉโ€™

<dimen name="small_25">2dp</dimen>
<dimen name="small_50">4dp</dimen>
<dimen name="small_100">8dp</dimen>   <!-- 50% of normal = 8dp -->

<dimen name="normal_100">16dp</dimen> <!-- 100% of normal = 16dp --> <dimen name="normal_125">20dp</dimen> <!-- 125% of normal = 16dp + 4dp = 20dp --> <dimen name="normal_150">24dp</dimen> <dimen name="normal_175">28dp</dimen>

<dimen name="large_100">32dp</dimen> <!-- large_100 = 2 x normal_100 --> <dimen name="large_125">40dp</dimen> <dimen name="large_150">48dp</dimen> <dimen name="large_175">56dp</dimen> <dimen name="large_200">64dp</dimen>

์ผ๋ฐ˜ ์น˜์ˆ˜์— ๋น„ํ•ด ํ›จ์”ฌ ํฐ dimensions์˜ ๊ฒฝ์šฐ

  • ๊ธฐ๋ณธ ํ˜•์‹ : [what]_[where]_[des]_[size] ex) keyline_all_text
<dimen name="size_selectVideo_player">500dp</dimen>

<WHAT>

Prefix Usage
width width in dp
height height in dp
size if width == height
margin margin in dp
padding padding in dp
elevation elevation in dp
keyline absolute keyline measured from view edge in dp
textsize size of text in sp

Android - Dimensions by Conventions

Style ๋„ค์ด๋ฐ

  • ์นด๋ฉœ์ผ€์ด์Šค
  • ๊ธฐ๋ณธ ํ˜•์‹:ย [des][View]ย ex) customText
<style name="selectVideoOptionImage" parent="Widget.AppCompat.ImageButton">
    <item name="android:layout_width">@dimen/large_125</item>
    <item name="android:layout_height">@dimen/large_125</item>
    <item name="elevation">@dimen/small_25</item>
    <item name="android:padding">@dimen/small_100</item>
</style>

Style resource | Android Developers

์ฝ”ํ‹€๋ฆฐ ์ปจ๋ฒค์…˜

ํด๋ž˜์Šค ๋ช…

๋‹จ์–ด์˜ ์ฒซ ๊ธ€์ž๋งŒ upper case

class Person
class User

ํ”„๋กœํผํ‹ฐ

1 ๋Œ€ 1 ๊ด€๊ณ„๋ฉด viewModel

1๋Œ€1 ๋‹ค ๊ด€๊ณ„๋ฉด ํ’€๋„ค์ž„

val viewModel: AddTaskViewModel by viewModels()
val activityViewModel: MainViewModel by viewModels()
val addTakAdapter = AddTaskAdapter()

ํ•จ์ˆ˜ ๋ช…

์ฝ”ํ‹€๋ฆฐ ๊ณต์‹ ๋ฉ”์†Œ๋“œ ๋„ค์ด๋ฐ

์ฒซ ๋‹จ์–ด๋ฅผ ์ œ์™ธํ•œ ๋‹จ์–ด๋ถ€ํ„ฐ ๋‹จ์–ด์˜ ์ฒซ ๊ธ€์ž๋งŒ upper case

๋™์‚ฌ ํ˜น์€ ๋™์‚ฌ๊ตฌ(๋™์‚ฌ๋กœ ์‹œ์ž‘)

fun getPersonId() {}
fun getUserId() {}

ํด๋ž˜์Šค ๋‚ด๋ถ€ ํ•จ์ˆ˜ ๋ฐฐ์น˜ ์ˆœ์„œ

  • ํ”„๋กœํผํ‹ฐ
  • ์ƒ์„ฑ์ž
  • init
  • onCreate
  • onCreateView
  • ํ•จ์ˆ˜
  • onDestroy
  • companion object
interface Example{
    // ๋„๊ธฐ
    fun A()
    
    fun B()
    
    fun C()
    // ๋„๊ธฐ
}

class D(
    a,
    b,
    c // 140 space ๋งž์ถฐ์„œ (Arrange Option ๋ณ€๊ฒฝํ•˜๊ธฐ)
) : B {
    // ๋„๊ธฐ
    private val _binding
    private val binding = get() = _binding
    
    private val viewModel by viewModels{}
    
    private lateinit var
    
    private val a = 3
    
    init {
        
    }
    
    override onCreate()
    
    private fun()
    
    override onDestroy()
    
    inner class C() {
        
    }
    
    companion object {
        
    }
}

ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ

//single Event
class Adapter(val onClick : (String) -> Unit)

//Multiple Event
class Adapter(val onClick : MinSeokOnClickListener)

fun interface MinSeokOnCLickListener {
    
    fun onClick(str : String)
    
    fun onLongClick(str : String)
    
}

val onclickListener = object: MinSeokOnCLickListener {
    fun onClick(str : String) {
    
    }
    
    fun onLongClick(str : String) {
    
    }
}

Adapter(onclickListener)

Adapter(::onClick) // 3์ค„ ์ด์ƒ ๋ถ„๋ฆฌ
Adapter {
    Log.d("asd", it)
} // 2์ค„ ์ด๋‚ด ์‚ฌ์šฉ

Enum

[What]Type

Sealed

NetworkState(= retrofit Result) MultipleViewType

scope ํ•จ์ˆ˜

apply, also, with, let, run

  • Scope ์ค‘์ฒฉ ์ง€์–‘(์ตœ๋Œ€ 2์ค‘์ฒฉ)
  • it ์ง€์–‘ (๋‹ค๋ฅธ ์ด๋ฆ„์œผ๋กœ ์„ ์–ธํ•ด์„œ ์“ฐ๊ธฐ)

ํ•จ์ˆ˜๋ช… prefix

๋น„๋™๊ธฐ ํ•จ์ˆ˜

  • fetch: Read
  • post : Write view(viewModel.fetchData) -> viewModel(repo.fetchData) -> repo(source.fetchData)

์ถ”๊ฐ€

  • add: list ์•ˆ์— ๋„ฃ์„ ๋•Œ
  • create: ์ƒˆ๋กœ ์ƒ์„ฑ

์กฐํšŒ

  • get: any
  • find: nullable any
  • is, has: boolean

ํ™”๋ฉด์ „ํ™˜

  • show[Dialog]
  • start[Activity]
  • navigate[Fragment]

ํ™”๋ฉด ๊ฐฑ์‹ 

  • show
  • invalidate

if๋ฌธ

else if ์‚ฌ์šฉ ๊ธˆ์ง€ -> when์œผ๋กœ ๋ณ€ํ™˜ else๋„ ์ง€์–‘ ๊ณ ๋ ค ์ค‘๊ด„ํ˜ธ ๋ฌด์กฐ๊ฑด ์“ฐ๊ธฐ

// ์ค‘๊ด„ํ˜ธ ํ™•์‹คํžˆ ์‚ฌ์šฉํ•˜๊ธฐ
if (true) {
    foo()
} else {
    bar()
}

// else ์ง€์–‘ 
โฌ‡๏ธ
bar()
if (true) {
    foo()
}

when๋ฌธ

// ์ž๋™ ์ •๋ ฌ ์‚ฌ์šฉํ•˜๊ธฐ
when {
    aaa -> {
        
    }
    
    bbb -> {
        
    }
}

// 2์ค„ ์ด์ƒ์€ ์ค‘๊ด„ํ˜ธ ๋‚ด์—์„œ, 1์ค„์€ ์ค‘๊ด„ํ˜ธ x
when {
    aaa -> foo()
    bbb -> bar()
}

// early return
// else ๋ฌธ์„ ๋ฏธ๋ฆฌ when ์œ„์— ๋นผ์„œ return ์‹œํ‚ค๊ธฐ (else block์—์„œ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ด ์—†์„ ๋•Œ)
val xxx = ... ?: return
when(target) {
		aaa -> {}
		bbb -> {}
}

navigate

ShoppingFragment -> ShoppingDetailFragment 
// 1. ShoppingFragment with Safe Args
override fun navigateToShoppingDetail(shoppingItemInfo: ShoppingItemInfo) {
        val navAction = ShoppingFragmentDirections.actionShoppingFragmentToDetailFragment(shoppingItemInfo)
        findNavController().navigate(navAction)
    }

// 2 ShoppingDetailFragment 
class ShoppingDetailFragment : Fragment(), ShoppingItemOnClickListener {
    private val args: ShoppingDetailFragmentArgs by navArgs()
    private val shoppingItemInfo : ShoppingItemInfo by lazy { args.shoppingItemInfo }

override fun onCreateView(...){...}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
     super.onViewCreated(view, savedInstanceState)
	   Log.d("shoppingItemInfo",shoppingItemInfo.toString()) // ์‚ฌ์šฉ
    }

์ƒ์ˆ˜

resource -> ํ™”๋ฉด์— ๋ณด์ด๋Š”๊ฐ€๋ฅผ ๊ธฐ์ค€์œผ๋กœ string.xml์— ๋ถ„๋ฆฌ ๊ฒฐ์ •

  • ex: EXTRA_TITLE_ID = "title_id" ์ƒ์ˆ˜ ๋„ค์ด๋ฐ์€ upper snake case

์˜๋ฏธ ์žˆ๋Š” ์ˆซ์ž, ๋ฌธ์ž์—ด์€ companion์— const val ์„ ์–ธ

  • ex: LOOP_COUNT = 10

๋„คํŠธ์›Œํฌ response ๊ฐ์ฒด Entity ๋งคํ•‘ ๋ฐฉ์‹

  • fromย โญ

ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ๋„ค์ด๋ฐ

  • ํ•œ๊ตญ์–ด, snake case
instrument ok
fun `์ผ์ •์„_์ž˜๋ชป_๊ฐ€์ ธ์˜ฌ_๋•Œ`()

Git ์ปจ๋ฒค์…˜

Feature ๋ธŒ๋žœ์น˜ ๋„ค์ด๋ฐ

Issue #<number> type: subject

body(option)

footer(option)

Type

  • feat:ย ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ
  • fix:ย ๋ฒ„๊ทธ ์ˆ˜์ •
  • docs:ย README, gitignore ์ฃผ์„ ์ˆ˜์ •
  • refactor:ย ์ฝ”๋“œ ๋ฆฌํŒฉํ„ฐ๋ง
  • test:ย ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ๋ฆฌํŒฉํ„ฐ๋ง ์‹œ ์‚ฌ์šฉํ•˜๋ฉฐ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • chore:ย ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์„ค์ • ๋ณ€๊ฒฝ, ๋นŒ๋“œ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ ๋“ฑ์— ์‚ฌ์šฉ๋˜๋ฉฐ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • res

โ†’ ์†Œ๋ฌธ์ž:

Subject

  • 50์ž ์ด๋‚ด
  • ๊ตฌ์–ด์ฒด/๋ฌธ์žฅํ˜• X, ๋ช…๋ นํ˜•์œผ๋กœ ์ž‘์„ฑ
  • ๋งˆ์นจํ‘œ ์‚ฌ์šฉ ๋ถˆ๊ฐ€

Body(Option)

  • ์ƒ๋žต ๊ฐ€๋Šฅ
  • 72์ž ์ด๋‚ด
  • ์–ด๋–ค(What) ์ž‘์—…์ธ์ง€, ์ž‘์—…์˜ ๋ชฉ์ (Why)์— ๋Œ€ํ•ด ์ž‘์„ฑ. ์ž‘์—…์„ ํ•ด๊ฒฐํ•œ ๋ฐฉ์‹(How)์€ ์ž‘์„ฑ X

Footer(Option)

Push/PR Issue ์—ฐ๊ฒฐ

  • Issue Tracker ID ํ‘œ์‹œ
  • Issue Tracker ์œ 
    • Fixes: ์ด์Šˆ ์ˆ˜์ •์ค‘ (์•„์ง ํ•ด๊ฒฐ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)
    • Resolves: ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ–ˆ์„ ๋•Œ ์‚ฌ์šฉ
    • Ref: ์ฐธ๊ณ ํ•  ์ด์Šˆ๊ฐ€ ์žˆ์„ ๋•Œ ์‚ฌ์šฉ
    • Related to: ํ•ด๋‹น ์ปค๋ฐ‹์— ๊ด€๋ จ๋œ ์ด์Šˆ๋ฒˆํ˜ธ (์•„์ง ํ•ด๊ฒฐ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)

Issue & PR ๊ณตํ†ต ์‚ฌํ•ญ

๋ผ๋ฒจ ๋‹ฌ๊ธฐ(chore, bug, fix, feature, docs, help wanted, wrong, question)
- project๋‹ฌ๊ธฐ
- Milestone ๋‹ฌ๊ธฐ
- asignees ์ง€์ •

PR ํ…œํ”Œ๋ฆฟ

# PR ๋‚ด์šฉ

...์ž‘์—… ๋‚ด์šฉ...

Issue ํ…œํ”Œ๋ฆฟ

# ์ง„ํ–‰ ์ƒํ™ฉ

...์ฒดํฌํฌ์ธํŠธ...

์ฐธ๊ณ  url