SlideShare une entreprise Scribd logo
1  sur  64
Télécharger pour lire hors ligne
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를 선택
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년 후는 다음 세미나에서…

Contenu connexe

Tendances

Jquery javascript_ed10
Jquery javascript_ed10Jquery javascript_ed10
Jquery javascript_ed10hungrok
 
Ksug2015 - JPA1, JPA 소개
Ksug2015 - JPA1, JPA 소개Ksug2015 - JPA1, JPA 소개
Ksug2015 - JPA1, JPA 소개Younghan Kim
 
자바야 놀자 PPT
자바야 놀자 PPT자바야 놀자 PPT
자바야 놀자 PPTJinKyoungHeo
 
Spring data jpa
Spring data jpaSpring data jpa
Spring data jpaTaesin Um
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Younghan Kim
 
Java 강의자료 ed11
Java 강의자료 ed11Java 강의자료 ed11
Java 강의자료 ed11hungrok
 
좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012Daum DNA
 
Java script 강의자료_ed13
Java script 강의자료_ed13Java script 강의자료_ed13
Java script 강의자료_ed13hungrok
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10hungrok
 
DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)beom kyun choi
 
Web server page_ed10
Web server page_ed10Web server page_ed10
Web server page_ed10hungrok
 
Java Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte CodeJava Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte CodeJavajigi Jaesung
 
[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱
[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱
[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱정석 양
 
Jdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamicJdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamicknight1128
 
Hibernate start (하이버네이트 시작하기)
Hibernate start (하이버네이트 시작하기)Hibernate start (하이버네이트 시작하기)
Hibernate start (하이버네이트 시작하기)visual khh
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!WooYoung Cho
 
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개beom kyun choi
 

Tendances (20)

HTTP web server 구현
HTTP web server 구현HTTP web server 구현
HTTP web server 구현
 
Java JPA
Java JPAJava JPA
Java JPA
 
Jquery javascript_ed10
Jquery javascript_ed10Jquery javascript_ed10
Jquery javascript_ed10
 
Ksug2015 - JPA1, JPA 소개
Ksug2015 - JPA1, JPA 소개Ksug2015 - JPA1, JPA 소개
Ksug2015 - JPA1, JPA 소개
 
자바야 놀자 PPT
자바야 놀자 PPT자바야 놀자 PPT
자바야 놀자 PPT
 
Spring data jpa
Spring data jpaSpring data jpa
Spring data jpa
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조
 
Java 강의자료 ed11
Java 강의자료 ed11Java 강의자료 ed11
Java 강의자료 ed11
 
좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012
 
Java script 강의자료_ed13
Java script 강의자료_ed13Java script 강의자료_ed13
Java script 강의자료_ed13
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10
 
DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)
 
Web server page_ed10
Web server page_ed10Web server page_ed10
Web server page_ed10
 
Spring Boot 1
Spring Boot 1Spring Boot 1
Spring Boot 1
 
Java Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte CodeJava Virtual Machine, Call stack, Java Byte Code
Java Virtual Machine, Call stack, Java Byte Code
 
[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱
[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱
[ 하코사세미나] 의외로 쉬운 D3 그래프 퍼블리싱
 
Jdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamicJdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamic
 
Hibernate start (하이버네이트 시작하기)
Hibernate start (하이버네이트 시작하기)Hibernate start (하이버네이트 시작하기)
Hibernate start (하이버네이트 시작하기)
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!
 
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
 

En vedette

Slipp 발표 자료 20151212
Slipp 발표 자료 20151212Slipp 발표 자료 20151212
Slipp 발표 자료 20151212Jinsoo Jung
 
Scala로의 산책
Scala로의 산책Scala로의 산책
Scala로의 산책Youmi Bae
 
SLiPP 스터디 - MSA
SLiPP 스터디 - MSASLiPP 스터디 - MSA
SLiPP 스터디 - MSADaekwon Kang
 
Slipp clojure-1212
Slipp clojure-1212Slipp clojure-1212
Slipp clojure-1212완수 양
 
딥러닝(Deep Learing) using DeepDetect
딥러닝(Deep Learing) using DeepDetect딥러닝(Deep Learing) using DeepDetect
딥러닝(Deep Learing) using DeepDetectJunyi Song
 

En vedette (6)

Slipp 발표 자료 20151212
Slipp 발표 자료 20151212Slipp 발표 자료 20151212
Slipp 발표 자료 20151212
 
Scala로의 산책
Scala로의 산책Scala로의 산책
Scala로의 산책
 
SLiPP 스터디 - MSA
SLiPP 스터디 - MSASLiPP 스터디 - MSA
SLiPP 스터디 - MSA
 
Slipp clojure-1212
Slipp clojure-1212Slipp clojure-1212
Slipp clojure-1212
 
딥러닝(Deep Learing) using DeepDetect
딥러닝(Deep Learing) using DeepDetect딥러닝(Deep Learing) using DeepDetect
딥러닝(Deep Learing) using DeepDetect
 
Slipp 발표 - GO
Slipp 발표 - GOSlipp 발표 - GO
Slipp 발표 - GO
 

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

오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례형석 김
 
자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)
자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)
자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)DK Lee
 
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담Javajigi Jaesung
 
Introduction to Apache Tajo
Introduction to Apache TajoIntroduction to Apache Tajo
Introduction to Apache TajoGruter
 
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용중선 곽
 
Sql 중심 코드 탈피
Sql 중심 코드 탈피Sql 중심 코드 탈피
Sql 중심 코드 탈피ssuser776e2d
 
Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료ssuser776e2d
 
레일스를 이용한 애자일 웹 개발 가이드
레일스를 이용한 애자일 웹 개발 가이드레일스를 이용한 애자일 웹 개발 가이드
레일스를 이용한 애자일 웹 개발 가이드Sukjoon Kim
 
Spring boot-summary(part2-part3)
Spring boot-summary(part2-part3)Spring boot-summary(part2-part3)
Spring boot-summary(part2-part3)Jaesup Kwak
 
Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Choonghyun Yang
 
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)DK Lee
 
Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드
Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드
Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드cranbe95
 
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트Dae Kim
 
좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVON좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVONYounghan Kim
 

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

오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
오픈 소스를 활용한 게임 배치 플랫폼 개선 사례
 
Cygnus unit test
Cygnus unit testCygnus unit test
Cygnus unit test
 
자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)
자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)
자바 웹 개발 시작하기 (9주차 : 프로젝트 구현 – 추가적인 뷰)
 
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
SLiPP 서비스를 Java에서 Scala로 전환하면서 경험담
 
Introduction to Apache Tajo
Introduction to Apache TajoIntroduction to Apache Tajo
Introduction to Apache Tajo
 
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
 
Sql 중심 코드 탈피
Sql 중심 코드 탈피Sql 중심 코드 탈피
Sql 중심 코드 탈피
 
Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료
 
Scala for play
Scala for playScala for play
Scala for play
 
레일스를 이용한 애자일 웹 개발 가이드
레일스를 이용한 애자일 웹 개발 가이드레일스를 이용한 애자일 웹 개발 가이드
레일스를 이용한 애자일 웹 개발 가이드
 
Spring boot-summary(part2-part3)
Spring boot-summary(part2-part3)Spring boot-summary(part2-part3)
Spring boot-summary(part2-part3)
 
dbt 101
dbt 101dbt 101
dbt 101
 
4-1. javascript
4-1. javascript4-1. javascript
4-1. javascript
 
Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)Spring boot 공작소(1-4장)
Spring boot 공작소(1-4장)
 
Spark sql
Spark sqlSpark sql
Spark sql
 
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
자바 웹 개발 시작하기 (5주차 : 스프링 프래임워크)
 
Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드
Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드
Ndc2011 성능 향상을_위한_데이터베이스_아키텍쳐_구축_및_개발_가이드
 
okspring3x
okspring3xokspring3x
okspring3x
 
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
 
좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVON좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVON
 

Plus de Javajigi Jaesung

나는 왜 TDD에 집착하는가?
나는 왜 TDD에 집착하는가?나는 왜 TDD에 집착하는가?
나는 왜 TDD에 집착하는가?Javajigi Jaesung
 
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵Javajigi Jaesung
 
패캠 네트워킹 데이 - 침묵으로 가르치기
패캠 네트워킹 데이 - 침묵으로 가르치기패캠 네트워킹 데이 - 침묵으로 가르치기
패캠 네트워킹 데이 - 침묵으로 가르치기Javajigi Jaesung
 
어느 40대 아저씨 이야기
어느 40대 아저씨 이야기어느 40대 아저씨 이야기
어느 40대 아저씨 이야기Javajigi Jaesung
 
커뮤니티 활동과 스터디
커뮤니티 활동과 스터디커뮤니티 활동과 스터디
커뮤니티 활동과 스터디Javajigi Jaesung
 
2014년에 만든 나만의 이력서
2014년에 만든 나만의 이력서2014년에 만든 나만의 이력서
2014년에 만든 나만의 이력서Javajigi Jaesung
 
어떻게 배움을 만들어 갈 것인가
어떻게 배움을 만들어 갈 것인가어떻게 배움을 만들어 갈 것인가
어떻게 배움을 만들어 갈 것인가Javajigi Jaesung
 

Plus de Javajigi Jaesung (8)

나는 왜 TDD에 집착하는가?
나는 왜 TDD에 집착하는가?나는 왜 TDD에 집착하는가?
나는 왜 TDD에 집착하는가?
 
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
 
패캠 네트워킹 데이 - 침묵으로 가르치기
패캠 네트워킹 데이 - 침묵으로 가르치기패캠 네트워킹 데이 - 침묵으로 가르치기
패캠 네트워킹 데이 - 침묵으로 가르치기
 
어느 40대 아저씨 이야기
어느 40대 아저씨 이야기어느 40대 아저씨 이야기
어느 40대 아저씨 이야기
 
커뮤니티 활동과 스터디
커뮤니티 활동과 스터디커뮤니티 활동과 스터디
커뮤니티 활동과 스터디
 
2014년에 만든 나만의 이력서
2014년에 만든 나만의 이력서2014년에 만든 나만의 이력서
2014년에 만든 나만의 이력서
 
어떻게 배움을 만들어 갈 것인가
어떻게 배움을 만들어 갈 것인가어떻게 배움을 만들어 갈 것인가
어떻게 배움을 만들어 갈 것인가
 
나, 우리, 스터디
나, 우리, 스터디나, 우리, 스터디
나, 우리, 스터디
 

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를 선택
  • 9.
  • 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" -> "test@gmail.com", "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("some@sample.com").build(); User user2 = new UserBuilder().withEmail("some@sample.com").withNickname("newname").build(); } } 22장. 복잡한 테스트 데이터 만들기 참고
  • 45. 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")
  • 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년 후는 다음 세미나에서…

Notes de l'éditeur

  1. 14
  2. 15
  3. 16
  4. 17
  5. 23
  6. 24