전체 글
return (code, data) 함께 반환하기
return (code, data) 함께 반환하기
2023.10.07때때로 method 내에서 정상 로직 진행에 실패한 경우에도 data를 상위 메서드에 전달해야 하는 경우가 있다. (e.g., 추가인증필요, 기처리) 기본적으로 throw Exception을 return 처럼 data 반환 용도로 사용하는 것은 불가능 하기 때문에, return 기반으로 접근해야 한다. 직접 return 타입 정의해 사용하기 data class FooResult( val code: Code, val field1OnlyIfSuccess, val field2OnlyIfSuccess, val field3OnlyIfFailure } { enum Code { SUCCESS, FAILURE } } Result 타입 R 타입에 code 없고 성공+실패 data field만 존재하는 경우 유용. 보편적..
caller는 callee를 믿지 않는 것이 좋다 (어차피 catch 해야 한다)
caller는 callee를 믿지 않는 것이 좋다 (어차피 catch 해야 한다)
2023.10.07중요한 처리로직 인 경우, 어차피 caller는 callee를 믿어서는 안된다. 여기서 callee는 다른 class 혹은 다른 class의 메서드를 의미한다. 같은 class 내 private method를 호출하는 경우라면, 자기 자신이 직접 정의한 기능이므로 믿을 수 있으나, class 바깥의 다른 class와 메시지를 주고 받는 상황이라면 신뢰하지 않는 것을 기본 전제로 깔고가야 한다. 예시 ) 금액 소진 메서드를 제공하는 callee가 Exception을 반환하지 않겠다고 docstring에 명시해두었다면 믿을 것인가? 금액 소진 기능인데, callee의 docstring과 현재 구현된 메서드 내부만 믿고 caller는 catch 안할 것인가? 그럴리가 없다는 것이다. caller 입장에서 ca..
throw Exception을 return 처럼 data 반환 용도로 사용하는 것은 불가능하다
throw Exception을 return 처럼 data 반환 용도로 사용하는 것은 불가능하다
2023.10.07return 대신 throw Exception 하면서 유용한 객체를 함께 반환하는 것은 불가능하다. (가능은 하지만 타입 정보가 사라져서 정적 타입 언어를 제대로 사용하는 방법이 아니다.) return Type 개수 만큼 Exception class를 정의 할 수는 없으니 generic을 이용해 CommonException 같이 정의하고 data: T에 데이터 담아서 던지면 되는거 아닌가 생각이 들 수 있는데 runtime에는 T가 사라지기 때문에 type-safe한 catching이 불가능하다. ( link ) 애초에 subclass of 'throwable' may not have type parameters 로 컴파일타임 에러가 발생하기 때문에 CommonException을 Generic으로 만들 ..
afterStep 에서 Exception을 던져도 다음 Step이 이어서 실행된다.
afterStep 에서 Exception을 던져도 다음 Step이 이어서 실행된다.
2023.09.19afterStep에서 검증 로직 돌린 후, 다음 Step 실행하지 않고 배치를 종료하고 싶은 경우가 있다. 배치 애플리케이션을 아예 종료해버리는 방법도 있지만, 보다 graceful 하게 처리하고 싶은 경우, 다음 Step이 실행되지 않도록 하려면? 종료 상태를 나타내는 Status는 BatchStatus와 ExitStatus 두개가 있다. https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#batchStatusVsExitStatus ExitStatus represents the status of a Step after it finishes execution. on(ExitStatus...) 로 Step의 종료..
인덱스 관련 총정리
인덱스 관련 총정리
2023.08.15인덱스 관련 이론 6장. 물리적 데이터베이스 설계 : 인덱스 관련 https://dataonair.or.kr/인덱스 기본 원리 https://d2.naver.com/helloworld/1155 https://docs.oracle.com/cd/E11882_01/server.112/e40540/indexiot.htm#CNCPT721 커버링 인덱스 적용하기 https://jojoldu.tistory.com/476 https://docs.oracle.com/javadb/10.8.3.0/tuning/ctunoptimz30768.html 커버링 인덱스는 SELECT의 모든 컬럼이 인덱스에 들어있어야 적용된다. 허나 그렇지 않다고 하더라도, Data Filter 보다 Key Filter를 적용하는게 성능에 큰 도움이..
[Kotlin] as와 타입 캐스팅. 런타임 에러. 타입 파라미터 소거(erasure)
[Kotlin] as와 타입 캐스팅. 런타임 에러. 타입 파라미터 소거(erasure)
2023.08.13@Test fun typeCastTest() { val stringMap = mapOf( "a" to "0", "b" to "10.01" ) val bigDecimalMap = stringMap as Map println(bigDecimalMap) /* 문제 없이 실행된다. */ bigDecimalMap.forEach { val bigDecimal: BigDecimal = it.value println(bigDecimal) /* 컴파일은 잘 되지만.. */ /* 런타임에 class java.lang.String cannot be cast to class java.math.BigDecimal 에러 발생한다 */ } } 즉, bigDecimal는 BigDecimal 타입이고 it.value는 String 타..
Spring JDBC와 JdbcOperations
Spring JDBC와 JdbcOperations
2023.08.10Spring Data JDBC를 사용할 때, CrudRepository와 자동생성 쿼리 만으로는 커버가 되지 않는 경우가 반드시 생기고, 이 경우 @Query 보다는 JdbcOperations를 쓰는 것이 낫다. (see [Spring Data JDBC] docs) 따라서 CrudRepository를 아래와 같이 Dao로 확장해서 관리하는 것이 좋다. interface MerchantInfoRepository : NfcJdbcRepository @Repository class MerchantInfoDao( private val merchantInfoRepository: MerchantInfoRepository, private val jdbcOperations: NamedParameterJdbcOperat..
전문 해석기 배치 - File Line to Domain Model 변환
전문 해석기 배치 - File Line to Domain Model 변환
2023.07.29전문 해석 시 고려해야 하는 것들은, align, padding, trim, 날짜 포맷, 숫자 포맷 변환 등이다. 문자 타입은 끝문자 trim 정도만 처리하면 제대로 매핑되지만, 날짜, 숫자 포맷은 전문 송신처에 따라 포맷이 각각 달라 디테일한 처리가 필요하다. - e.g., 0.8%을 어디서는 00080000 으로 보내고, 어디서는 00.80으로 보냄. - padding도 어디서는 (0, LEFT)로, 어디서는 (' ', RIGHT) RIGHT로 할 수 있음 - 날짜를 어디서는 yyyyMMdd를 사용하고, 어디서는 yyMMdd 사용함. 따라서 전문 해석 케이스를 정리해보면, 크게 2가지 클래스가 필요하다. class A ⇒ fieldSet에서 꺼내서 type 변환하고, align에 따라 padding ..
전문 해석기 배치 LineMapper - TelegramFieldSetMapper
전문 해석기 배치 LineMapper - TelegramFieldSetMapper
2023.07.26RecordFieldSetMapper로 모든 케이스의 전문 변환이 커버 가능할까? => 아니다. public interface ConversionService { override fun convert(source: Any?, sourceType: TypeDescriptor?, targetType: TypeDescriptor): Any? } // 위 메서드는 아래 호출 구문을 통해서 넘어오는데... public class RecordFieldSetMapper implements FieldSetMapper { public T mapFieldSet(FieldSet fieldSet) { args[i] = this.typeConverter.convertIfNecessary(fieldSet.readRawString..
Enum VS String : 외부 API 요청에 대한 응답 수신 코드로 enum을 쓰는게 좋을까?
Enum VS String : 외부 API 요청에 대한 응답 수신 코드로 enum을 쓰는게 좋을까?
2023.07.13상황 1) 외부 API 요청에 대한 응답 수신 코드로 enum을 쓰는게 좋을까? 요약 ) 외부 API 요청에 대한 응답 코드나, 내 API에 대한 요청 코드의 타입은 enum으로 정의하는 것 보다 String으로 정의하고 enum 변환하는게 더 유연하다. (fault tolerance) enum에 정의 되어 있지 않은 값이 응답 코드로 들어올 수 있기 때문에 이에 대한 처리를 생각해 주어야 한다. (e.g., 예고 없이 갑자기 추가된 응답 코드) Exception 발생 해도 상관 없는 경우) 기본적으로 Exception 발생하게 되어 있다. 기본 Exception 메시지에서 @JsonValue 기준 값이 로깅된다. Caused by: com.fasterxml.jackson.databind.exc.Inva..
전문 해석기 배치 LineMapper - BeanWrapperFieldSetMapper와 RecordFieldSetMapper의 차이
전문 해석기 배치 LineMapper - BeanWrapperFieldSetMapper와 RecordFieldSetMapper의 차이
2023.06.29LineMapper는 크게 Tokenizer와 FieldSetMapper로 이루어진다. 전문 특성상 LineMapper로는 PatternMatchingCompositeLineMapper를 Tokeinizer로는 FixedLengthTokenizer를 사용하면 되는데 FieldSetMapper로는 세 가지 선택지가 있다. 1. BeanWrapperFieldSetMapper 2. RecordFieldSetMapper 3. 직접 구현 이 중 SpringBoot에서 기본 제공하는 1, 2에 대해 비교해보았다. class SampleModel() { var field1: String? = null var field2: Int? = null var field3: Double? = null var field4: Bi..
전문 해석기 배치 LineMapper - PatternMatchingCompositeLineMapper
전문 해석기 배치 LineMapper - PatternMatchingCompositeLineMapper
2023.06.22전문은 line의 맨 처음 시작 문자 (H, D, T 등)에 따라서 라인의 포맷, 필드가 달라진다. 배치에서 파일을 읽어와 맨 처음 시작 문자를 보고, 적절하게 분기해서 lineMapping 해야 하는 상황이었다. 기존 코드에서는 FlatFileItemReader를 상속한 TelegramFileItemReader가 있고, 여기서 LineMapper들을 가지고 있으면서, 분기처리해서 적절한 lineMapper를 불러주는 방식으로 처리하고 있었다. 헌데 내 생각에는 FlatFileItemReader는 resource에서 data를 읽어오는 책임이지, 읽어온 line 내부에 대해서는 관여하지 않는게 좋아보였다. 말 그대로 FileItemReader니까, FileItemRead만 제대로 하면 OK인 것이고, 상..