 |
|
난이도 : 초급 Richard Hightower, CTO, Mammatus Inc.
원문 게재일 : 2009 년 8 월 25 일 번역 게재일 : 2009 년 10 월 06 일 데이터 지속성은 엔터프라이즈 환경에서 확장 가능한 애플리케이션을 전달하기 위해
반드시 갖추고 있어야 하는 능력입니다. Google App Engine for Java™를 소개하는 Rick Hightower의
시리즈 중 마지막 기사인 이 기사에서는 App Engine의 최신 Java 기반 지속성 프레임워크에 대해
설명합니다. 현재 프리뷰 릴리스의 Java 지속성이 아직 충분한 기능을 제공하지 못하는 이유를 살펴본
후 App Engine for Java 애플리케이션의 데이터를 지속적으로 유지하기 위해 수행할 수 있는 작업의
데모를 살펴봅니다. 이 기사에서는 JDO API를 사용하여 Contact 오브젝트를
지속적으로 유지하고, 쿼리하고, 업데이트하고, 삭제하는 방법을 다루므로 Part 2에서
작성한 연락처 관리 애플리케이션이 실행되고 있어야 합니다.
App Engine for Java에서 확장 가능한 웹 애플리케이션을 위한 지속성 계층의 작성과 관련된
문제를 해결하기 위해 노력하고 있기는 하지만 이 목표가 얼마나 달성되고 있을까? 이 기사에서는
JDO(Java Data Objects)와 JPA(Java Persistence API)를 기반으로 작성된 지속성 프레임워크에
대한 개요를 끝으로 App Engine for Java에 대한 소개를 마칠 것이다. 초기의 기대와는 달리 App
Engine의 Java 기반 지속성 기능에는 아직까지 몇 가지 심각한 단점이 남아 있으며 이 기사에서
이러한 단점에 대해 설명하고 그 예를 살펴본다. App Engine for Java 지속성의 작동 방식과 안고
있는 문제점 및 Java 개발자를 위한 Google의 클라우드 플랫폼에서 작업할 때 선택할 수 있는 지속성
옵션에 대해 설명한다.
이 기사를 읽고 예제를 실행해 보는 동안 한 가지 유의해야 할 점은 App Engine for Java가
아직까지는 프리뷰 릴리스라는 점이다. Java 기반 지속성이 현재까지는 사용자의 기대나
요구를 모두 충족하지 못하고 있지만 앞으로 충족될 수 있을 것이며 또 그렇게 되어야 할 것이다. 이
기사를 쓰면서 필자는 보수적인 개발자의 경우 App Engine for Java를 사용하여 확장 가능한 데이터
집약적 Java 애플리케이션을 개발하는 것이 적합하지 않다고 느꼈다. 이 작업은 마치 구조 요원도 보이지
않는 상황에서 수영장의 깊은 곳으로 들어가는 것과 비슷하다. 물 속 깊이 가라앉게 될지 아니면 안전하게
헤엄쳐 나오게 될 것인지 여부가 수영하는 자신에게 달려 있듯이 프로젝트의 성공 여부도 개발자 자신에게 달려
있다.
이 기사의 예제 애플리케이션은 Part 2에서
개발한 연락처 관리 애플리케이션을 기반으로 한다. 이 기사의 예제를 진행하려면 Part 2의 애플리케이션을
빌드하여 실행 가능하게 만들어야 한다.
기본 메커니즘과 추상화 약점
원래의 Google App Engine과 마찬가지로 App Engine for Java 또한 확장 가능한 애플리케이션
개발의 3대 기능인 배포, 복제 및 로드 밸런싱을 지원하는 Google의 내부 인프라를 활용한다. Google
인프라에서 작업하기 때문에 이러한 뛰어난 기능의 대부분은 인식되지 않은 상태에서 수행되며 Java의
표준 기반 API용 App Engine을 통해 액세스할 수 있다. 데이터 저장소 인터페이스는 오픈 소스 DataNucleus
프로젝트를 기반으로 하는 JDO와 JPA를 기반으로 한다. 또한 App Engine for Java는 App Engine for
Java 데이터 저장소를 직접 처리할 수 있는 하위 레벨 어댑터 API도 제공한다. 이 API는 Google의
BigTable 구현을 기반으로 하고 있다. BigTable에 대한 자세한 정보는 Part
1에서 볼 수 있다.
하지만 App Engine for Java 데이터 지속성은 Google App Engine의 지속성과는 달리 약간
복잡하다. BigTable이 관계형 데이터베이스가 아니기 때문에 JDO 및 JPA 인터페이스의 추상화
기능이 강력하지 못하다. 예를 들어, App Engine for Java에서는 조인을 수행하는 쿼리를 수행할
수 없다. JPA와 JDO의 관계를 설정할 수는 있지만 이 또한 관계를 지속적으로 유지하기 위해서만
사용할 수 있다. 그리고 오브젝트의 지속성을 유지할 경우 오브젝트는 같은 엔터티 그룹에 있을
경우에만 같은 원자성 트랜잭션 내에서 지속적으로 유지될 수 있다. 규칙에 따라 소유 관계에 있는
오브젝트 중 하위 오브젝트는 상위 오브젝트와 동일한 엔터티 그룹에 있어야 한다. 이와는 반대로
비소유 관계에 있는 오브젝트는 서로 다른 엔터티 그룹에 속하게 된다.
데이터 정규화에 대한 또 다른 생각
App Engine의 확장 가능한 데이터 저장소를 사용하려면 정규화된 데이터의 장점에 대한 기존
개념을 바꿔야 한다. 물론 실무 경력이 많다면 이미 성능을 위해 정규화를 양보한 경험이 한두
번은 있을 것이다. App Engine 데이터 저장소 작업에서의 차이점은 역정규화를 초기에 종종 수행해야
한다는 것이다. 역정규화는 더 이상 거부해야 하는 단어가 아니다. 도리어 이 단어는 앞으로
App Engine for Java 애플리케이션의 설계 단계에서 주요 개념으로 자주 등장할 것이다.
App Engine for Java의 약한 지속성으로 인한 주요 단점은 RDBMS용으로 작성된 애플리케이션을
App Engine for Java로 이식할 때 드러난다. App Engine for Java 데이터 저장소는 관계형 데이터베이스에
대한 드롭인 대체가 아니기 때문에 App Engine for Java를 사용하여 수행한 작업은 RDBMS 포트로
쉽게 변환할 수가 없다. 기존 스키마를 데이터 저장소에 이식하는 경우는 많지 않다. 레거시 Java
애플리케이션을 App Engine으로 이식하기로 결정한 경우에는 많은 주의를 기울여야 하며 철저한 분석
작업뿐만 아니라 백업도 수행해야 한다. Google App Engine은 특별히 전용 애플리케이션을 위해 설계된
플랫폼이다. Google App Engine for Java의 JDO 및 JPA 지원을 사용하면 비록 정규화되지 엔터프라이즈
애플리케이션이라 하더라도 이러한 애플리케이션을 좀 더 일반적인 방법으로 이식할 수 있다.
관계 관련 문제
현재 프리뷰 릴리스에서 볼 수 있는 App Engine for Java의 또 다른 문제는 관계를 처리하는
방법에 있다. 현재는 관계를 작성하기 위해 JDO에 대한 App Engine for Java 관련 확장을 사용해야
한다. BigTable의 아티팩트를 기반으로 키가 생성되므로(즉, "기본 키"에는 모든 하위 오브젝트에
인코딩되는 상위 오브젝트 키가 있으므로) 사용자가 비관계형 데이터베이스의 데이터를 관리해야
한다. 데이터의 지속성을 유지해야 한다는 점도 또 다른 제한이다. 비표준 AppEngine for Java
Key 클래스를 사용하면 복잡한 문제가 발생한다. 먼저 모델을 RDBMS로
이식할 때 비표준 Key를 사용할 수 있는 적절한 방법이 없다. 둘째, GWT
엔진에서 Key 클래스를 변환할 수 없기 때문에 이 클래스를 사용하는 모델
오브젝트를 GWT 애플리케이션에서 사용할 수 없다.
물론 이 기사를 쓰던 당시에는 Google App Engine for Java가 프리뷰 모드로 제공되고 있었기
때문에 서비스가 정상적으로 제공되는 상황은 아니었다. JDO의 관계에 대한 설명서를 보면 명확하게
알 수 있을 것이다. 하지만 이 설명서는 흔하지도 않을 뿐만 아니라 불완전한 예제가 들어 있다는
점이 아쉬운 부분이다.
App Engine for Java 개발 킷에는 여러 가지 예제 프로그램이 들어 있다. 이들 중 많은 예제에서는
JDO를 사용하고 있으며 JPA를 사용하는 예제는 없다. 그리고 jdoexamples를 포함한 그 어떤 예제에도
단순한 관계로 구성된 단일 예제가 없다. 대신 모든 예제에서는 단 하나의 오브젝트를 사용하여 데이터
저장소에 데이터를 저장한다. Google App Engine for Java 토론 그룹에는
단순한 관계를 사용하는 방법에 대한 많은 질문과 소수의 답변이 올라와 있다. 일부 개발자의 경우 관계에
대한 문제를 해결한 것이 분명하지만 그 과정이 복잡하고 많은 노력이 필요하다는 것을 알 수 있다.
App Engine for Java에서의 관계에 대한 결론은 결국 JDO 또는 JPA의 지원이 충분하지 못하기
때문에 사용자가 관계를 관리해야 한다는 것이다. 하지만 Google의 BigTable은 확장 가능한 애플리케이션을
개발하는 데 적합한 검증된 기술이기에 이 기술을 기반으로 많은 작업을 수행할 수 있다. BigTable을
사용할 경우에는 완성도가 낮은 API를 다루지 않아도 된다. 그에 반해 하위 레벨 API를 다루어야 한다는
점도 간과해선 안된다.
AppEngine for Java의 JDO(Java Data Objects)
기존 Java 애플리케이션을 App Engine for Java로 이식할 수 없고 심지어 관계로 인해 문제가
있는 경우라도, 이 플랫폼을 사용할 수 있는 지속성 시나리오가 여전히 존재한다. 이제 마지막으로
App Engine for Java 지속성의 작동 방법을 경험할 수 있는 작업 예제를 살펴보자. 먼저
Part 2에서
작성한 연락처 관리 애플리케이션부터 시작하자. 여기에서는 App Engine for Java 데이터
저장소 기능을 사용하여 Contact 오브젝트의 지속성을 유지하기
위한 지원을 추가하는 절차에 대해 설명한다.
이전 기사에서는 Contact 오브젝트에 대해 CRUD 작업을 수행하는
간단한 GWT GUI를 작성하면서 Listing 1과 같은 간단한 인터페이스를 정의했다.
Listing 1. 간단한 ContactDAO 인터페이스
package gaej.example.contact.server;
import java.util.List;
import gaej.example.contact.client.Contact;
public interface ContactDAO {
void addContact(Contact contact);
void removeContact(Contact contact);
void updateContact(Contact contact);
List<Contact> listContacts();
}
|
그런 다음 Listing 2와 같이 메모리 내 컬렉션의 데이터에 대한 작업을 수행하는 모의 버전을 작성했다.
Listing 2. DAO를 모방한 ContactDAOMock
package gaej.example.contact.server;
import gaej.example.contact.client.Contact;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ContactDAOMock implements ContactDAO {
Map<String, Contact> map = new LinkedHashMap<String, Contact>();
{
map.put("rhightower@mammatus.com", new Contact("Rick Hightower",
"rhightower@mammatus.com", "520-555-1212"));
map.put("scott@mammatus.com", new Contact("Scott Fauerbach",
"scott@mammatus.com", "520-555-1213"));
map.put("bob@mammatus.com", new Contact("Bob Dean",
"bob@mammatus.com", "520-555-1214"));
}
public void addContact(Contact contact) {
String email = contact.getEmail();
map.put(email, contact);
}
public List<Contact> listContacts() {
return Collections.unmodifiableList(new ArrayList<Contact>(map.values()));
}
public void removeContact(Contact contact) {
map.remove(contact.getEmail());
}
public void updateContact(Contact contact) {
map.put(contact.getEmail(), contact);
}
}
|
이제 모의 구현을 Google App Engine 데이터 저장소와 통신하는 버전의 애플리케이션으로 바꾸면
어떻게 되는지 살펴보자. 이 예제에서는 JDO를 사용하여 Contact 클래스의
지속성을 유지한다. Google Eclipse Plugin을 사용하여 작성된 애플리케이션에는 이미 JDO를 사용하는
데 필요한 모든 라이브러리가 포함되어 있으며 jdoconfig.xml 파일도 포함되어 있다. 따라서 Contact
클래스에 어노테이션을 지정하기만 하면 JDO를 사용할 준비가 완료된다.
Listing 3에서는 JDO API를 사용하여 오브젝트를 지속적으로 유지하고, 쿼리하고, 업데이트하고,
삭제할 수 있도록 확장된 ContactDAO 인터페이스를 보여 준다.
Listing 3. JDO를 사용하는 ContactDAO
package gaej.example.contact.server;
import gaej.example.contact.client.Contact;
import java.util.List;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
public class ContactJdoDAO implements ContactDAO {
private static final PersistenceManagerFactory pmfInstance = JDOHelper
.getPersistenceManagerFactory("transactions-optional");
public static PersistenceManagerFactory getPersistenceManagerFactory() {
return pmfInstance;
}
public void addContact(Contact contact) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
try {
pm.makePersistent(contact);
} finally {
pm.close();
}
}
@SuppressWarnings("unchecked")
public List<Contact> listContacts() {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
String query = "select from " + Contact.class.getName();
return (List<Contact>) pm.newQuery(query).execute();
}
public void removeContact(Contact contact) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
try {
pm.currentTransaction().begin();
// We don't have a reference to the selected Product.
// So we have to look it up first,
contact = pm.getObjectById(Contact.class, contact.getId());
pm.deletePersistent(contact);
pm.currentTransaction().commit();
} catch (Exception ex) {
pm.currentTransaction().rollback();
throw new RuntimeException(ex);
} finally {
pm.close();
}
}
public void updateContact(Contact contact) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
String name = contact.getName();
String phone = contact.getPhone();
String email = contact.getEmail();
try {
pm.currentTransaction().begin();
// We don't have a reference to the selected Product.
// So we have to look it up first,
contact = pm.getObjectById(Contact.class, contact.getId());
contact.setName(name);
contact.setPhone(phone);
contact.setEmail(email);
pm.makePersistent(contact);
pm.currentTransaction().commit();
} catch (Exception ex) {
pm.currentTransaction().rollback();
throw new RuntimeException(ex);
} finally {
pm.close();
}
}
}
|
메소드
이제 Listing 3의 각 메소드에서 어떤 작업이 수행되는지 살펴보자. 메소드 이름이 낯설 수도
있겠지만 메소드에서 수행되는 작업은 거의 대부분 익숙할 것이다.
먼저 PersistenceManager에 액세스하기 위해 정적 PersistenceManagerFactory를
작성했다. 이전에 JPA로 작업했다면 PersistenceManager는 JPA의 EntityManager와
유사하다. Hibernate로 작업했다면 PersistenceManager는 Hibernate Session과 비슷하다. 기본적으로
PersistenceManager는 JDO 지속성 시스템에 대한 기본 인터페이스로 데이터베이스에 대한 세션을
나타낸다. getPersistenceManagerFactory() 메소드는 Listing 4와 같이 정적으로 초기화된
PersistenceManagerFactory를 리턴한다.
Listing 4. PersistenceManagerFactory를 리턴하는 getPersistenceManagerFactory()
private static final PersistenceManagerFactory pmfInstance = JDOHelper
.getPersistenceManagerFactory("transactions-optional");
public static PersistenceManagerFactory getPersistenceManagerFactory() {
return pmfInstance;
}
|
addContact() 메소드는 데이터 저장소에 새 연락처를 추가한다. 이 작업을
수행하기 위해 이 메소드는 PersistenceManager 인스턴스를 작성한 다음
PersistenceManager의 makePersistence() 메소드를
호출해야 한다. makePersistence() 메소드는 비어 있는 Contact
오브젝트(사용자가 GWT GUI를 통해 해당 정보를 입력함)를 받아서 지속성 오브젝트로 설정한다. Listing 5에서는
이 모든 작업을 보여 준다.
Listing 5. addContact()
public void addContact(Contact contact) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
try {
pm.makePersistent(contact);
} finally {
pm.close();
}
}
|
Listing 5를 보면 persistenceManager가 finally 블록에
포함되어 있는 것을 볼 수 있다. 이 코드는 persistenceManager에 연결된 리소스를 정리하기
위한 것이다.
Listing 6의 listContact() 메소드는 persistenceManager로부터
검색을 수행할 쿼리 오브젝트를 작성한다. 그런 다음 execute() 메소드를 호출하면 데이터 저장소에
있는 Contact의 목록이 리턴된다.
Listing 6. listContact()
@SuppressWarnings("unchecked")
public List<Contact> listContacts() {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
String query = "select from " + Contact.class.getName();
return (List<Contact>) pm.newQuery(query).execute();
}
|
Listing 7의 removeContact() 메소드는 ID를 기준으로 연락처를 검색한 후
dataStore에서 해당 연락처를 제거한다. 하지만 GWT GUI에서 가져온 Contact는
JDO를 알지 못하므로 연락처를 직접 삭제해서는 안되며 PersistenceManager
캐시에 연관된 Contact를 가져와야만 삭제할 수 있다.
Listing 7. removeContact()
public void removeContact(Contact contact) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
try {
pm.currentTransaction().begin();
// We don't have a reference to the selected Product.
// So we have to look it up first,
contact = pm.getObjectById(Contact.class, contact.getId());
pm.deletePersistent(contact);
pm.currentTransaction().commit();
} catch (Exception ex) {
pm.currentTransaction().rollback();
throw new RuntimeException(ex);
} finally {
pm.close();
}
}
|
Listing 8의 updateContact() 메소드는 removeContact()
메소드와 마찬가지로 Contact를 검색한다. 그런 다음 updateContact()
메소드는 Contact의 특성을 복사한다. 이러한 특성은 Contact에
대한 인수로 전달된 후 PersistenceManager를 통해 검색된다. 그런 다음 PersistenceManager는
검색된 오브젝트의 변경 여부를 확인한다. 오브젝트가 변경되었으면 트랜잭션이 커미트될 때 PersistenceManager가
데이터베이스에 변경 사항을 적용한다.
Listing 8. updateContact()
public void updateContact(Contact contact) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
String name = contact.getName();
String phone = contact.getPhone();
String email = contact.getEmail();
try {
pm.currentTransaction().begin();
// We don't have a reference to the selected Product.
// So we have to look it up first,
contact = pm.getObjectById(Contact.class, contact.getId());
contact.setName(name);
contact.setPhone(phone);
contact.setEmail(email);
pm.makePersistent(contact);
pm.currentTransaction().commit();
} catch (Exception ex) {
pm.currentTransaction().rollback();
throw new RuntimeException(ex);
} finally {
pm.close();
}
}
|
오브젝트 지속성에 대한 어노테이션
Contact를 지속적으로 유지하기 위해서는 @PersistenceCapable
어노테이션을 사용하여 지속 가능한 오브젝트로 식별해야 한다. 그런 다음 Listing 9와 같이 지속 가능한 모든
필드에 어노테이션을 지정해야 한다.
Listing 9. 지속 가능한 Contact
package gaej.example.contact.client;
import java.io.Serializable;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Contact implements Serializable {
private static final long serialVersionUID = 1L;
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
@Persistent
private String name;
@Persistent
private String email;
@Persistent
private String phone;
public Contact() {
}
public Contact(String name, String email, String phone) {
super();
this.name = name;
this.email = email;
this.phone = phone;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
|
오브젝트 지향 프로그래밍의 특성과 인터페이스별 설계의 원칙에 따라 원래의 ContactDAOMock을
새 ContactJdoDAO로 바꿀 수 있다. 그러면 변경 없이도 GWT GUI가 JDO와 정상적으로 작동한다.
마지막으로 이렇게 변경하고 나면 DAO가 서비스에서 인스턴스화되는 방법이 Listing 10처럼 바뀌게 된다.
Listing 10. RemoteServiceServlet
public class ContactServiceImpl extends RemoteServiceServlet implements ContactService {
private static final long serialVersionUID = 1L;
//private ContactDAO contactDAO = new ContactDAOMock();
private ContactDAO contactDAO = new ContactJdoDAO();
...
|
결론
이 세 번째 기사에서는 확장 가능한 애플리케이션 전달을 위한 초석의 하나인 지속성 기능이
현재 Google App Engine for Java에서 지원되는 모습을 살펴보았다. 발전을 거듭하고 있는 플랫폼인
점을 감안하더라도 전반적으로 기대에 미치지 못한다는 느낌을 받았다. App Engine for Java 프리뷰
릴리스용으로 작성된 애플리케이션은 JDO 또는 JPA를 사용할 수 있기는 하지만 아직까지는 App Engine의
지속성 인프라에 대한 의존도가 너무 높은 편이다. 프리뷰 버전의 App Engine for Java에는 지속성
프레임워크에 대한 설명서가 거의 없으며 App Engine for Java와 함께 제공되는 예제를 사용하여 아주
단순한 관계를 구현하는 것마저도 거의 불가능하다.
JDO 및 JPA 구현의 완성도가 높아졌다고는 하지만 아직까지는 App Engine for Java 애플리케이션을
작성해서 RDBMS 기반 엔터프라이즈 애플리케이션으로 쉽게 이식할 수 있는 단계까지는 도달하지 못했다. 적어도
이식 작업을 수행하기 위한 복잡한 코딩 작업이 필요하다.
지속성 기능은 시간이 지나면서 완성된 모습을 갖추게 될 것이다. 그러나 지금 당장 App Engine
for Java로 작업해야 한다면 이 Java API를 무시하고 하위 레벨 Datastore API를 직접 사용하는
것이 좋다. App Engine for Java 플랫폼으로 작업할 수 있지만 JPA 및/또는 JDO 작업에 익숙해서 이들
API를 사용하려고 한다면 필요한 기능을 익히는 데 시간이 필요할 것이다. 왜냐하면 이 기사의 시작
부분에서 언급했듯이 추상화 기능이 강력하지 않을 뿐만 아니라 해당 기능이 정상적으로 작동하지 않을
수도 있고 기능에 대한 설명도 부족하기 때문이다.
참고자료 교육
- "Google App Engine for Java,
Part 1: 새로운 시작"(Rick Hightower 저, developerWorks, 2009년 8월): Google Plugin for Eclipse에
대해 설명한 후 확장 가능한 애플리케이션을 빠르게 개발하는 방법에 대해 살펴본다.
- "Google App Engine for Java,
Part 2: 킬러 애플리케이션 작성하기"(Rick Hightower 저, developerWorks, 2009년 8월): 연락처 관리 애플리케이션을 위한
사용자 정의 GWT GUI를 작성하는 간단한 튜토리얼을 통해 App Engine으로 구현할 수 있는 기능을 간단히 살펴본다. 두 번째 기사의
예제는 이 세 번째 기상의 예제를 완성하기 위한 전제 조건이다.
- "클라우드에 연결하기,
Part 1: 애플리케이션에서 클라우드 활용하기"(Mark O'Neill 저, developerWorks, 2009년 4월): 세 편의 기사를 통해 주요 공급자(Amazon,
Google, Microsoft® 및 SalesForce.com)의 클라우드 컴퓨팅 플랫폼에 대한 개요를 살펴본다.
-
Google IO
video session: The softer side of schemas: Google 엔지니어인 Max Ross가 JDO 및 JPA
표준을 사용하여 Google App Engine 데이터 저장소와 통신하는 방법을 설명한다.
-
JDO Tutorial, the Apache DB Project: 간단한
애플리케이션 시나리오에서
ObjectRelationalBridge와 JDO API를 사용하는 방법에 대해 설명한다.
-
BigTable이란?: Google Research Publications에서 제공하는 BigTable에 대한 정보를 읽어보자.
-
The DataNucleus Project: Java 프로그래밍 언어를 사용하여
데이터 관리와 관련된 여러 가지 소프트웨어 제품을 제공하는 오픈 소스 프로젝트로 이전에는 JPOX(Java
Persistent Objects)였다.
-
Google App Engine 홈 페이지: 플랫폼에 대한 자세한 정보를 볼 수 있다.
-
Google App Engine Java 설명서: App Engine을 이용한 Java 개발에 유익한 정보를 제공한다.
-
Will it play in App Engine?:
App Engine과 호환되는 표준 Java API 및 프레임워크를 확인할 수 있다.
-
기술 서점에서
다양한 기술 주제와 관련된 서적을 살펴보자.
-
developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자.
제품 및 기술 얻기
토론
필자소개  | |  | Rick Hightower는 클라우드 컴퓨팅, GWT, Java EE, Spring 및 Hibernate 개발과 관련된
교육 서비스를 전문으로 제공하는 회사인 Mammatus Inc.의
CIO이다. 유명한 Java Tools for Extreme Programming의 공동 저자이며 TheServerSide.com에서
여러 해 동안 다운로드 수가 가장 높았던 Struts Live 초판의 저자이다. IBM developerWorks에
많은 기사와 튜토리얼을 기고하고 있는 그는 Java Developer's Journal의 편집위원으로 활동하고 있으며
DZone에도 Java 및 Groovy와 관련된 많은 글을 기고하고 있다. |
기사에 대한 평가
 |
| 이 문서 북마킹 하기
|
|