SlideShare ist ein Scribd-Unternehmen logo
1 von 43
Downloaden Sie, um offline zu lesen
객체 지향 발담그기
최범균, madvirus@madvirus.net
오늘의 주제

추상화 + 유연함
여러 클라우드에
올라간 파일들을
통합 관리하는
앱을 만들어보자.

출처: http://www.flickr.com/photos/42402605@N07/5693120074
빨리 선보이기 위한 최초 0.1 버전

•  대상 클라우드
o 

드롭박스, 박스

o 

각 클라우드의 목록 조회하기
각 클라우드에서 파일 다운로드 하기

•  주요 기능
o 
파일 정보 표현
public class FileInfo {
private CloudId cloudId;
private String name;
private long length;
… // get 메서드
}

public enum CloudId {
DROPBOX,
BOX;
}
파일 목록 조회
public List<FileInfo> getFileInfos(CloudId cloudId) {
if (cloudId == CloudId.DROPBOX) {
DropboxClient dc = …;
List<DbFile> dbFiles = db.getFiles();
List<FileInfo> result = new ArrayList<>();
for (DbFile dbFile : dbFiles) {
FileInfo fi = new FileInfo();
fi.setCloudId(CloudId.DROPBOX);
…
result.add(fi);
}
return result;
} else if (cloudId == CloudId.BOX) {
BoxService boxSvc = …;
… //
}
}
파일 다운로드 (계속)
public void download(FileInfo file, File localTarget) {
if (file.getCloudId() == CloudId.DROPBOX) {
DropboxClient dc = …;
FileOutputStream out = new FileOutputStream(localTarget);
dc.copy(file.getFileId(), out);
out.close();
} else if (file.getCloudId() == CloudId.BOX) {
// TODO
}
동작하도록 반영
}

public class FileInfo {
private CloudId cloudId;
private String fileId;
private String name;
...

for (DbFile dbFile : dbFiles) {
FileInfo fi = new FileInfo();
fi.setFileId(dbFile.getId());
fi.setCloudId(cloudId);
…
}
파일 다운로드
public void download(FileInfo file, File localTarget) {
if (file.getCloudId() == CloudId.DROPBOX) {
...
} else if (file.getCloudId() == CloudId.BOX) {
BoxService boxSvc = …;
InputStream is = boxSvc.getInputStream(file.getId());
FileOutputStream out = new FileOutputStream(localTarget);
CopyUtil.copy(is, out);
}
}
야호!

•  무사히 동작하는 0.1 버전 완성
•  0.5 버전을 향해
o 

기능 확대
§  파일 업로드
§  파일 삭제
§  검색
§  이미지 미리보기
0.5v 기능 추가
public FileInfo upload(File file, CloudId cid) {
if (cid == CloudId.DROPBOX) {
...
} else if (cid == CloudId.BOX) {
...
public void delete(String fileId, CloudId cid) {
}
if (cid == CloudId.DROPBOX) {
}
...
} else if (cid == CloudId.BOX) {
...
}
public List<FileInfo> search(String query, CloudId cid) {
}
if (cid == CloudId.DROPBOX) {
...
} else if (cid == CloudId.BOX) {
...
}
}
음...

•  무사히 동작하는 0.5 버전 완성
•  베타 버전을 향해
o 

o 

클라우드 추가
§  S클라우드
§  D클라우드
§  N클라우드
§  ...
기능 추가
§  클라우드 간 파일 복사
과정
public FileInfo upload(File file, CloudId cid) {
if (cid == CloudId.DROPBOX) {
...
} else if (cid == CloudId.BOX) {
...
}
코드복사
}

public FileInfo upload(File file, CloudId cid) {
if (cid == CloudId.DROPBOX) {
...
} else if (cid == CloudId.BOX) {
...
} else if (cid == CloudId.BOX) {
...
}
}

public FileInfo upload(File file, CloudId cid) {
if (cid == CloudId.DROPBOX) {
...
} else if (cid == CloudId.BOX) {
...
} else if (cid == CloudId.SCLOUD) {
ScloudClient scClient = …;
...
구현변경
}
}

public FileInfo upload(File file, CloudId cid) {
if (cid == CloudId.DROPBOX) {
...
조건변경
} else if (cid == CloudId.BOX) {
...
} else if (cid == CloudId.SCLOUD) {
...
}
}
흔한 실수
public List<FileInfo> getFileInfos(CloudId cloudId) {
if (cloudId == CloudId.DROPBOX) {
…
} else if (cloudId == CloudId.BOX) {
…
} else if (cloudId == CloudId.SCLOUD) {
…
} else if (cloudId == CloudId.DCLOUD) {
…

public void delete(String fileId, CloudId cid) {
if (cid == CloudId.DROPBOX) {
...
return result;
} else if (cloudId == CloudId.BOX) {
… //
} else if (cloudId == CloudId.SCLOUD) {
… //

alert(“파일이 존재하지 않습니다.”);

...
} else if (cloudId == CloudId.DCLOUD) {
…

fi.setCloudId(CloudId.SCLOUD);
…
} else if (cloudId == CloudId.NCLOUD) {
…
}
}

음.. 파일이
있는데,
왜 없다 그러지?

alert(“파일이 존재하지 않습니다.”);

...
} else if (cloudId == CloudId.NCLOUD) {
… //
}
}

OO;;
클라우드 간 파일 복사 기능 고려사항

•  URL로부터 복사해서 가져오는 클라우드 존재
o 

그런데, URL을 제공하지 않는 클라우드 존재

o 

그런데, InputStream을 제공하지 않는 클라우드 존재

•  InputStream을 제공하면 되는 클라우드 존재
•  로컬 File을 제공해야 하는 클라우드 존재
클라우드 간 파일 복사 기능 구현 ...
public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) {
if (to == CloudId.DROPBOX) { // URL로 복사하기 지원
DropBoxClient dbClient = …;
if (from == CloudId.BOX) {
dbClient.copyFromUrl(“http://www.box.com/files/”+fileInfo.getFileId());
} else if (from == CloudId.SCLOUD) {
ScloudClient sClient = …;
InputStream is = sClient.getInputStream(fileInfo.getFileId());
dbClient.copyFromInputStream(is, fileInfo.getName());
} else if (from ==CloudId.DCLOUD) {
dbClient.copyFromUrl(“http://www.dcloud.com/getfile?fileId=”+fileInfo.getFileId());
} else if (from == CloudId.NCLOUD) {
NCloudClient nClient = …;
File temp = File.createTemp();
nClient.save(fileInfo.getFileId(), temp);
InputStream is = new FileInputStream(temp);
dbClient.copyFromInputStream(is, fileInfo.getName());
}
} else if (to == CloudId.BOX) {
// 코드 계속 ….
클라우드 간 파일 복사 기능 구현 ...
} else if (to == CloudId.BOX) { // URL로 복사하기 지원
BoxService boxService = …;
if (from == CloudId.DROPBOX) {
boxService.createFileByUrl(“http://www.dropbox.com/box/files/”+fileInfo.getFileId());
} else if (from == CloudId.SCLOUD) {
ScloudClient sClient = …;
InputStream is = sClient.getInputStream(fileInfo.getFileId());
boxService.uploadFile(is, fileInfo.getName());
} else if (from ==CloudId.DCLOUD) {
boxService.createFileByUrl(“http://www.dcloud.com/getfile?fileId=”+fileInfo.getFileId());
} else if (from == CloudId.NCLOUD) {
NCloudClient nClient = …;
File temp = File.createTemp();
nClient.save(fileInfo.getFileId(), temp);
boxService.uploadFile(temp, fileInfo.getName());
}
} else if (to == CloudId.SCLOUD) {
// 코드 계속 ….
클라우드 간 파일 복사 기능 구현 ...
} else if (to == CloudId.SCLOUD) {
ScloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.DCLOUD) {
// 코드 계속 ….
클라우드 간 파일 복사 기능 코드
(if-else 구조만 표시)
public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) {
if (to == CloudId.DROPBOX) { // URL로 복사하기 지원
DropBoxClient dbClient = …;
if (from == CloudId.BOX) {
...
} else if (from == CloudId.SCLOUD) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.BOX) { // URL로 복사하기 지원
BoxService boxService = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.SCLOUD) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.SCLOUD) {
ScloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}

} else if (to == CloudId.DCLOUD) {
DcloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.SCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.NCLOUD) {
NcloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.SCLOUD) {
…
...
} else if (from == CloudId.DCLOUD) {
…
...
}
}
}
.
새로운 요구사항
public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) {
if (to == CloudId.DROPBOX) { // URL로 복사하기 지원
DropBoxClient dbClient = …;
if (from == CloudId.BOX) {
...
} else if (from == CloudId.SCLOUD) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.BOX) { // URL로 복사하기 지원
BoxService boxService = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.SCLOUD) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.SCLOUD) {
ScloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.DCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}

} else if (to == CloudId.DCLOUD) {
DcloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.SCLOUD) {
…
...
} else if (from == CloudId.NCLOUD) {
…
...
}
} else if (to == CloudId.NCLOUD) {
NcloudClient sClient = …;
if (from == CloudId.DROPBOX) {
…
...
} else if (from == CloudId.BOX) {
…
...
} else if (from ==CloudId.SCLOUD) {
…
...
} else if (from == CloudId.DCLOUD) {
…
...
}
}

클라우드 10개 추가

}
.
1개 클라우드 추가 비용
개발
비용

예전엔
빨리 했는
데…...

시간
개발시간이
왜
증가하는가?
개발 시간 증가 이유

•  코드 구조가 길어지고 복잡해짐
o 

새로운 클라우드 추가시 모든 메서드에 새로운 if 블록 추가
§  중첩 if-else는 복잡도 배로 증가
§  if-else가 많을수록 진척 더딤 (신중 모드)

•  관련 코드가 여러 곳에 분산됨
o 

한 클라우드 처리와 관련된 코드가 여러 메서드에 흩어짐

o 

코드 추가에 따른 노동 시간 증가
실수하기 쉽고, 이로 인한 불필요한 디버깅 시간 증가

•  결과적으로, 코드 가독성과 분석 속도 저하
o 
해결책

데이터와기능을함께갖는
객체로추상화Abstraction
추상화
DROPBOX
BOX
SCLOUD
DCLOUD
NCLOUD

클라우드
파일시스템
클라우드 파일 시스템 설계
DROPBOX용 구현 (계속)
public class DropBoxFileSystem implements CloudFileSystem {
private DropBoxClient dbClient = new DropBoxClient(...);
@Override
public List<CloudFile> getFiles() {
List<DbFile> dbFiles = dbClient.getFiles();
List<CloudFile> results = new ArrayList<>(dbFiles.size());
for (DbFile file : dbFiles) {
DropBoxCloudFile cf = new DropBoxCloudFile(file, dbClient);
results.add(cf);
}
return results;
}
DROPBOX용 구현
public class DropBoxCloudFile
implements CloudFile {
private DropBoxClient dbClient;
private DbFile dbFile;
public DropBoxCloudFile(
DbFile dbFile, dbClient) {
this.dbFile = dbFile;
this.dbClient = dbClient;
}
public String getId() {
return dbFile.getId();
}
public boolean hasUrl() {
return true;
}
public String getUrl() {
return dbFile.getFileUrl();
}

public String getName() {
return dbFile.getFileName();
}
public InputStream getInputStream() {
return dbClient
.createStreamOfFile(dbFile);
}
public void write(OutputStream out) {
...
}
public void delete() {
dbClient.deleteFile(dbFile.getId());
}
…
}
v0.1의 파일 목록/다운로드 기능 구현
public List<CloudFile> getFileInfos(CloudId cloudId) {
CloudFileSystem fileSystem =
CloudFileSystemFactory.getFileSystem(cloudId);
return fileSystem.getFiles();
}
public void download(CloudFile file, File localTarget) {
file.write(new FileOutputStream(localTarget));
}

현재 드롭박스 지원만 구현 된 상태
BOX 클라우드 지원 추가
v0.1의 파일 목록/다운로드 기능 구현
(다시)
public List<CloudFile> getFileInfos(CloudId cloudId) {
CloudFileSystem fileSystem =
CloudFileSystemFactory.getFileSystem(cloudId);
return fileSystem.getFiles();
}
public void download(CloudFile file, File localTarget) {
file.write(new FileOutputStream(localTarget));
}

박스 지원도 반영 (코드 그대로네… 응?)
복잡했던 파일 복사 기능의 변신:
copyFrom(CloudFile file) 추가

public void copy(CloudFile file, CloudId target) {
CloudFileSystem fileSystem =
CloudFileSystemFactory.getFileSystem(target);
fileSystem.copyFrom(file);
}
복잡했던 파일 복사 기능의 변신:
파일시스템 별 copyFrom 메서드
-- DropBoxFileSystem
private DropBoxClient dbClient = new DropBoxClient(...);
public void copyFrom(CloudFile file) {
if (file.hasUrl())
dbClient.copyFromUrl(file.getUrl());
else
dbClient.copyFromInputStream(file.getInputStream(), file.getName());
}
-- NcloudFileSystem
private NcloudClient nClient = new NCloudClient(...);
public void copyFrom(CloudFile file) {
File tempFile = File.createTemp();
file.write(new FileOutputStream(tempFile));
nClient.upload(tempFile, file.getName());
}
추상화를 잘 했더니
public class CloudFileManeger {
public List<CloudFile> getFileInfos(CloudId cloudId) {
CloudFileSystem fileSystem = CloudFileSystemFactory.getFileSystem(cloudId);
return fileSystem.getFiles();
}
public void download(CloudFile file, File localTarget) {
file.write(new FileOutputStream(localTarget));
}
public void copy(CloudFile file, CloudId target) {
CloudFileSystem fileSystem =
CloudFileSystemFactory.getFileSystem(target);
fileSystem.copyFrom(file);
}
…
...
}

추상화된
타입으로만
핵심 기능 구현
가능
추상화를 잘 했더니

새로운
클라우드 지원을
추가
코드
수정없이
이것이 바로 OCP
Open-Closed principle
Open for Extenstion
확장에 열려 있음

Closed for Modification
수정엔 닫혀 있음
추상화를 잘 했더니:
기능이 만들어 짐

•  URL 제공 여부 및 구성 코드가 메서드로 이동
public FileInfo copy(FileInfo fileInfo,
CloudId from, CloudId to) {
if (to == CloudId.DROPBOX) {
DropBoxClient dbClient = …;
if (from == CloudId.BOX) {
dbClient.copyFromUrl(
“http://www.box.com/files/”+
fileInfo.getFileId());
} else if (from == CloudId.SCLOUD) {
ScloudClient sClient = …;
InputStream is = sClient.getInputStream(
fileInfo.getFileId());
dbClient.copyFromInputStream(is,
fileInfo.getName());

-- DropBoxFileSystem
private DropBoxClient dbClient = ...;
public void copyFrom(CloudFile file) {
if (file.hasUrl())
dbClient.copyFromUrl(file.getUrl());
else
dbClient.copyFromInputStream(
file.getInputStream(),
file.getName());
}
이것이 바로 캡슐화Encapsulation

•  내부 구현을 외부에 감춤
o 

내부 구현을 변경해도 이를 사용하는 코드 영향 최소화
-- DropBoxFileSystem
private DropBoxClient dbClient = ...

URL 생성 규칙이 변경되어도
이 코드는 바뀌지 않음

public void copyFrom(CloudFile file) {
if (file.hasUrl())
dbClient.copyFromUrl(file.getUrl());
else
URL 제공 여부가 변경되어도
이 코드는 바뀌지 않음
dbClient.copyFromInputStream(
file.getInputStream(),
file.getName());
}
OCP/캡슐화가 적용된 코드의
1개 클라우드 추가 비용
개발
비용

그냥 막 작성한
코드

OCP/캡슐화 등 좋은
설계를 가진 코드

시간
이것이 객체 지향을 해야하는 이유

비용

(즉, 변경의 유연함)
추상화는 언제?

•  유연함이 필요한 시점(변화가 생기는 시점)
o 
o 

예, 1개 클라우드 지원에서 2개 클라우드로 확장
예, 물류업체 추가

•  아직 구현할 수 없는 부분이 존재할 때
o 

예, 물류 업체와의 연동 프로토콜 미확정
§  물류 시스템 연동을 추상화해서 인터페이스로 표현

•  추상화(모델링)에는 비용이 발생
o 

과도한 추상화(모델링)는 불필요한 복잡도를 증가시킴
정리

•  개발 시간을 줄이기 위해 필요한 것 중 하나,
o 

변화를 수용할 수 있는 설계/구현

o 
o 

변화에 대한 유연함 제공
이는 개발 비용(즉, 시간) 절감 효과!

o 

캡슐화, 추상화, 다형성, SOLID

o 

좋은 코드, 패턴, 테스트 주도 개발, 리팩토링 등

•  잘 된 추상화/캡슐화가 해 주는 것
•  익혀야 할 것 → 객체 지향
•  더불어 익힐 것
참고 서적
감사합니다.
연락은 트위터(@madvirus)
또는 이메일로(madvirus@madvirus.net)

Weitere ähnliche Inhalte

Was ist angesagt?

Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Young-Beom Rhee
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSCirculus
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로Jaeseung Ha
 
Es2015 Simple Overview
Es2015 Simple OverviewEs2015 Simple Overview
Es2015 Simple OverviewKim Hunmin
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린Park JoongSoo
 
Ai C#세미나
Ai C#세미나Ai C#세미나
Ai C#세미나Astin Choi
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개beom kyun choi
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oopYoung-Beom Rhee
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료욱진 양
 
Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Circulus
 
빠르게 활용하는 파이썬3 스터디(ch1~4)
빠르게 활용하는 파이썬3 스터디(ch1~4)빠르게 활용하는 파이썬3 스터디(ch1~4)
빠르게 활용하는 파이썬3 스터디(ch1~4)SeongHyun Ahn
 
헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리은숙 이
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdfHyosang Hong
 
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Circulus
 
프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js functionYoung-Beom Rhee
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crowJaeseung Ha
 
[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow
[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow
[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow정연 최
 

Was ist angesagt? (19)

Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
 
함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
Es2015 Simple Overview
Es2015 Simple OverviewEs2015 Simple Overview
Es2015 Simple Overview
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린
 
Javascript
JavascriptJavascript
Javascript
 
Ai C#세미나
Ai C#세미나Ai C#세미나
Ai C#세미나
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료
 
Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저
 
빠르게 활용하는 파이썬3 스터디(ch1~4)
빠르게 활용하는 파이썬3 스터디(ch1~4)빠르게 활용하는 파이썬3 스터디(ch1~4)
빠르게 활용하는 파이썬3 스터디(ch1~4)
 
헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdf
 
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
 
프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crow
 
[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow
[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow
[새차원, 코틀린(Kotlin) 강좌] 5. Control Flow
 

Mehr von beom kyun choi

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개beom kyun choi
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기beom kyun choi
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나beom kyun choi
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)beom kyun choi
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀beom kyun choi
 
Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugbeom kyun choi
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초beom kyun choi
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유beom kyun choi
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료beom kyun choi
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개beom kyun choi
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해beom kyun choi
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기beom kyun choi
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)beom kyun choi
 
Hive 입문 발표 자료
Hive 입문 발표 자료Hive 입문 발표 자료
Hive 입문 발표 자료beom kyun choi
 

Mehr von beom kyun choi (20)

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)
 
DDD 준비 서문래
DDD 준비 서문래DDD 준비 서문래
DDD 준비 서문래
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀
 
Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksug
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유
 
Spring Boot 소개
Spring Boot 소개Spring Boot 소개
Spring Boot 소개
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
Zookeeper 소개
Zookeeper 소개Zookeeper 소개
Zookeeper 소개
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)
 
Storm 훑어보기
Storm 훑어보기Storm 훑어보기
Storm 훑어보기
 
Hive 입문 발표 자료
Hive 입문 발표 자료Hive 입문 발표 자료
Hive 입문 발표 자료
 
HBase 훑어보기
HBase 훑어보기HBase 훑어보기
HBase 훑어보기
 
Flume 훑어보기
Flume 훑어보기Flume 훑어보기
Flume 훑어보기
 

객체 지향 발담그기 JCO 컨퍼런스 14회

  • 3. 여러 클라우드에 올라간 파일들을 통합 관리하는 앱을 만들어보자. 출처: http://www.flickr.com/photos/42402605@N07/5693120074
  • 4. 빨리 선보이기 위한 최초 0.1 버전 •  대상 클라우드 o  드롭박스, 박스 o  각 클라우드의 목록 조회하기 각 클라우드에서 파일 다운로드 하기 •  주요 기능 o 
  • 5. 파일 정보 표현 public class FileInfo { private CloudId cloudId; private String name; private long length; … // get 메서드 } public enum CloudId { DROPBOX, BOX; }
  • 6. 파일 목록 조회 public List<FileInfo> getFileInfos(CloudId cloudId) { if (cloudId == CloudId.DROPBOX) { DropboxClient dc = …; List<DbFile> dbFiles = db.getFiles(); List<FileInfo> result = new ArrayList<>(); for (DbFile dbFile : dbFiles) { FileInfo fi = new FileInfo(); fi.setCloudId(CloudId.DROPBOX); … result.add(fi); } return result; } else if (cloudId == CloudId.BOX) { BoxService boxSvc = …; … // } }
  • 7. 파일 다운로드 (계속) public void download(FileInfo file, File localTarget) { if (file.getCloudId() == CloudId.DROPBOX) { DropboxClient dc = …; FileOutputStream out = new FileOutputStream(localTarget); dc.copy(file.getFileId(), out); out.close(); } else if (file.getCloudId() == CloudId.BOX) { // TODO } 동작하도록 반영 } public class FileInfo { private CloudId cloudId; private String fileId; private String name; ... for (DbFile dbFile : dbFiles) { FileInfo fi = new FileInfo(); fi.setFileId(dbFile.getId()); fi.setCloudId(cloudId); … }
  • 8. 파일 다운로드 public void download(FileInfo file, File localTarget) { if (file.getCloudId() == CloudId.DROPBOX) { ... } else if (file.getCloudId() == CloudId.BOX) { BoxService boxSvc = …; InputStream is = boxSvc.getInputStream(file.getId()); FileOutputStream out = new FileOutputStream(localTarget); CopyUtil.copy(is, out); } }
  • 9. 야호! •  무사히 동작하는 0.1 버전 완성 •  0.5 버전을 향해 o  기능 확대 §  파일 업로드 §  파일 삭제 §  검색 §  이미지 미리보기
  • 10. 0.5v 기능 추가 public FileInfo upload(File file, CloudId cid) { if (cid == CloudId.DROPBOX) { ... } else if (cid == CloudId.BOX) { ... public void delete(String fileId, CloudId cid) { } if (cid == CloudId.DROPBOX) { } ... } else if (cid == CloudId.BOX) { ... } public List<FileInfo> search(String query, CloudId cid) { } if (cid == CloudId.DROPBOX) { ... } else if (cid == CloudId.BOX) { ... } }
  • 11. 음... •  무사히 동작하는 0.5 버전 완성 •  베타 버전을 향해 o  o  클라우드 추가 §  S클라우드 §  D클라우드 §  N클라우드 §  ... 기능 추가 §  클라우드 간 파일 복사
  • 12. 과정 public FileInfo upload(File file, CloudId cid) { if (cid == CloudId.DROPBOX) { ... } else if (cid == CloudId.BOX) { ... } 코드복사 } public FileInfo upload(File file, CloudId cid) { if (cid == CloudId.DROPBOX) { ... } else if (cid == CloudId.BOX) { ... } else if (cid == CloudId.BOX) { ... } } public FileInfo upload(File file, CloudId cid) { if (cid == CloudId.DROPBOX) { ... } else if (cid == CloudId.BOX) { ... } else if (cid == CloudId.SCLOUD) { ScloudClient scClient = …; ... 구현변경 } } public FileInfo upload(File file, CloudId cid) { if (cid == CloudId.DROPBOX) { ... 조건변경 } else if (cid == CloudId.BOX) { ... } else if (cid == CloudId.SCLOUD) { ... } }
  • 13. 흔한 실수 public List<FileInfo> getFileInfos(CloudId cloudId) { if (cloudId == CloudId.DROPBOX) { … } else if (cloudId == CloudId.BOX) { … } else if (cloudId == CloudId.SCLOUD) { … } else if (cloudId == CloudId.DCLOUD) { … public void delete(String fileId, CloudId cid) { if (cid == CloudId.DROPBOX) { ... return result; } else if (cloudId == CloudId.BOX) { … // } else if (cloudId == CloudId.SCLOUD) { … // alert(“파일이 존재하지 않습니다.”); ... } else if (cloudId == CloudId.DCLOUD) { … fi.setCloudId(CloudId.SCLOUD); … } else if (cloudId == CloudId.NCLOUD) { … } } 음.. 파일이 있는데, 왜 없다 그러지? alert(“파일이 존재하지 않습니다.”); ... } else if (cloudId == CloudId.NCLOUD) { … // } } OO;;
  • 14. 클라우드 간 파일 복사 기능 고려사항 •  URL로부터 복사해서 가져오는 클라우드 존재 o  그런데, URL을 제공하지 않는 클라우드 존재 o  그런데, InputStream을 제공하지 않는 클라우드 존재 •  InputStream을 제공하면 되는 클라우드 존재 •  로컬 File을 제공해야 하는 클라우드 존재
  • 15. 클라우드 간 파일 복사 기능 구현 ... public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) { if (to == CloudId.DROPBOX) { // URL로 복사하기 지원 DropBoxClient dbClient = …; if (from == CloudId.BOX) { dbClient.copyFromUrl(“http://www.box.com/files/”+fileInfo.getFileId()); } else if (from == CloudId.SCLOUD) { ScloudClient sClient = …; InputStream is = sClient.getInputStream(fileInfo.getFileId()); dbClient.copyFromInputStream(is, fileInfo.getName()); } else if (from ==CloudId.DCLOUD) { dbClient.copyFromUrl(“http://www.dcloud.com/getfile?fileId=”+fileInfo.getFileId()); } else if (from == CloudId.NCLOUD) { NCloudClient nClient = …; File temp = File.createTemp(); nClient.save(fileInfo.getFileId(), temp); InputStream is = new FileInputStream(temp); dbClient.copyFromInputStream(is, fileInfo.getName()); } } else if (to == CloudId.BOX) { // 코드 계속 ….
  • 16. 클라우드 간 파일 복사 기능 구현 ... } else if (to == CloudId.BOX) { // URL로 복사하기 지원 BoxService boxService = …; if (from == CloudId.DROPBOX) { boxService.createFileByUrl(“http://www.dropbox.com/box/files/”+fileInfo.getFileId()); } else if (from == CloudId.SCLOUD) { ScloudClient sClient = …; InputStream is = sClient.getInputStream(fileInfo.getFileId()); boxService.uploadFile(is, fileInfo.getName()); } else if (from ==CloudId.DCLOUD) { boxService.createFileByUrl(“http://www.dcloud.com/getfile?fileId=”+fileInfo.getFileId()); } else if (from == CloudId.NCLOUD) { NCloudClient nClient = …; File temp = File.createTemp(); nClient.save(fileInfo.getFileId(), temp); boxService.uploadFile(temp, fileInfo.getName()); } } else if (to == CloudId.SCLOUD) { // 코드 계속 ….
  • 17. 클라우드 간 파일 복사 기능 구현 ... } else if (to == CloudId.SCLOUD) { ScloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.DCLOUD) { // 코드 계속 ….
  • 18. 클라우드 간 파일 복사 기능 코드 (if-else 구조만 표시) public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) { if (to == CloudId.DROPBOX) { // URL로 복사하기 지원 DropBoxClient dbClient = …; if (from == CloudId.BOX) { ... } else if (from == CloudId.SCLOUD) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.BOX) { // URL로 복사하기 지원 BoxService boxService = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.SCLOUD) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.SCLOUD) { ScloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.DCLOUD) { DcloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.SCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.NCLOUD) { NcloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.SCLOUD) { … ... } else if (from == CloudId.DCLOUD) { … ... } } } .
  • 19. 새로운 요구사항 public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) { if (to == CloudId.DROPBOX) { // URL로 복사하기 지원 DropBoxClient dbClient = …; if (from == CloudId.BOX) { ... } else if (from == CloudId.SCLOUD) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.BOX) { // URL로 복사하기 지원 BoxService boxService = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.SCLOUD) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.SCLOUD) { ScloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.DCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.DCLOUD) { DcloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.SCLOUD) { … ... } else if (from == CloudId.NCLOUD) { … ... } } else if (to == CloudId.NCLOUD) { NcloudClient sClient = …; if (from == CloudId.DROPBOX) { … ... } else if (from == CloudId.BOX) { … ... } else if (from ==CloudId.SCLOUD) { … ... } else if (from == CloudId.DCLOUD) { … ... } } 클라우드 10개 추가 } .
  • 20. 1개 클라우드 추가 비용 개발 비용 예전엔 빨리 했는 데…... 시간
  • 22. 개발 시간 증가 이유 •  코드 구조가 길어지고 복잡해짐 o  새로운 클라우드 추가시 모든 메서드에 새로운 if 블록 추가 §  중첩 if-else는 복잡도 배로 증가 §  if-else가 많을수록 진척 더딤 (신중 모드) •  관련 코드가 여러 곳에 분산됨 o  한 클라우드 처리와 관련된 코드가 여러 메서드에 흩어짐 o  코드 추가에 따른 노동 시간 증가 실수하기 쉽고, 이로 인한 불필요한 디버깅 시간 증가 •  결과적으로, 코드 가독성과 분석 속도 저하 o 
  • 26. DROPBOX용 구현 (계속) public class DropBoxFileSystem implements CloudFileSystem { private DropBoxClient dbClient = new DropBoxClient(...); @Override public List<CloudFile> getFiles() { List<DbFile> dbFiles = dbClient.getFiles(); List<CloudFile> results = new ArrayList<>(dbFiles.size()); for (DbFile file : dbFiles) { DropBoxCloudFile cf = new DropBoxCloudFile(file, dbClient); results.add(cf); } return results; }
  • 27. DROPBOX용 구현 public class DropBoxCloudFile implements CloudFile { private DropBoxClient dbClient; private DbFile dbFile; public DropBoxCloudFile( DbFile dbFile, dbClient) { this.dbFile = dbFile; this.dbClient = dbClient; } public String getId() { return dbFile.getId(); } public boolean hasUrl() { return true; } public String getUrl() { return dbFile.getFileUrl(); } public String getName() { return dbFile.getFileName(); } public InputStream getInputStream() { return dbClient .createStreamOfFile(dbFile); } public void write(OutputStream out) { ... } public void delete() { dbClient.deleteFile(dbFile.getId()); } … }
  • 28. v0.1의 파일 목록/다운로드 기능 구현 public List<CloudFile> getFileInfos(CloudId cloudId) { CloudFileSystem fileSystem = CloudFileSystemFactory.getFileSystem(cloudId); return fileSystem.getFiles(); } public void download(CloudFile file, File localTarget) { file.write(new FileOutputStream(localTarget)); } 현재 드롭박스 지원만 구현 된 상태
  • 30. v0.1의 파일 목록/다운로드 기능 구현 (다시) public List<CloudFile> getFileInfos(CloudId cloudId) { CloudFileSystem fileSystem = CloudFileSystemFactory.getFileSystem(cloudId); return fileSystem.getFiles(); } public void download(CloudFile file, File localTarget) { file.write(new FileOutputStream(localTarget)); } 박스 지원도 반영 (코드 그대로네… 응?)
  • 31. 복잡했던 파일 복사 기능의 변신: copyFrom(CloudFile file) 추가 public void copy(CloudFile file, CloudId target) { CloudFileSystem fileSystem = CloudFileSystemFactory.getFileSystem(target); fileSystem.copyFrom(file); }
  • 32. 복잡했던 파일 복사 기능의 변신: 파일시스템 별 copyFrom 메서드 -- DropBoxFileSystem private DropBoxClient dbClient = new DropBoxClient(...); public void copyFrom(CloudFile file) { if (file.hasUrl()) dbClient.copyFromUrl(file.getUrl()); else dbClient.copyFromInputStream(file.getInputStream(), file.getName()); } -- NcloudFileSystem private NcloudClient nClient = new NCloudClient(...); public void copyFrom(CloudFile file) { File tempFile = File.createTemp(); file.write(new FileOutputStream(tempFile)); nClient.upload(tempFile, file.getName()); }
  • 33. 추상화를 잘 했더니 public class CloudFileManeger { public List<CloudFile> getFileInfos(CloudId cloudId) { CloudFileSystem fileSystem = CloudFileSystemFactory.getFileSystem(cloudId); return fileSystem.getFiles(); } public void download(CloudFile file, File localTarget) { file.write(new FileOutputStream(localTarget)); } public void copy(CloudFile file, CloudId target) { CloudFileSystem fileSystem = CloudFileSystemFactory.getFileSystem(target); fileSystem.copyFrom(file); } … ... } 추상화된 타입으로만 핵심 기능 구현 가능
  • 34. 추상화를 잘 했더니 새로운 클라우드 지원을 추가 코드 수정없이
  • 35. 이것이 바로 OCP Open-Closed principle Open for Extenstion 확장에 열려 있음 Closed for Modification 수정엔 닫혀 있음
  • 36. 추상화를 잘 했더니: 기능이 만들어 짐 •  URL 제공 여부 및 구성 코드가 메서드로 이동 public FileInfo copy(FileInfo fileInfo, CloudId from, CloudId to) { if (to == CloudId.DROPBOX) { DropBoxClient dbClient = …; if (from == CloudId.BOX) { dbClient.copyFromUrl( “http://www.box.com/files/”+ fileInfo.getFileId()); } else if (from == CloudId.SCLOUD) { ScloudClient sClient = …; InputStream is = sClient.getInputStream( fileInfo.getFileId()); dbClient.copyFromInputStream(is, fileInfo.getName()); -- DropBoxFileSystem private DropBoxClient dbClient = ...; public void copyFrom(CloudFile file) { if (file.hasUrl()) dbClient.copyFromUrl(file.getUrl()); else dbClient.copyFromInputStream( file.getInputStream(), file.getName()); }
  • 37. 이것이 바로 캡슐화Encapsulation •  내부 구현을 외부에 감춤 o  내부 구현을 변경해도 이를 사용하는 코드 영향 최소화 -- DropBoxFileSystem private DropBoxClient dbClient = ... URL 생성 규칙이 변경되어도 이 코드는 바뀌지 않음 public void copyFrom(CloudFile file) { if (file.hasUrl()) dbClient.copyFromUrl(file.getUrl()); else URL 제공 여부가 변경되어도 이 코드는 바뀌지 않음 dbClient.copyFromInputStream( file.getInputStream(), file.getName()); }
  • 38. OCP/캡슐화가 적용된 코드의 1개 클라우드 추가 비용 개발 비용 그냥 막 작성한 코드 OCP/캡슐화 등 좋은 설계를 가진 코드 시간
  • 39. 이것이 객체 지향을 해야하는 이유 비용 (즉, 변경의 유연함)
  • 40. 추상화는 언제? •  유연함이 필요한 시점(변화가 생기는 시점) o  o  예, 1개 클라우드 지원에서 2개 클라우드로 확장 예, 물류업체 추가 •  아직 구현할 수 없는 부분이 존재할 때 o  예, 물류 업체와의 연동 프로토콜 미확정 §  물류 시스템 연동을 추상화해서 인터페이스로 표현 •  추상화(모델링)에는 비용이 발생 o  과도한 추상화(모델링)는 불필요한 복잡도를 증가시킴
  • 41. 정리 •  개발 시간을 줄이기 위해 필요한 것 중 하나, o  변화를 수용할 수 있는 설계/구현 o  o  변화에 대한 유연함 제공 이는 개발 비용(즉, 시간) 절감 효과! o  캡슐화, 추상화, 다형성, SOLID o  좋은 코드, 패턴, 테스트 주도 개발, 리팩토링 등 •  잘 된 추상화/캡슐화가 해 주는 것 •  익혀야 할 것 → 객체 지향 •  더불어 익힐 것