브랜치를 합치는 방법에는 크게 merge와 rebase가 있습니다. 두 방법의 차이는 크게 커밋 히스토리가 달라집니다. merge 커밋 순서를 바꾸지 않습니다. 존재하는 브랜치가 변경되지 않습니다. 새로운 merge commit이 생깁니다. 변경 내용의 이력이 모두 그대로 남아 있기 때문에 이력이 복잡해집니다. rebase 커밋 메시지가 시간 순서대로 합쳐집니다. 히스토리가 좀 더 깔끔해집니다. 원래의 커밋 이력이 변경되기 때문에 정확한 이력을 남겨야 할 필요가 있을 경우 사용하면 안됩니다. rebase는 base를 새롭게 설정한다는 의미이고, 커밋 메시지가 좀 더 깔끔해지는 특징이 있습니다. rebase명령어를 통해 커밋 히스토리를 깔금하게 브랜치를 병합할 수 있습니다. user@AL01724100 G..
커밋하지 않은 변경 내용이나 새롭게 추가된 파일들이 작업 트리에 남아있는 채로 다른 브랜치로 전환(checkout)하면, 그 변경 내용은 기존 브랜치가 아닌 전환된 브랜치로 옮겨가게 됩니다. 만약 코드를 열심히 수정하다가 갑자기 핫픽스 요청이 들어오는 경우 완성되지 않은 내용을 커밋하기에는 찝찝하고, 변경사항 전체를 하드 리셋하거나, 새로운 저장소를 만들어서 작업하는 등 명쾌한 해답은 없었습니다. git add . git commit -m "Hotfix 작업을 위한 임시 저장(작업중)" 이런 상황에서 git stash 명령어로 변경사항을 임시 저장했다가, 나중에 다시 이어서 작업할 수 있습니다. user@AL01724100 Git-Study % ls aabbcc aa, bb, cc 파일이 있을 때 cc ..
의미 있는 이름 소프트웨어에서 이름은 어디나 쓰입니다. 변수, 함수, 인수, 클래스 심지어 디렉터리, jar, war, ear 등 다양한 곳에 쓰입니다. 이렇듯 많이 사용하므로 이름을 잘 지으면 여러모로 편합니다. 의도를 분명히 밝혀라 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많습니다. 그러므로 이름을 주의깊게 살펴 더 나은 이름이 떠오르면 개선해야합니다. int d; // 경과 시간 int elapsedTimeInDays; int daysSinceCreation; int daysSinceModification; int fileAgeInDays; 이름 d는 아무 의미도 없고 이를 설명하기 위한 주석이 필요합니다. 하지만 변수 명을 좀 더 자세하게 지으면 의미도 명확하고..
코드가 존재하라 코드는 요구사항을 상세하게 표현하는 언어이다. 코드의 도움 없이는 요구사항을 상세하게 표현할 수 없고, 추상화 할 수 없습니다. 기계가 실행할 수 있도록 상세하게 요구사항을 명시하는 작업이 프로그래밍이고, 그 결과가 바로 코드입니다. 나쁜 코드, 르블랑 법칙 80년대 킬러 앱을 구현한 회사가 있었습니다. 제품은 인기를 끌었지만 점차 버그가 많아지며 화가나서 프로그램을 사용하지 더이상 사용하지 않았고 결국 회사가 망했습니다. 프로그래머라면 누구나 나쁜 코드를 경험합니다. 그렇다면 어째서 나쁜 코드를 경험하고 나쁜 코드를 짰을까? 급해서? 서두르느라? 제대로 짤 시간이 없다고 생각해서 코드를 다듬느라 시간을 보냈다가 상사한테 욕 먹을까봐 지겨워서 빨리 끝내려고 다른 업무가 너무 밀려 후딱 해..
Coroutine 동기화 문제 아래의 코드는 100개의 Coroutine을 만들고 각 Coroutine은 coutner를 1씩 증가하는 작업을 1000번 작업한다. 하지만 결과를 확인하면 우리의 예상대로 나오지 않는다. 그 이유는 Coroutine의 Dispatcher는 내부적으로 Thread Pool을 통해 Multi Thread 환경에서 작동한다. 즉 동기화 작업을 처리하지 않았기 때문에 오류가 발행한다. Dispatchers.Default는 JVM에 설정된 만큼 Thread Pool을 갖습니다. 보통 CPU 수와 같으며 최소 2개를 갖습니다. import kotlinx.coroutines.* import kotlin.system.measureTimeMillis suspend fun massiveRu..
Supervision Coroutine에서 Exception이 발생한 경우 Exception이 전파되면서 다른 자식들의 Coroutine을 취소시키고, 부모까지 취소시킨다. 하지만 여러 Coroutine에서 API를 호출하여 UI를 업데이트 하는 작업을 생각해보자. 하나의 API가 실패한 경우 모든 Coroutine이 취소되면서 다른 작업까지 영향을 미친다. 이러한 문제점을 해결하기 위한 방법이 Supervision이다. SupervisionJob 일반적인 Job과 비슷하지만 Exception이 아래 방향으로만 전달된다. 즉 Exception이 발생했을 때 다른 자식들이나 부모의 Coroutine을 취소하지 않고 자신과 자신의 자식들의 Coroutine만 취소한다. SupervisionJob은 매개변수로..
Exception Coroutine에서 기본적으로 Exception 처리 방식은 전달(Propagation)과 노출(Expose)가 있습니다. launch나 actor같은 빌더는 예외가 부모 Coroutine으로 전달되고, async나 produce같은 빌더는 결과 값을 사용할 때 Exception이 노출됩니다. import kotlinx.coroutines.* @OptIn(DelicateCoroutinesApi::class) fun main() = runBlocking { val job = GlobalScope.launch { // root coroutine with launch println("Throwing exception from launch") throw IndexOutOfBoundsExcep..
Job Lifecycle Job의 상태는 기본적으로 New, Active, Completing, Cancelling, Cancelled, Completed 총 6개의 상태를 가집니다. State isActive isCompleted isCancelled New false false false Active true false flase Completing true false false Cancelling false false true Cancelled false true true Completed false true false New : Coroutine을 생성할 때 start를 Lazy로 설정한 경우 New로 시작합니다. start(), join() 등의 함수로 시작할 수 있습니다. Active : 기본..
- Total
- Today
- Yesterday
- 코루틴
- 클린 코드
- rxjava
- null
- gradle
- 연산자
- Flutter
- Kotlin
- ViewModelProvider
- TDD
- 함수
- ConcatAdapter.Config
- viewmodel
- clean code
- DSL
- isActive
- ViewModelStoreOwner
- Exception
- observable
- Coroutine
- Widget
- 보이스카우트 규칙
- commit
- Android
- git
- Flowable
- DART
- ConcatAdapter
- CancellationException
- 클린코드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |