SlideShare a Scribd company logo
Scala, Spring-Boot, JPA의 불편하면서도
즐거운 동거
Scala, Spring-Boot, JPA가 동거를 시작한 이유는?
JPA가 동거에 기여하는 점
Spring-Boot가 동거에 기여하는 점
Scala가 동거에 기여하는 점
Scala, Spring-Boot, JPA 동거할 때 고려할 사항
Scala, Spring-Boot, JPA가 동거를
시작한 이유는?
JPA
• 단순, 반복적인 CRUD 작업하기 싫다.
• 스키마 변경에 따른 비용을 최소화하고 싶다.
• 핵심 비즈니스 로직에 집중하고 싶다.
Spring Boot
• 단순, 반복적인 Spring 설정 작업하기 싫다.
• 핵심 비즈니스 로직에 집중하고 싶다.
Scala
• 10년 이상 Java만 했더니 재미없더라.
• 2년 정도 함수형 언어로 Scheme, Clojure 도전했다가 중도 포기
• 어딘가 직접적으로 활용하고 있지 않으면 동기부여가 잘 되지 않는
성격
• 단순, 반복적인 작업 제거
• 핵심 비즈니스 로직에 집중
• Java에 싫증이나 Scala를 선택
• 단순, 반복적인 작업 제거
• 핵심 비즈니스 로직에 집중
• Java에 싫증이나 Scala를 선택
Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
Play가 아닌 Scala + Spring + JPA 조합을 선택한
이유
• Spring과 JPA 경험을 버리는 것의 아쉬움.
• 중도 포기하지 않으려면 변화를 Scala 하나로 한정.
• 변화를 싫어하는 다른 Java 개발자를 설득하기 위해 최소한의 변화.
JPA가 동거에 기여하는 점
JPA
• 단순, 반복적인 CRUD 작업하기 싫다.
• 스키마 변경에 따른 비용을 최소화하고 싶다.
• 핵심 비즈니스 로직에 집중하고 싶다.
JPA 도입에 따른 더 큰 효과
요구사항이 자주 변경되는 프로젝트 초반, 빠른 사이클로 설계에
대해 다양한 실험이 가능하다.
JPA를 사용하지 않는 경우 – 테이블 최초 생성시
데이터베이스에 스키마 적용
비즈니스 로직 구현 테이블 설계
테이블 스키마 생성SQL 쿼리 구현
자바 테이블과 매핑되는 객체 추
가
1
2
34
5
6
JPA를 사용하지 않는 경우 – 테이블 스키마 변경시
데이터베이스에 스키마 적용
비즈니스 로직 변경(선택)
테이블 설계
테이블 스키마 변경
칼럼 변경에 따른 SQL
쿼리 수정
자바 객체에 필드 변경
비즈니스 로직 구현 객체 설계
JPA를 사용하는 경우 – 객체(Entity) 최초 생성시
객체 추가 및 매핑
데이터베이스에 스
키마 적용
비즈니스 로직 구현 테이블 설계
테이블 스키마 생성SQL 쿼리 구
현
자바 테이블과 매핑되
는 객체 추가
1
2
3
비즈니스 로직 구현(선
택)
객체 설계
JPA를 사용하는 경우 – 객체(Entity) 필드 변경
객체 필드 변경
데이터베이스에 스키마
적용
비즈니스 로직 변경(선택)
테이블 설계
테이블 스키마 변경칼럼 변경에 따른
SQL 쿼리 수정
자바 객체에 필드 변경
JPA 도입 효과
• 요구사항이 자주 변경되는 프로젝트 초반 빠른 구현 – 피드백 사이
클
• 빠른 피드백 사이클은 삽질할 수 있는 시간을 확보함으로써 빠른 지식
축적이 가능하다.
• 지식 축적은 도메인에 최적화된 설계를 할 수 있도록 한다.
• 좋은 설계는 사용자의 요구사항 변화에 빠르게 대응할 수 있다.
• 개발자는 소스 코드에 대한 자부심과 여유 시간을 확보할 수 있다.
더 자세히 알고 싶다면…
ORM 프레임워크를 활용할 때의 설계, 개발 프로세스
Spring-Boot가 동거에 기여하는 점
Spring Boot
• 단순, 반복적인 Spring 설정 작업하기 싫다.
• 핵심 비즈니스 로직에 집중하고 싶다.
1. @IntegrationTest
• Spring Boot는 Embedded Tomcat 기반으로 동작.
• @IntegrationTest 기반으로 테스트하면 Embedded Tomcat을 자동
실행한 후 Client 테스트가 가능.
• 특히 RestTemplate을 활용해 API 테스트할 때 유용.
지금까지 통합 테스트 방법
WAS 시작
통합 테스트 실행
@IntegrationTest 기반 API 테스트 방법
Only 통합 테스트 실행
= WAS 시작 + 통합 테스트 실행
@SpringApplicationConfiguration(classes = Array(classOf[MyWebConfig]))
@WebAppConfiguration
@IntegrationTest(Array("server.port:0"))
abstract class ServerIntegrationTest {
@Value("${local.server.port}")
var port: Int = _ // 사용하지 않는 임의의 port가 할당됨
val baseUrl = "http://localhost:" + port
}
@RunWith(classOf[SpringJUnit4ClassRunner])
class UserControllerTest extends ServerIntegrationTest {
val restTemplate: RestTemplate = new RestTemplate()
@Test
def canCreateUser() {
val result = restTemplate.postForEntity(
baseUrl + "/users",
postParameter(List(
"email" -> "test@gmail.com",
"password" -> "password"
)),
classOf[String])
assert(result.getStatusCode == HttpStatus.OK)
}
}
2. Spring Boot Actuator
• 서비스 운영시 모니터링 요소에 대한 기본 정보 제공
제공하는 정보
• Spring 관련 정보
• /autoconfig – Spring auto configuration 정보
• /beans - Spring Bean 목록
• /configprops - @ConfigurationProperties 정보
• /mappings - @RequestMapping 정보
• 시스템 운영 및 성능
• /dump – thread dump
• /health – 애플리케이션의 정상 동작 유무
• /metrics – 애플리케이션의 메모리 상태, heap, thread 등과 관련한 정보 제공
• http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-
ready 에서 추가 정보 확인
Application Detail
출처 : https://github.com/codecentric/spring-boot-admin
Thread 상태
출처 : https://github.com/codecentric/spring-boot-admin
Actuator Remote Shell
출처 : http://nomimic.tistory.com/5
빠르게 최소한의 모니터링 및 운영 환경을 구축할 수 있다.
Scala가 동거에 기여하는 점
Spring Boot + JPA 환경 조합만으로 충분히 생산성 높다.
Scala
• 10년 이상 Java만 했더니 재미없더라.
• 2년 정도 함수형 언어로 Scheme, Clojure 도전했다가 중도 포기
• 어딘가 직접적으로 활용하고 있지 않으면 동기부여가 잘 되지 않는
성격
1. Domain과 DTO의 명확한 분리에 대한 거부감이
줄어듦
• 현재 개발 추세는 Domain 객체와 DTO에 중복되는 부분이 많아 자바
객체 하나가 Domain 역할, DTO 역할을 하는 방식으로 구현.
• Scala를 활용하면 각 역할별로 구현하는 것에 대한 거부감이 줄어듦
@Entity
class User(pEmail: String, pNickName: String, pPassword: String) extends
DomainModel {
@Id
@GeneratedValue
var id: Long = _
@Column(unique = true, nullable = false)
val email = pEmail
@Column(name = "nick_name", nullable = false)
val nickName = pNickName
@Column(nullable = false)
val password = pPassword
def isGuest(): Boolean = {
false
}
}
User Entity
• 반드시 setter/getter를 생성하지 않아도 된다.
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
@JsonInclude(Include.NON_NULL)
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility =
Visibility.NONE, setterVisibility = Visibility.NONE)
trait View
case class UserView(id: Long, email: String, nickName: String) extends
View {
def this(u: User) = this(u.id, u.email, u.nickName)
def this() = this(new User())
}
User View DTO
• Scala case class를 활용하면 자동으로 field 추가함.
class UserForm {
@BeanProperty
@Email
var email: String = _
@BeanProperty
@NotNull
@Size(min = 3, max = 10)
var nickName: String = _
@BeanProperty
@NotNull
@Size(min = 8, max = 15)
var password: String = _
def toUser() = new User(email, nickName,
password)
}
User Form DTO
• @BeanProperty 활용하면 setter/getter method 자동
추가
Domain과 DTO의 명확한 분리에 대한 거부감이
줄어듦
• 분리하는 것이 항상 좋은 것은 아니다.
• 상황에 따라 Entity와 DTO를 분리/통합할 것인지에 대한
역량을 키우는 것이 더 중요하다.
2. Test Fixture(Test Data) 생성하기 용이함.
• 자바에서 Test Fixture를 생성하고 변경하기 어려움은 Test 코드를
만드는데 약간의 장애물이다.
• Scala는 named parameter를 통해 해결 가능
email, nickname, password를 가지는 User 객체에 대한 테스트를 데이터를
만든다면…
public class UserBuilder {
private String email;
private String nickname;
private String password;
public UserBuilder withEmail(String email) {
this.email = email;
return this;
}
public UserBuilder withNickname(String nickname) {
this.nickname = nickname;
return this;
}
public UserBuilder withPassword(String password) {
this.password = password;
return this;
}
public User build() {
return new User(email, nickname, password);
}
}
public class UserTest {
@Test
public void canCreate() throws Exception {
User user1 = new UserBuilder().withEmail("some@sample.com").build();
User user2 = new
UserBuilder().withEmail("some@sample.com").withNickname("newname").build();
}
}
22장. 복잡한 테스트 데이터 만들기 참고
trait Fixture {
def aSomeUser(email: String = "some@sample.com", nickname: String = "nickName", password:
String = "password")
= new User(email, nickname, password)
}
val user1 = aSomeUser
val user2 = aSomeUser(email="some2@sample.com")
val user1 = aSomeUser(nickName="newname")
3. implicit을 활용한 중복 제거
• 애플리케이션을 구현하다보면 반복적으로 전달하는 인자가 존재함.
• Scala의 implicit을 활용해 제거 가능
class ClanService @Autowired() (val clanRepository: ClanRepository,
val channelService: ChannelService) {
def findClan(id: Long)(implicit user: User) = {
[...]
}
def create(name: String)(implicit user: User) = {
[...]
}
}
class ClanService @Autowired() (val clanRepository: ClanRepository,
val channelService: ChannelService) {
def findClan(id: Long)(implicit user: User) = {
[...]
}
def create(name: String)(implicit user: User) = {
[...]
}
}
class ClanController @Autowired() (val clanService: ClanService) extends BaseController {
@RequestMapping(value = Array(""), method = Array(RequestMethod.POST))
def create(name: String) = {
val savedClan = clanService.create(name)
new ClanDetailView(savedClan, currentUser)
}
@RequestMapping(value = Array("/{id}"), method = Array(RequestMethod.GET))
def clanUsers(@PathVariable id: Long) = {
val clan = clanService.findClan(id)
new ClanDetailView(clan, currentUser)
}
}
object CurrentUserDetails {
implicit def cud: CurrentUserDetails = {
currentUserDetails(SecurityContextHolder.getContext().getAuthentication().getPrincipal())
}
implicit def currentUser: User = {
cud.getUser
}
}
import support.security.CurrentUserDetails._
class ClanController @Autowired() (val clanService: ClanService) extends BaseController {
@RequestMapping(value = Array(""), method = Array(RequestMethod.POST))
def create(name: String) = {
val savedClan = clanService.create(name)
new ClanDetailView(savedClan, currentUser)
}
@RequestMapping(value = Array("/{id}"), method = Array(RequestMethod.GET))
def clanUsers(@PathVariable id: Long) = {
val clan = clanService.findClan(id)
new ClanDetailView(clan, currentUser)
}
}
• Case Class
• Named Parameter
• implicit
• Pattern Match
• Some/Option
• Lambda(람다)
• 막강 Collection
• 모나드 등등 …
• Functional Programming
• Case Class
• Named Parameter
• implicit
Java에서 Scala 적용 단계
Scala를 적용 단계
• 1단계 : Scala를 자바처럼 구현한다.
• 2단계 : 점차 Scala 문법에 친숙해지면 Scala 기능을 하나씩
적용한다.
• 3단계 : 함수형 프로그래밍 스타일로 구현한다.
• 4단계 : play 프레임워크로 갈아탄다.
Scala, Spring-Boot, JPA 동거할 때
고려할 부분
Scala, Spring, JPA 동거시 불편한 부분
• Java 기반 프레임워크 사용하면서 고려할 부분이 생긴다.
• Scala의 모든 기능을 극한으로 사용하는데 제약 사항이 있다.
@RestController
class UserController @Autowired() (val userRepository: UserRepository) {
val Log = LoggerFactory.getLogger(classOf[UserController])
@RequestMapping(value = Array("/users"), method = Array(RequestMethod.POST) )
def join(@Valid @RequestBody userForm: UserForm, result: BindingResult) = {
...
}
@RequestMapping(value = Array("/users/{userEmail}"), method =
Array(RequestMethod.POST) )
def login(@PathVariable userEmail: String, @RequestParam(required = true)
password:String) = {
...
}
}
import java.lang.Long
import org.springframework.data.repository.CrudRepository
trait UserRepository extends CrudRepository[User, Long] {
def findByEmail(email: String): User
def findByEmailAndPassword(email: String, password: String): User
def findByNickName(nickName: String): User
}
import java.util.{ArrayList, List}
@Entity
class Clan(pName: String) extends DomainModel {
...
@OneToMany(mappedBy = "clan", cascade = Array(CascadeType.PERSIST,
CascadeType.REMOVE), fetch = FetchType.LAZY)
val clanMembers: List[ClanMember] = new ArrayList[ClanMember]
}
Scala 컴파일 시간
• Scala의 가장 큰 단점은 컴파일 시간이 많이 소요된다.
• Scala 기반으로 개발하려면 SSD는 필수. 장비빨이 받쳐주어야 한다.
마치며…
자바 기반의 MSA를 고려한다면
Spring Boot + JPA
자바가 싫증나거나, OOP와 FP를 결합한 프로그래밍을 하고 싶다면
Scala
Scala, Spring-Boot, JPA 동거 지속할거냐?
1년만 더…
1년 후는 다음 세미나에서…
Ad

Recommended

〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
Heungsub Lee
 
Apache kafka 모니터링을 위한 Metrics 이해 및 최적화 방안
Apache kafka 모니터링을 위한 Metrics 이해 및 최적화 방안
SANG WON PARK
 
객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기
Young-Ho Cho
 
Java でつくる 低レイテンシ実装の技巧
Java でつくる 低レイテンシ実装の技巧
Ryosuke Yamazaki
 
Index tuning
Index tuning
Microsoft
 
Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門
tsukasamannen
 
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
 
4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴
Terry Cho
 
DevOps Overview
DevOps Overview
IIJ
 
Data pipeline and data lake
Data pipeline and data lake
DaeMyung Kang
 
redis 소개자료 - 네오클로바
redis 소개자료 - 네오클로바
NeoClova
 
파이썬 생존 안내서 (자막)
파이썬 생존 안내서 (자막)
Heungsub Lee
 
도메인 주도 설계의 본질
도메인 주도 설계의 본질
Young-Ho Cho
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향
Young-Ho Cho
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)
Seung-June Lee
 
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
Juhong Park
 
iOS の通信における認証の種類とその取り扱い
iOS の通信における認証の種類とその取り扱い
niwatako
 
Exactly-once Stream Processing with Kafka Streams
Exactly-once Stream Processing with Kafka Streams
Guozhang Wang
 
Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例
Tomohisa Kusukawa
 
アーキテクチャの進化から学ぶ、プラットフォームエンジニアリングへのアプローチ
アーキテクチャの進化から学ぶ、プラットフォームエンジニアリングへのアプローチ
Yusuke Suzuki
 
[DO07] マイクロサービスに必要な技術要素はすべて Spring Cloud にある
[DO07] マイクロサービスに必要な技術要素はすべて Spring Cloud にある
de:code 2017
 
[우리가 데이터를 쓰는 법] 모바일 게임 로그 데이터 분석 이야기 - 엔터메이트 공신배 팀장
[우리가 데이터를 쓰는 법] 모바일 게임 로그 데이터 분석 이야기 - 엔터메이트 공신배 팀장
Dylan Ko
 
백억개의 로그를 모아 검색하고 분석하고 학습도 시켜보자 : 로기스
백억개의 로그를 모아 검색하고 분석하고 학습도 시켜보자 : 로기스
NAVER D2
 
대용량 분산 아키텍쳐 설계 #1 아키텍쳐 설계 방법론
대용량 분산 아키텍쳐 설계 #1 아키텍쳐 설계 방법론
Terry Cho
 
UI/UXが無意識に検索行動に与える影響について
UI/UXが無意識に検索行動に与える影響について
Tairo Moriyama
 
카프카, 산전수전 노하우
카프카, 산전수전 노하우
if kakao
 
Google Cloud Platform monitoring with Zabbix
Google Cloud Platform monitoring with Zabbix
Max Kuzkin
 
Slipp 발표 자료 20151212
Slipp 발표 자료 20151212
Jinsoo Jung
 
영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA
경원 이
 

More Related Content

What's hot (20)

DevOps Overview
DevOps Overview
IIJ
 
Data pipeline and data lake
Data pipeline and data lake
DaeMyung Kang
 
redis 소개자료 - 네오클로바
redis 소개자료 - 네오클로바
NeoClova
 
파이썬 생존 안내서 (자막)
파이썬 생존 안내서 (자막)
Heungsub Lee
 
도메인 주도 설계의 본질
도메인 주도 설계의 본질
Young-Ho Cho
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향
Young-Ho Cho
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)
Seung-June Lee
 
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
Juhong Park
 
iOS の通信における認証の種類とその取り扱い
iOS の通信における認証の種類とその取り扱い
niwatako
 
Exactly-once Stream Processing with Kafka Streams
Exactly-once Stream Processing with Kafka Streams
Guozhang Wang
 
Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例
Tomohisa Kusukawa
 
アーキテクチャの進化から学ぶ、プラットフォームエンジニアリングへのアプローチ
アーキテクチャの進化から学ぶ、プラットフォームエンジニアリングへのアプローチ
Yusuke Suzuki
 
[DO07] マイクロサービスに必要な技術要素はすべて Spring Cloud にある
[DO07] マイクロサービスに必要な技術要素はすべて Spring Cloud にある
de:code 2017
 
[우리가 데이터를 쓰는 법] 모바일 게임 로그 데이터 분석 이야기 - 엔터메이트 공신배 팀장
[우리가 데이터를 쓰는 법] 모바일 게임 로그 데이터 분석 이야기 - 엔터메이트 공신배 팀장
Dylan Ko
 
백억개의 로그를 모아 검색하고 분석하고 학습도 시켜보자 : 로기스
백억개의 로그를 모아 검색하고 분석하고 학습도 시켜보자 : 로기스
NAVER D2
 
대용량 분산 아키텍쳐 설계 #1 아키텍쳐 설계 방법론
대용량 분산 아키텍쳐 설계 #1 아키텍쳐 설계 방법론
Terry Cho
 
UI/UXが無意識に検索行動に与える影響について
UI/UXが無意識に検索行動に与える影響について
Tairo Moriyama
 
카프카, 산전수전 노하우
카프카, 산전수전 노하우
if kakao
 
Google Cloud Platform monitoring with Zabbix
Google Cloud Platform monitoring with Zabbix
Max Kuzkin
 
DevOps Overview
DevOps Overview
IIJ
 
Data pipeline and data lake
Data pipeline and data lake
DaeMyung Kang
 
redis 소개자료 - 네오클로바
redis 소개자료 - 네오클로바
NeoClova
 
파이썬 생존 안내서 (자막)
파이썬 생존 안내서 (자막)
Heungsub Lee
 
도메인 주도 설계의 본질
도메인 주도 설계의 본질
Young-Ho Cho
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향
Young-Ho Cho
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)
Seung-June Lee
 
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
Juhong Park
 
iOS の通信における認証の種類とその取り扱い
iOS の通信における認証の種類とその取り扱い
niwatako
 
Exactly-once Stream Processing with Kafka Streams
Exactly-once Stream Processing with Kafka Streams
Guozhang Wang
 
Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例
Tomohisa Kusukawa
 
アーキテクチャの進化から学ぶ、プラットフォームエンジニアリングへのアプローチ
アーキテクチャの進化から学ぶ、プラットフォームエンジニアリングへのアプローチ
Yusuke Suzuki
 
[DO07] マイクロサービスに必要な技術要素はすべて Spring Cloud にある
[DO07] マイクロサービスに必要な技術要素はすべて Spring Cloud にある
de:code 2017
 
[우리가 데이터를 쓰는 법] 모바일 게임 로그 데이터 분석 이야기 - 엔터메이트 공신배 팀장
[우리가 데이터를 쓰는 법] 모바일 게임 로그 데이터 분석 이야기 - 엔터메이트 공신배 팀장
Dylan Ko
 
백억개의 로그를 모아 검색하고 분석하고 학습도 시켜보자 : 로기스
백억개의 로그를 모아 검색하고 분석하고 학습도 시켜보자 : 로기스
NAVER D2
 
대용량 분산 아키텍쳐 설계 #1 아키텍쳐 설계 방법론
대용량 분산 아키텍쳐 설계 #1 아키텍쳐 설계 방법론
Terry Cho
 
UI/UXが無意識に検索行動に与える影響について
UI/UXが無意識に検索行動に与える影響について
Tairo Moriyama
 
카프카, 산전수전 노하우
카프카, 산전수전 노하우
if kakao
 
Google Cloud Platform monitoring with Zabbix
Google Cloud Platform monitoring with Zabbix
Max Kuzkin
 

Viewers also liked (7)

Slipp 발표 자료 20151212
Slipp 발표 자료 20151212
Jinsoo Jung
 
영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA
경원 이
 
Scala로의 산책
Scala로의 산책
Youmi Bae
 
SLiPP 스터디 - MSA
SLiPP 스터디 - MSA
Daekwon Kang
 
Slipp clojure-1212
Slipp clojure-1212
완수 양
 
딥러닝(Deep Learing) using DeepDetect
딥러닝(Deep Learing) using DeepDetect
Junyi Song
 
Slipp 발표 - GO
Slipp 발표 - GO
라한사 아
 
Slipp 발표 자료 20151212
Slipp 발표 자료 20151212
Jinsoo Jung
 
영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA
경원 이
 
Scala로의 산책
Scala로의 산책
Youmi Bae
 
SLiPP 스터디 - MSA
SLiPP 스터디 - MSA
Daekwon Kang
 
Slipp clojure-1212
Slipp clojure-1212
완수 양
 
딥러닝(Deep Learing) using DeepDetect
딥러닝(Deep Learing) using DeepDetect
Junyi Song
 
Ad

Similar to Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거 (20)

SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
Javajigi Jaesung
 
Spring Boot 2
Spring Boot 2
경륜 이
 
MyBatis에서 JPA로
MyBatis에서 JPA로
Dongmin Shin
 
spring data jpa 간단한 튜토리얼
spring data jpa 간단한 튜토리얼
라한사 아
 
Jpa 쿼리 포함 자료
Jpa 쿼리 포함 자료
Hyosang Hong
 
Jpa 쿼리 포함 자료
Jpa 쿼리 포함 자료
Hyosang Hong
 
[2018] MyBatis에서 JPA로
[2018] MyBatis에서 JPA로
NHN FORWARD
 
SpringDataJPA - 스프링 캠프
SpringDataJPA - 스프링 캠프
Younghan Kim
 
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
형석 김
 
[162] jpa와 모던 자바 데이터 저장 기술
[162] jpa와 모던 자바 데이터 저장 기술
NAVER D2
 
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
SangIn Choung
 
2023.06.12 발표 자료 : JPA / 스프링 구조
2023.06.12 발표 자료 : JPA / 스프링 구조
HONG YONG JUN
 
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
DK Lee
 
Spring Framework 튜토리얼 - 네이버 최영목님
Spring Framework 튜토리얼 - 네이버 최영목님
NAVER D2
 
2007년 제8회 JCO 컨퍼런스 POJO 프로그래밍 발표 자료
2007년 제8회 JCO 컨퍼런스 POJO 프로그래밍 발표 자료
beom kyun choi
 
Unionweb프로젝트
Unionweb프로젝트
Dong-Jin Park
 
Java JPA
Java JPA
Yonghoon Ji
 
Ksug2015 - JPA1, JPA 소개
Ksug2015 - JPA1, JPA 소개
Younghan Kim
 
[Spring]오브젝트와 의존관계
[Spring]오브젝트와 의존관계
slowstarter
 
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
Javajigi Jaesung
 
MyBatis에서 JPA로
MyBatis에서 JPA로
Dongmin Shin
 
spring data jpa 간단한 튜토리얼
spring data jpa 간단한 튜토리얼
라한사 아
 
Jpa 쿼리 포함 자료
Jpa 쿼리 포함 자료
Hyosang Hong
 
Jpa 쿼리 포함 자료
Jpa 쿼리 포함 자료
Hyosang Hong
 
[2018] MyBatis에서 JPA로
[2018] MyBatis에서 JPA로
NHN FORWARD
 
SpringDataJPA - 스프링 캠프
SpringDataJPA - 스프링 캠프
Younghan Kim
 
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
형석 김
 
[162] jpa와 모던 자바 데이터 저장 기술
[162] jpa와 모던 자바 데이터 저장 기술
NAVER D2
 
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
SangIn Choung
 
2023.06.12 발표 자료 : JPA / 스프링 구조
2023.06.12 발표 자료 : JPA / 스프링 구조
HONG YONG JUN
 
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
DK Lee
 
Spring Framework 튜토리얼 - 네이버 최영목님
Spring Framework 튜토리얼 - 네이버 최영목님
NAVER D2
 
2007년 제8회 JCO 컨퍼런스 POJO 프로그래밍 발표 자료
2007년 제8회 JCO 컨퍼런스 POJO 프로그래밍 발표 자료
beom kyun choi
 
Unionweb프로젝트
Unionweb프로젝트
Dong-Jin Park
 
Ksug2015 - JPA1, JPA 소개
Ksug2015 - JPA1, JPA 소개
Younghan Kim
 
[Spring]오브젝트와 의존관계
[Spring]오브젝트와 의존관계
slowstarter
 
Ad

More from Javajigi Jaesung (11)

나는 왜 TDD에 집착하는가?
나는 왜 TDD에 집착하는가?
Javajigi Jaesung
 
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
Javajigi Jaesung
 
패캠 네트워킹 데이 - 침묵으로 가르치기
패캠 네트워킹 데이 - 침묵으로 가르치기
Javajigi Jaesung
 
어느 40대 아저씨 이야기
어느 40대 아저씨 이야기
Javajigi Jaesung
 
커뮤니티 활동과 스터디
커뮤니티 활동과 스터디
Javajigi Jaesung
 
2014년에 만든 나만의 이력서
2014년에 만든 나만의 이력서
Javajigi Jaesung
 
HTTP web server 구현
HTTP web server 구현
Javajigi Jaesung
 
Java Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte Code
Javajigi Jaesung
 
어떻게 배움을 만들어 갈 것인가
어떻게 배움을 만들어 갈 것인가
Javajigi Jaesung
 
나, 우리, 스터디
나, 우리, 스터디
Javajigi Jaesung
 
ORM을 활용할 경우의 설계, 개발 과정
ORM을 활용할 경우의 설계, 개발 과정
Javajigi Jaesung
 
나는 왜 TDD에 집착하는가?
나는 왜 TDD에 집착하는가?
Javajigi Jaesung
 
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
Javajigi Jaesung
 
패캠 네트워킹 데이 - 침묵으로 가르치기
패캠 네트워킹 데이 - 침묵으로 가르치기
Javajigi Jaesung
 
어느 40대 아저씨 이야기
어느 40대 아저씨 이야기
Javajigi Jaesung
 
커뮤니티 활동과 스터디
커뮤니티 활동과 스터디
Javajigi Jaesung
 
2014년에 만든 나만의 이력서
2014년에 만든 나만의 이력서
Javajigi Jaesung
 
Java Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte Code
Javajigi Jaesung
 
어떻게 배움을 만들어 갈 것인가
어떻게 배움을 만들어 갈 것인가
Javajigi Jaesung
 
ORM을 활용할 경우의 설계, 개발 과정
ORM을 활용할 경우의 설계, 개발 과정
Javajigi Jaesung
 

Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거

  • 1. Scala, Spring-Boot, JPA의 불편하면서도 즐거운 동거
  • 2. Scala, Spring-Boot, JPA가 동거를 시작한 이유는? JPA가 동거에 기여하는 점 Spring-Boot가 동거에 기여하는 점 Scala가 동거에 기여하는 점 Scala, Spring-Boot, JPA 동거할 때 고려할 사항
  • 3. Scala, Spring-Boot, JPA가 동거를 시작한 이유는?
  • 4. JPA • 단순, 반복적인 CRUD 작업하기 싫다. • 스키마 변경에 따른 비용을 최소화하고 싶다. • 핵심 비즈니스 로직에 집중하고 싶다.
  • 5. Spring Boot • 단순, 반복적인 Spring 설정 작업하기 싫다. • 핵심 비즈니스 로직에 집중하고 싶다.
  • 6. Scala • 10년 이상 Java만 했더니 재미없더라. • 2년 정도 함수형 언어로 Scheme, Clojure 도전했다가 중도 포기 • 어딘가 직접적으로 활용하고 있지 않으면 동기부여가 잘 되지 않는 성격
  • 7. • 단순, 반복적인 작업 제거 • 핵심 비즈니스 로직에 집중 • Java에 싫증이나 Scala를 선택
  • 8. • 단순, 반복적인 작업 제거 • 핵심 비즈니스 로직에 집중 • Java에 싫증이나 Scala를 선택
  • 10. Play가 아닌 Scala + Spring + JPA 조합을 선택한 이유 • Spring과 JPA 경험을 버리는 것의 아쉬움. • 중도 포기하지 않으려면 변화를 Scala 하나로 한정. • 변화를 싫어하는 다른 Java 개발자를 설득하기 위해 최소한의 변화.
  • 12. JPA • 단순, 반복적인 CRUD 작업하기 싫다. • 스키마 변경에 따른 비용을 최소화하고 싶다. • 핵심 비즈니스 로직에 집중하고 싶다.
  • 13. JPA 도입에 따른 더 큰 효과 요구사항이 자주 변경되는 프로젝트 초반, 빠른 사이클로 설계에 대해 다양한 실험이 가능하다.
  • 14. JPA를 사용하지 않는 경우 – 테이블 최초 생성시 데이터베이스에 스키마 적용 비즈니스 로직 구현 테이블 설계 테이블 스키마 생성SQL 쿼리 구현 자바 테이블과 매핑되는 객체 추 가 1 2 34 5 6
  • 15. JPA를 사용하지 않는 경우 – 테이블 스키마 변경시 데이터베이스에 스키마 적용 비즈니스 로직 변경(선택) 테이블 설계 테이블 스키마 변경 칼럼 변경에 따른 SQL 쿼리 수정 자바 객체에 필드 변경
  • 16. 비즈니스 로직 구현 객체 설계 JPA를 사용하는 경우 – 객체(Entity) 최초 생성시 객체 추가 및 매핑 데이터베이스에 스 키마 적용 비즈니스 로직 구현 테이블 설계 테이블 스키마 생성SQL 쿼리 구 현 자바 테이블과 매핑되 는 객체 추가 1 2 3
  • 17. 비즈니스 로직 구현(선 택) 객체 설계 JPA를 사용하는 경우 – 객체(Entity) 필드 변경 객체 필드 변경 데이터베이스에 스키마 적용 비즈니스 로직 변경(선택) 테이블 설계 테이블 스키마 변경칼럼 변경에 따른 SQL 쿼리 수정 자바 객체에 필드 변경
  • 18. JPA 도입 효과 • 요구사항이 자주 변경되는 프로젝트 초반 빠른 구현 – 피드백 사이 클 • 빠른 피드백 사이클은 삽질할 수 있는 시간을 확보함으로써 빠른 지식 축적이 가능하다. • 지식 축적은 도메인에 최적화된 설계를 할 수 있도록 한다. • 좋은 설계는 사용자의 요구사항 변화에 빠르게 대응할 수 있다. • 개발자는 소스 코드에 대한 자부심과 여유 시간을 확보할 수 있다.
  • 19. 더 자세히 알고 싶다면… ORM 프레임워크를 활용할 때의 설계, 개발 프로세스
  • 21. Spring Boot • 단순, 반복적인 Spring 설정 작업하기 싫다. • 핵심 비즈니스 로직에 집중하고 싶다.
  • 22. 1. @IntegrationTest • Spring Boot는 Embedded Tomcat 기반으로 동작. • @IntegrationTest 기반으로 테스트하면 Embedded Tomcat을 자동 실행한 후 Client 테스트가 가능. • 특히 RestTemplate을 활용해 API 테스트할 때 유용.
  • 23. 지금까지 통합 테스트 방법 WAS 시작 통합 테스트 실행
  • 24. @IntegrationTest 기반 API 테스트 방법 Only 통합 테스트 실행 = WAS 시작 + 통합 테스트 실행
  • 25. @SpringApplicationConfiguration(classes = Array(classOf[MyWebConfig])) @WebAppConfiguration @IntegrationTest(Array("server.port:0")) abstract class ServerIntegrationTest { @Value("${local.server.port}") var port: Int = _ // 사용하지 않는 임의의 port가 할당됨 val baseUrl = "http://localhost:" + port }
  • 26. @RunWith(classOf[SpringJUnit4ClassRunner]) class UserControllerTest extends ServerIntegrationTest { val restTemplate: RestTemplate = new RestTemplate() @Test def canCreateUser() { val result = restTemplate.postForEntity( baseUrl + "/users", postParameter(List( "email" -> "[email protected]", "password" -> "password" )), classOf[String]) assert(result.getStatusCode == HttpStatus.OK) } }
  • 27. 2. Spring Boot Actuator • 서비스 운영시 모니터링 요소에 대한 기본 정보 제공
  • 28. 제공하는 정보 • Spring 관련 정보 • /autoconfig – Spring auto configuration 정보 • /beans - Spring Bean 목록 • /configprops - @ConfigurationProperties 정보 • /mappings - @RequestMapping 정보 • 시스템 운영 및 성능 • /dump – thread dump • /health – 애플리케이션의 정상 동작 유무 • /metrics – 애플리케이션의 메모리 상태, heap, thread 등과 관련한 정보 제공 • http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production- ready 에서 추가 정보 확인
  • 29. Application Detail 출처 : https://github.com/codecentric/spring-boot-admin
  • 30. Thread 상태 출처 : https://github.com/codecentric/spring-boot-admin
  • 31. Actuator Remote Shell 출처 : http://nomimic.tistory.com/5
  • 32. 빠르게 최소한의 모니터링 및 운영 환경을 구축할 수 있다.
  • 34. Spring Boot + JPA 환경 조합만으로 충분히 생산성 높다.
  • 35. Scala • 10년 이상 Java만 했더니 재미없더라. • 2년 정도 함수형 언어로 Scheme, Clojure 도전했다가 중도 포기 • 어딘가 직접적으로 활용하고 있지 않으면 동기부여가 잘 되지 않는 성격
  • 36. 1. Domain과 DTO의 명확한 분리에 대한 거부감이 줄어듦 • 현재 개발 추세는 Domain 객체와 DTO에 중복되는 부분이 많아 자바 객체 하나가 Domain 역할, DTO 역할을 하는 방식으로 구현. • Scala를 활용하면 각 역할별로 구현하는 것에 대한 거부감이 줄어듦
  • 37. @Entity class User(pEmail: String, pNickName: String, pPassword: String) extends DomainModel { @Id @GeneratedValue var id: Long = _ @Column(unique = true, nullable = false) val email = pEmail @Column(name = "nick_name", nullable = false) val nickName = pNickName @Column(nullable = false) val password = pPassword def isGuest(): Boolean = { false } } User Entity • 반드시 setter/getter를 생성하지 않아도 된다.
  • 38. @JsonIgnoreProperties(ignoreUnknown = true) @JsonPropertyOrder(alphabetic = true) @JsonInclude(Include.NON_NULL) @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE) trait View case class UserView(id: Long, email: String, nickName: String) extends View { def this(u: User) = this(u.id, u.email, u.nickName) def this() = this(new User()) } User View DTO • Scala case class를 활용하면 자동으로 field 추가함.
  • 39. class UserForm { @BeanProperty @Email var email: String = _ @BeanProperty @NotNull @Size(min = 3, max = 10) var nickName: String = _ @BeanProperty @NotNull @Size(min = 8, max = 15) var password: String = _ def toUser() = new User(email, nickName, password) } User Form DTO • @BeanProperty 활용하면 setter/getter method 자동 추가
  • 40. Domain과 DTO의 명확한 분리에 대한 거부감이 줄어듦 • 분리하는 것이 항상 좋은 것은 아니다. • 상황에 따라 Entity와 DTO를 분리/통합할 것인지에 대한 역량을 키우는 것이 더 중요하다.
  • 41. 2. Test Fixture(Test Data) 생성하기 용이함. • 자바에서 Test Fixture를 생성하고 변경하기 어려움은 Test 코드를 만드는데 약간의 장애물이다. • Scala는 named parameter를 통해 해결 가능
  • 42. email, nickname, password를 가지는 User 객체에 대한 테스트를 데이터를 만든다면…
  • 43. public class UserBuilder { private String email; private String nickname; private String password; public UserBuilder withEmail(String email) { this.email = email; return this; } public UserBuilder withNickname(String nickname) { this.nickname = nickname; return this; } public UserBuilder withPassword(String password) { this.password = password; return this; } public User build() { return new User(email, nickname, password); } }
  • 44. public class UserTest { @Test public void canCreate() throws Exception { User user1 = new UserBuilder().withEmail("[email protected]").build(); User user2 = new UserBuilder().withEmail("[email protected]").withNickname("newname").build(); } } 22장. 복잡한 테스트 데이터 만들기 참고
  • 45. trait Fixture { def aSomeUser(email: String = "[email protected]", nickname: String = "nickName", password: String = "password") = new User(email, nickname, password) } val user1 = aSomeUser val user2 = aSomeUser(email="[email protected]") val user1 = aSomeUser(nickName="newname")
  • 46. 3. implicit을 활용한 중복 제거 • 애플리케이션을 구현하다보면 반복적으로 전달하는 인자가 존재함. • Scala의 implicit을 활용해 제거 가능
  • 47. class ClanService @Autowired() (val clanRepository: ClanRepository, val channelService: ChannelService) { def findClan(id: Long)(implicit user: User) = { [...] } def create(name: String)(implicit user: User) = { [...] } }
  • 48. class ClanService @Autowired() (val clanRepository: ClanRepository, val channelService: ChannelService) { def findClan(id: Long)(implicit user: User) = { [...] } def create(name: String)(implicit user: User) = { [...] } } class ClanController @Autowired() (val clanService: ClanService) extends BaseController { @RequestMapping(value = Array(""), method = Array(RequestMethod.POST)) def create(name: String) = { val savedClan = clanService.create(name) new ClanDetailView(savedClan, currentUser) } @RequestMapping(value = Array("/{id}"), method = Array(RequestMethod.GET)) def clanUsers(@PathVariable id: Long) = { val clan = clanService.findClan(id) new ClanDetailView(clan, currentUser) } }
  • 49. object CurrentUserDetails { implicit def cud: CurrentUserDetails = { currentUserDetails(SecurityContextHolder.getContext().getAuthentication().getPrincipal()) } implicit def currentUser: User = { cud.getUser } } import support.security.CurrentUserDetails._ class ClanController @Autowired() (val clanService: ClanService) extends BaseController { @RequestMapping(value = Array(""), method = Array(RequestMethod.POST)) def create(name: String) = { val savedClan = clanService.create(name) new ClanDetailView(savedClan, currentUser) } @RequestMapping(value = Array("/{id}"), method = Array(RequestMethod.GET)) def clanUsers(@PathVariable id: Long) = { val clan = clanService.findClan(id) new ClanDetailView(clan, currentUser) } }
  • 50. • Case Class • Named Parameter • implicit
  • 51. • Pattern Match • Some/Option • Lambda(람다) • 막강 Collection • 모나드 등등 … • Functional Programming • Case Class • Named Parameter • implicit
  • 53. Scala를 적용 단계 • 1단계 : Scala를 자바처럼 구현한다. • 2단계 : 점차 Scala 문법에 친숙해지면 Scala 기능을 하나씩 적용한다. • 3단계 : 함수형 프로그래밍 스타일로 구현한다. • 4단계 : play 프레임워크로 갈아탄다.
  • 54. Scala, Spring-Boot, JPA 동거할 때 고려할 부분
  • 55. Scala, Spring, JPA 동거시 불편한 부분 • Java 기반 프레임워크 사용하면서 고려할 부분이 생긴다. • Scala의 모든 기능을 극한으로 사용하는데 제약 사항이 있다.
  • 56. @RestController class UserController @Autowired() (val userRepository: UserRepository) { val Log = LoggerFactory.getLogger(classOf[UserController]) @RequestMapping(value = Array("/users"), method = Array(RequestMethod.POST) ) def join(@Valid @RequestBody userForm: UserForm, result: BindingResult) = { ... } @RequestMapping(value = Array("/users/{userEmail}"), method = Array(RequestMethod.POST) ) def login(@PathVariable userEmail: String, @RequestParam(required = true) password:String) = { ... } }
  • 57. import java.lang.Long import org.springframework.data.repository.CrudRepository trait UserRepository extends CrudRepository[User, Long] { def findByEmail(email: String): User def findByEmailAndPassword(email: String, password: String): User def findByNickName(nickName: String): User }
  • 58. import java.util.{ArrayList, List} @Entity class Clan(pName: String) extends DomainModel { ... @OneToMany(mappedBy = "clan", cascade = Array(CascadeType.PERSIST, CascadeType.REMOVE), fetch = FetchType.LAZY) val clanMembers: List[ClanMember] = new ArrayList[ClanMember] }
  • 59. Scala 컴파일 시간 • Scala의 가장 큰 단점은 컴파일 시간이 많이 소요된다. • Scala 기반으로 개발하려면 SSD는 필수. 장비빨이 받쳐주어야 한다.
  • 61. 자바 기반의 MSA를 고려한다면 Spring Boot + JPA
  • 62. 자바가 싫증나거나, OOP와 FP를 결합한 프로그래밍을 하고 싶다면 Scala
  • 63. Scala, Spring-Boot, JPA 동거 지속할거냐?
  • 64. 1년만 더… 1년 후는 다음 세미나에서…

Editor's Notes