긴 클래스 이름

feanor의 이미지

Spring Framework에는 transactionawarepersistencemanagerfactoryproxy라는 클래스가 있습니다.

http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/orm/jdo/TransactionAwarePersistenceManagerFactoryProxy.html

이, 이것은 무슨 주문 같군요.

댓글

송효진의 이미지

CamelCase 로 안써주면 주문이 되겠죠~

emerge money
http://wiki.kldp.org/wiki.php/GentooInstallSimple - 명령어도 몇 개 안돼요~
http://xenosi.de/

emerge money
http://wiki.kldp.org/wiki.php/FuntooInstallLog - 명령어도 몇 개 안돼요~
http://xenosi.de/

creativeidler의 이미지

long name 자체는 accoutable하기만 하다면 나쁜 것이 아니고, 저 이름은 이름만으로도 뭐 하는 클래스인지 알 수 있을 만큼 충분히 accountable합니다. 그러나, 반대로 필요 이상으로 복잡한 아키텍처를 대변해주고 있기도 하죠. good naming, but bad name이랄까요.

TransactionAwarePersistenceManagerFactoryProxy

트랜잭션을 처리할 수 있는 퍼시스턴스 관리자를 만들어주는 대리자...인 셈인데.. 어떤 요구 때문에 저런 구조가 되었는지 짐작도 가고 사실 저런 구조로 설계를 하기 시작하면 필연적인 귀결이기도 합니다만, 설계 방향을 조금 더 앞에서 비틀었다면 저렇게까지는 안되었을 겁니다.

인지적으로도 저런 이름은 좋지 않습니다. 사람이 자연스럽게 한 라인에서 인지할 수 있는 token의 개수는 10개 정도입니다. 물론, 단어는 다 token이죠. 그런데 클래스 이름에서 6개의 token을 먹어버리면 getPersistanceManagerFactory 같은 함수 하나 호출하면서 선언을 하는 순간 변수명, = 포함 12개의 token이 되버리죠. 인자라도 받는다면 token 수는 더 늘어납니다.

80자 라인이 아직도 중요하다면 그 이유는 프린터가 아니라 우리의 뇌 구조일 겁니다.

fender의 이미지

순수한 궁금증입니다만, 설계를 앞단에서 어떤 식으로 바꾸었으면 TransactionAwarePersistenceManagerFactoryProxy 같은 구조가 안나올 수 있었을까요?

스프링에 너무 익숙해서 그런지 불필요한 복잡성이라고 생각이 들지 않고, 딱히 다른 대안이 쉽게 머리에 떠오르지 않아서 질문 드려 봅니다. 이름이 긴 것 같지만 어차피 퍼시스턴스 API를 다루는 개발자가 사용하는 클래스라면 PersistenceManagerFactory가 무엇인지는 이미 알고 있을 것이고, 그렇다면 그냥 해당 클래스의 스프링 트랜잭션에 통합된 프록시를 반환한다고 바로 이해될 수 있지 않을까요?

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

creativeidler의 이미지

우선, 한 가지 오해가 있는 것 같은데, 저는 저 이름 자체가 문제라고 보지 않습니다. 코드에서 이름의 역할은 설계자의 의도를 드러내는 것이고 저 이름은 그 역할을 충실히 하고 있습니다. 저 클래스가 무슨 역할인지 이해하는데는 아무런 어려움이 없을 겁니다. 그래서 good naming이라고 한 것이구요. 하지만 이름 자체가 너무 길다는 것 때문에 약간의 악영향이 있는데 사실 그 악영향은 그보다 더 깊은 설계 문제의 증상이라고 보기 때문에 bad name이라고 한 것입니다.

그리고, 앞단이라고 이야기한 것은 PersistenceManagerFactory부분까지 포함하는 것입니다. 즉, 퍼시스턴스 API까지 다른 방향으로 설계를 했어야 한다는 것이죠. 제가, 저렇게 설계하면 필연적인 귀결이라고 한 것도 그 이야기입니다.

설계를 비틀면 될 것 같다는 것은 일단은 그냥 직관에서 한 이야기입니다. 실용적인 개선 제안까지 하려면 좀더 체계적인 분석이 필요할 것 같구요. 제가 요즘은 자바에서 멀어져 있는 상태라서 그 정도의 의지는 없습니다만, 원론적인 이야기는 몇 가지 할 수 있을 것 같습니다.

일단, 이런 설계는 흔하게 보이며, 같은 문제를 해결하는 다른 대안 설계가 여러 가지 존재합니다. 물론 스프링 프레임웍을 좋아하는 사람들은 대개 그런 것들은 대안이 아니라고 말하는 것을 많이 보아왔습니다만, 어쨋든 중요한 건 데이터를 DB에서 뽑아와서 뿌려주는 걸 제대로 해내면 되는 거 아니냐는 관점에 있는 사람들도 있습니다. 이미 예~~전에도 fender님과 이 비슷한 논쟁을 한 적이 있었던 걸로 기억합니다. 굳이 그게 아니라도 커뮤니티에서 이런 관점 간의 논쟁이 치열하고 아직 누가 그 논쟁에서 이겨가고 있는 것 같진 않아서 이런 식으로는 더 언급하기 두렵습니다.

그래서, 조금 다른 관점으로 보자면, Manager, Factory, Proxy 세 가지 패턴에 대한 이야기를 할 수 있을 듯 합니다. 세 가지 패턴 모두 비슷한 역할을 합니다. 뭔가를 대리하는 것이죠. Manager는 보통 어떤 객체의 data에 대한 CRUD를 대리하는 경우가 많고 Factory는 생성을 대리하며, Proxy는 consumer의 요구에 따라 객체 전체, 혹은 객체의 일부를 대리합니다. 세 패턴 모두 조금 더 높은 유연성을 확보하는 대가로 조금씩 더 복잡해집니다.

XML 파서를 예로 든다면, DocumentBuilderFactory로 DocumentBuilder를 생성하고 DocumentBuilder로 parse를 해서 Document를 생성해내는 방식을 쓰면 다양한 파서를 쓸 수 있고 파싱 옵션 등을 쉽게 조정할 수 있다는 유연성이 있습니다. 하지만 코드가 좀 복잡해지겠죠. 대신에 그냥 파서 하나 지정해서 new Document()를 해버리면 이런 유연성에 제약을 받는 대신 코드가 더 쉬워집니다.

그런데 이 클래스는 비슷한 성격의 패턴을 세 개나 쓰고 있어서 유연성은 그만큼 높아졌지만 그 대가로 구조가 세 배는 복잡해진 것입니다. 근데, 실제로 비즈니스의 요구사항이 너무나 복잡해서 그런 유연성이 필요하다면 어쩔 수 없습니다. 다만, 여기서 정말로 그 정도의 유연성이 필요한가? 하는 질문을 던져봐야 한다는 것입니다.

덧붙이자면, 사실 Manager는 다소 반 OOP적인 패턴이라고 봅니다. 제대로 연구된 바도 없는 약간 ad-hoc스러운, 그러나 아주아주 널리 쓰이는 패턴이죠. 저도 설계를 하다가 어딘가에 Manager란 이름이 붙는 클래스를 만들어야 할 것 같은 느낌이 들면 설계를 재검토하곤 합니다.

사실 주저리주저리 늘어놓긴 했지만 공감을 얻을 수 있을지는 모르겠군요.

fender의 이미지

하도 요즘에 열띈(?) 토론이 많다보니 서로 답글 달기가 부담이 되는 듯 하네요 ㅎㅎ;

아무튼 충분한 답변이 되었습니다 ^^;; 저는 TransactionAware*Proxy라는 네이밍이 나오게된 설계 자체는 그닥 문제될 것이 없다고 보았고 creativeidler님께서는 오히려 스프링이 아닌 JDO의 PersistenceManagerFactory까지 포괄해서 원론적인 말씀을 하신 것 같군요.

사실 프록시와 AOP등을 통해 트랜잭션등을 자동적으로 통합해주는 것은 어떤 불가피한 꽁수라기 보다는 가장 '스프링스러운' 고안의 하나라고 생각하고 있었습니다. 예컨대 문제가 되는 요구사항을 '어떻게 하면 다양한 써드파티 API 등을 연결해 쓰면서 복잡한 코딩없이도 일관된 방법으로 트랜잭션, 보안, 원격연결을 쉽게 통합할 수 있는가?'로 본다면 이러한 방식은 독창적이진 않을지 몰라도 상당히 효율적인 접근이 아닌가 싶습니다. 그래서 creativeidler님께서 혹시 어떤 다른 방식의 더 나은 설계를 알고 계신 것이 아닌가 해서 궁금증이 들었던 것입니다.

만일 지적하신 부분이 원론적 차원에서 '과연 Proxy 패턴이 유효한가', 혹은 과연 'JDO 같은게 꼭 필요한가?' 같은 질문이 된다면 아무래도 우려하신 것처럼 이보단 훨씬 길고긴 토론이 될지도 모르겠습니다. 일단 제가 궁금해하고 있는 그 부분과 다른 측면의 문제를 말씀하셨다는 사실을 확인한 것으로 제 의문은 충분히 해결이 되었습니다. 단지 첨언하고 싶은 건 'manager, factory, proxy 셋다 유연성과 복잡성을 트레이드오프하는 패턴인데 문제의 클래스는 세가지를 다 쓰고 있으니 구조가 세 배는 복잡해지는 것 아닌가?'라는 지적은 조금 지나치게 원론적인 차원의 지적인 듯 하긴 합니다.

TransactionAwarePersistenceManagerFactoryProxy를 예로들어 조금 구체적으로 살펴본다면,

(1) 'factory' 패턴이 정말 필요한가? - 사실 팩토리 패턴 같이 흔히 쓰이는 패턴을 개발자들이 습득하고 이해하는 복잡도를 우려해야한다면 어쩌면 '과연 객체지향 프로그램이 필요한가?'까지로 확장될 수 있는 질문이라고 생각합니다. 이 경우 factory가 없었다면 Persistence API라는 공통 스펙이 있고 이에 대한 다양한 프로바이더를 플러그인 가능한 형태로 찾아쓰는 방식은 불가능하거나 다른 더 복잡한 형식으로 구현해야 했을 것입니다.

예로드신 XML파서의 경우도 동일한 상황입니다만, 사실 개발자가 원한다면 DocumentBuilderFactory 대신 그냥 구체적인 DocumentBuilder 클래스 이름을 찾아서 new로 생성할 수도 있을 것입니다. 하지만 DocumentBuilderFactory.newDocumentBuilder()를 하는 대신 팩토리 클래스를 하나 없애고 예컨대 개발자가 직접 org.apache.xerces.jaxp.DocumentBuilderImpl 클래스를 찾아서 new를 한다고 해서 복잡도를 제거한다는 측면에서 의미있는 결과가 생긴다고 보긴 어려울 듯합니다. 대신 유연성이 떨어지는 단점은 상대적으로 명확하게 보이는 듯합니다.

(2) 'proxy' 패턴이 필요한가? - 이 경우에 프록시 패턴을 쓰지 않는다면, 스프링이 지향하는 투명하게 일관된 방식으로 트랜잭션/보안/원격연결 등을 통합한다는 기능구현 자체가 불가능했을 것입니다. 물론 트랜잭션 통합 이슈 하나만 본다면 JDO 자체의 API를 잘 이용하면 프록시 없이 충분히 해결할 수 있었을 것입니다. 하지만 이미 객체지향 개발을 하고 있는 개발자 입장에서 '프록시'라는 개념이나 이름이 주는 복잡함을 없애기 위해 일관된 방식의 트랜잭션 통합 같은 기능을 포기한다면 득보단 실이 훨씬 많을 것으로 생각합니다.

만일 프록시 대신 JDO 자체 API를 통해 트랜잭션을 통합했다면 아마도 JDO가 아닌 다른 ORM API를 쓰는 경우나 직접 JDBC호출을 하는 경우 등에 대해 모두 다른 방식의 접근이 필요했을 것이고 경우에 따라선 구조적으로 코딩없는 통합 자체가 불가능한 경우도 나올 수밖에 없을 것으로 봅니다.

더구나 스프링의 경우 '프록시 패턴을 쓴다'라는 것이 직접 프록시 패턴을 이해하고 이를 적용한 코딩을 하라는 것이 아니라 이미 제공되는 클래스를 컨벤션에 따라 xml 등에 선언하라는 것이니만큼 그 작업이 너무 복잡해서 예컨대 직접 트랜잭션을 코딩으로 일일이 처리하겠다라는 식의 접근이 유효할 것 같지는 않습니다.

(3) 'manager' 패턴(?)이 필요한가? - 앞선 두 가지 경우가 객체지향적 패턴의 사용이 가져오는 복잡성에 대한 지적이라면 오히려 이 경우는 편의성을 위해 어느 정도 객체지향적 접근을 희생하는 패턴에 대한 지적이 될 것 같습니다. *Manager에 대한 지적 자체는 저 역시 적극 공감하고 있는 부분입니다. 사실 지금 프로젝트에도 수십개의 *Manager가 널려있는 판이라 항상 눈엣가시같이 여기고 있었습니다 ㅎㅎ;

아무튼, 오히려 앞선 두가지의 지적이 조금이라도 의미가 있다면 어쩌면 PersistenceManager 같이 편이를 위해 일반적인 오퍼레이션들을 위임해놓은 식의 구현은 복잡도를 줄이기 위한 패턴이지 늘이기 위한 패턴은 아니라고 생각합니다. 만일 PersistenceManager에 정의된 해당 메소드들이 객체지향적으로 좀더 엄격하게 각각의 의미있는 클래스로 분산되어 설계되었다면 'manager'라는 이름을 쓰지 않는 편리함(?)은 얻을 수 있겠지만 구현이나 사용 측면에서는 지금보단 훨씬 복잡한 모습이 되었을 것으로 생각합니다.

이런 관점에서 본다면 프록시나 팩토리, 매니저 등을 이름에 사용하기 때문에 얻는 복잡성 보다는 해당 패턴들로 인해 해결되는 복잡성이나 확보되는 유연성이 더욱 의미가 있다고 느껴집니다.

물론 더 원론적으로 '객체지향이 정말 필요한가?', 'JDO 같은 것이 필요한가?', '트랜잭션은 꼭 통합해야 하는가?'와 같은 질문을 이어간다면 그 부분에 대해선 훨씬 더 길고 원론적인 토론이 필요할지 모르겠습니다.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

creativeidler의 이미지

factory 패턴에 문제가 있다는 것이 factory 패턴이 나쁘다거나, factory 패턴은 써서는 안된다는 얘기가 아닙니다. 물론, manager는 꼭 필요한 경우가 아니면 안 쓰는 게 좋다고 보지만 factory는 자바 같은 언어에서는 어쩔 수 없는 경우도 많으니까요. 이 이야기는 단순히 장단점이 있다는 이야기가 아니고 trade-off를 잘 계산해서 장점이 더 큰 경우에만 적용해야 한다는 뜻입니다. 아시다시피 패턴은 context-free rule이 아닙니다. factory 패턴의 trade-off는 고정불변이 아니고 상황에 따라서 장점이 더 클 수도, 단점이 더 클 수도 있습니다. 말하자면, factory 패턴이 늘 나쁘다는 게 아니고 저 클래스가 해결하려는 문제에 한정된 특수한 상황에서 bad choice처럼 보인다는 것입니다.

DocumentBuilderFactory 같은 경우도 factory 패턴의 오용 사례로 자주 꼽힙니다. 오죽하면 아예 JAXP의 대안을 만든 사람들이 그렇게 많겠습니까. JDOM에서는 그냥 new Document()로 생성하기도 하는데 그로 인해서 현실적으로 잃는 가치는 거의 없습니다. 그러면서 훨씬 간결한 문법으로 더 많은 기능을 지원할 수 있게 되었죠.

bad smell이라는 관점에서 봐도 JAXP를 사용한 코드는 문제가 있습니다. JAXP를 쓰는 방식은 다음과 같은데...

DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

이런 식의 코드는 message chain으로 잘 알려져 있는 smell을 발생시킵니다. 물론 저기서 중간 객체를 변수로 받으면 겉으로는 message chain이 아닌 것처럼 보이게 할 수 있고, 덤으로 옵션도 조정할 수 있겠지만 원칙적으로는 같은 smell이 발생하는 것이죠. 물론 extract method를 활용하면 일단은 해결이 되겠지만 JDOM의 new Document()라면 없어도 되는 메소드가 하나 늘어나는 것입니다.

게다가, factory는 평행 상속 구조를 유발하는 경우가 많습니다. AAAFactory & AAA, BBBFactory & BBB 와 같은 식이죠.

그래서, 저는 factory 패턴 오용의 대표 사례로 DocumentBuilderFactory를 끄집어냈던 것인데, 이것을 factory를 잘 활용한 사례로 보고 있으시다면 이 부분의 의견 차이를 좁히기는 어려울 것 같습니다.

그리고 패턴에 대한 공격을 OOP에 대한 공격으로 받아들이시는 것 같은데, 전 패턴을 공격했다고 생각하지도 않지만, 패턴을 공격했다고 하더라도 OOP를 공격한 것은 아닙니다. 패턴은 OOP를 지지해주는 그런 개념은 아닙니다. 사실 GoF의 패턴들 중 절반 이상이 동적인 언어에서는 필요 없는 패턴입니다. factory 패턴도 동적 언어에서 필요 없어지는 대표적인 패턴입니다. 물론, 자바에서는 여전히 많은 패턴이 필요합니다만, 그래도 JAXP에 대해 JDOM이 보여준 것처럼, 혹은 Struts에 대해 Stripes가 보여준 것처럼 다양한 대안 설계가 가능합니다.

그래서, 'OOP가 필요한가'라는 것으로 논쟁을 할 생각은 없습니다. '패턴이 필요한가' 역시 아닙니다. 다만 '패턴은 context에 맞게 적용해야 한다'라고는 할 수 있겠죠.

fender의 이미지

creativeidler님이 실제로 OOP를 공격하셨다고 주장한 것은 아니고 factory, proxy 등에 대해 말씀하신 논리는 구체적인 사례나 대안이 없는 경우엔 그렇게 까지 확장될 수 있다는 의미였습니다. 물론 저 또한 정적언어의 객체지향이 진정한 객체지향이라던가 하는 식의 논리는 펼치지 않았습니다. creativeidler님께서 동적 언어의 예를 드신 것도 제가 동적 언어를 무시한다는 뜻은 아니었다고 이해합니다.

아무튼, 본론으로 돌아오면 말씀하신 JDom과 JAXP가 지금 논쟁에서 같은 맥락에서 비교할 수 있는 대상이라고 생각하지는 않습니다. 표준 스펙의 여러 구현을 팩토리를 활용해서 플러거블하게 사용하려는 요구와 그런 것 다 필요없으니 쉽고 간편한 특정 라이브러리 하나만 필요하다는 요구는 차이가 있을 수밖에 없습니다.

말씀하신대로 이는 개별 프로젝트의 상황에 맞게 트레이드오프를 고려해서 결정할 문제이고 근본적으로 어느 한쪽 접근이 우월하다고 할 수 없습니다. 제가 JAXP의 경우 DocumentBuilderFactory가 필요하다고 한 것은 그 설계가 깔끔하다거나 JDom보다 사용하기 쉽다는 것이 아니라 전자와 같은 유용성을 확보하기 위해선 factory 같은 트레이드 오프가 필요하다는 뜻입니다.

JDom으로 충분한 경우에 JAXP을 써서 조금쯤 문법이 verbose해졌다면 그건 JAXP의 설계상의 결함이 아닌 주어진 상황에 최적의 툴을 고르지 않은 개발자 선택의 문제입니다.

스프링 문제로 돌아간다면 스프링 프로젝트의 탄생 의도와 주요 용도를 생각해보면 단순히 스프링에서 프록시나 팩토리등이 널리 활용된다는 자체를 문제삼기 시작한다면 근본적으로 '스프링을 꼭 써야하나?'혹은 앞서 말한 'OOP가 꼭 필요하나?'와 같은 훨씬 일반적인 질문으로 귀결되는 것이고 그에 대한 답은 이미 아시듯이 '프로젝트 마다 다르다'가 될 수밖에 없습니다.

논지를 조금 정리해보면, creativeidler님께서 스프링의 TransactionAwarePersistenceFactoryProxy라는 클래스에 대해 (1) '설계상에 다른 방법으로 더 단순화 할 수 있다' (2) '프록시, 팩토리, 매니저 패턴을 함께 사용하니 3배로 복잡해졌다'라고 말씀하신 바 있습니다.

1, 2번 모두에 대한 근거로 creativeidler님께서는 스프링이나 해당 클래스의 구체적 용법을 떠나 원론적 차원의 트레이드오프를 말씀하셨고 저 역시 일반론적인 트레이드 오프 관계에 대해선 전혀 이견이 없습니다.

하지만 일반론이 아닌 원래의 스프링의 특정 클래스가 불필요하게 복잡하다는 주장에 대해서는 적절한 근거가 나오지 않은 듯 합니다. 반복해서 예로드신 JAXP vs JDOM의 경우를 적용한다해도 그것은 사실상 스프링이 지향하는 유연성 자체에 대한 비판이 될 수밖에 없다고 봅니다. 왜냐하면 앞서 말씀드렸 듯이 JDOM은 JAXP의 어떤 설계 결함을 고쳐서 이를 대체한다기 보다는 그런 유연성이 필요 없는 경우에 매우 유용하게 사용할 수 있는 특정 라이브러리이니까요.

직접 강조하신 바와 같이 유연성과 단순함이 트레이드 오프를 형성하고 있는 상황이라면 맥락이 없는 단순 비교는 무의미 하다고 생각합니다. 따라서 TransactionAwarePersistenceFactoryProxy의 잠재적 설계상의 결함이나 대안에 대해 이야기한다면 본래 해당클래스가 사용되는 의도와 환경을 전제해야한다고 봅니다. 그런 맥락을 떠나 동적언어에서는 팩토리 패턴의 의미가 축소된다거나 하는 일반론을 근거로 이야기를 한다면 토론이 훨씬 다른 방향으로 확대될 수밖에 없을 것입니다.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

creativeidler의 이미지

흠냐, 사실 처음부터 "직관"을 전제로 한 이야기였기 때문에 fender님이 원하시는 것처럼 저 클래스가 잘못된 설계임을 "입증"까지는 할 수 없습니다. 입증하려면 저도 더 들이파고 연구를 해야 하니까요. 그렇지만, 저는 이 문제가 DocumentBuilderFactory와 아주 유사하다고 보고 있기 때문에 DocumentBuilderFactory를 통해서 충분한 수준의 비확정 증거를 확보할 수 있다고 봅니다.

fender님은 대체로 늘 확정 증거만을 원하시는 것 같습니다만, 법정에서도 그렇듯 설계 문제에서도 확정 증거 없이 비확정 증거만으로도 판단이 가능한 경우가 많습니다. 오히려 확정 증거를 찾을 수 있는 경우가 더 드물죠. 현장에서 용의자의 지문이 발견되었다 하더라도 이것은 용의자가 범인임을 입증해주지는 않습니다만, 범인일 가능성을 아주 높여주죠. 거기에 용의자가 전과가 있다면 역시 확정 증거는 아니지만 더 혐의가 올라갑니다. 현장 근처에서 사건 발생 시각 근처에 용의자를 목격한 사람이 있다면 더 혐의가 굳어지겠죠. 이 모든 것들이 확정 증거는 아니지만 이런 증거들이 아주 많이 쌓이면 유죄 판결이 가능합니다. 이것은 과학의 연구방법이기도 합니다. 진화론도 확정 증거는 하나도 없습니다. 지난 번에도 이런 이야기를 했었는데 fender님이 그 때 마치 제가 근거도 안되는 이야기를 하는 것처럼 말씀을 하셨었죠. 이번에도 비확정 증거는 절대 인정 불가! 이런 입장이시라면 더 이상 의견이 좁혀지는 것은 불가능할 겁니다.

이런 점을 감안한 상태에서 비확정 증거를 댄다면, 우선, 저는 패턴은 상황에 따라 다르게 적용해야 한다고 주장했지만 JDOM과 JAXP가 그런 관계라고 보지는 않습니다. JDOM은 99% 이상의 확률로 JAXP보다 항상 좋은 선택입니다. 1)JDOM은 factory를 쓰지 않고도 JAXP가 하는 일의 99%를 할 수 있고 JAXP에 없는 기능까지 더 쉽게 쓸 수 있습니다. 2)JAXP는 유연성이 필요할 때건 아니건 메세지 체인과 평행 상속 구조(구현체에서)의 문제점은 항상 발생합니다. 3)JAXP에서 제공하는 유연성을 활용하기는 쉽지 않습니다. JAXP에서 구현체를 crimson이나 xerces 중에 선택하는 방법을 아는 개발자가 몇이나 될까요? 파싱 옵션을 바꾸려면 builder에서 바꿔야 할지 factory에서 바꿔야 할지 아는 개발자는요?

이런 점을 들어, 저는 factory를 쓰지 않고도 유연성은 거의 떨어지지 않으면서 적은 bad smell과 간결한 코드로 같은 일을 할 수 있는 대안이 가능하다고 주장하는 것입니다. 물론, JDO를 수정한다는 전제 하에서 말이죠.

저 클래스 역시 factory 부분이 하는 일은 JAXP와 아주 비슷합니다. 그래서 유연성을 거의 희생하지 않고 factory를 제거하는 것이 가능하다고 보는 것입니다. 물론, 그렇다고 저 클래스에 대한 처방으로 factory 제거가 최선이라는 뜻은 아닙니다. 일단은 Manager의 제거가 우선이고 Manager가 성공적으로 제거되고 나면 "어? 그럼 factory도 필요 없네?"하는 생각이 들 가능성이 높습니다. 여기서의 Proxy 역시 Factory가 없으면 존재 의미가 반감됩니다. 이런 식으로 점차적인 리팩토링이 가능할 것입니다. 물론 이것은 부분적인 리팩토링을 시도할 때 이야기고 전체적인 관점에서 본다면 더 나은 방법도 있을 수 있겠죠.

fender의 이미지

개발자로서의 직관은 무척 중요합니다만, 토론에서 '개인의 직감'을 근거로 의견을 좁히긴 불가능하다고 봅니다.

그리고 여전히 JAXP의 구현체를 바꿀 수 있는 설계가 항상 무의미하다고 생각하진 않습니다만 설사 그렇다 쳐도 원래의 논의에 대한 근거로 사용하려면 JDO나 스프링 등등이 보장하는 유연성이 모두 JAXP 수준의 상대적으로 사소한 것이라는 전제가 선행되야 합니다.

JDom으로 JAXP를 쓰는 경우의 99%를 커버할 수 있다는 것이 과연 스프링의 프록시를 통한 트랜잭션 통합이나 JDO의 추상화도 마찬가지로 99%쯤 기능을 포함하면서 훨씬 간단한 그 무엇으로 바꿀 수 있다는 근거가 될 수 있을까요?

이 부분에 대한 근거가 개발자의 직관이라면 더 논의를 진행해도 크게 의미있는 결과가 나올 것 같지는 않습니다.

나중에라도 creativeidler님이 추후에 말씀대로 시간을 내서 JDO를 파악하고 개선점을 찾아내서 직관으로 깨달은 지금 구현의 문제를 확증하고 대안을 찾아내실 수 있는 가능성까지 무시하지는 않겠습니다 - 물론 'TransactionAwarePersistenceManagerFactoryProxy'에서 7글자를 줄이는 것이 그런 노력을 들일말한 작업인지는 차치하고 말입니다.

아무튼 저 같으면 직관을 갖는 건 몰라도 직관만 가지고 다른 사람과 토론을 하진 않을 것 같습니다.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

creativeidler의 이미지

저는 직관을 가지고 의견을 좁히고자 한 적도 없고 직관으로 제 주장을 뒷받침하고자 한 적도 없습니다. 거듭 제가 쓴 글을 다시 읽어봤지만 아무리 봐도 제가 잘못 쓰지는 않았습니다. 다시 읽어주시면 감사하겠습니다.

Quote:
JDom으로 JAXP를 쓰는 경우의 99%를 커버할 수 있다는 것이 과연 스프링의 프록시를 통한 트랜잭션 통합이나 JDO의 추상화도 마찬가지로 99%쯤 기능을 포함하면서 훨씬 간단한 그 무엇으로 바꿀 수 있다는 근거가 될 수 있을까요?

이것도 확대해석입니다. 이건 설명을 드리죠. 제 논지는 이런 구조입니다.
1. JDOM이 factory 없이 JAXP를 대체한다.
2. 고로 factory 없이 유연성 떨어지지 않는 간단한 대안이 가능하다.
3. 그러므로 저 클래스에서도 factory 제거가 가능하다.

2번은 1번의 일반화이고 3번은 2번의 적용입니다. 1->2->3이죠. 여기서 fender님이 확대해석하신 것은 뒤에 Manager 이후의 내용이 3번과 이어지는 것이라고 생각하신 것입니다. 저는 1번을 근거로 프록시까지 가려는 생각은 전혀 없습니다. 단지 factory 부분에 한해서 큰 유연성 저하 없이 제거할 수 있을 거라는 얘깁니다.

문단을 끊지 않았기 때문에 오해할 수도 있겠다는 생각이 들지만, 맥락을 보시면, 물론이라는 표현 뒤로 앞의 내용과 단절을 시도하고 있습니다. 거기서부터는 Manager를 공격하고 그로 인한 연쇄로 factory의 제거가 가능할 수 있다는 이야기죠. 이것은 JDOM과는 별개로, 개선 가능성을 나타내는 두번째 근거입니다.

그동안 fender님이 저 외에도 다른 분과 논쟁하는 것도 많이 봐왔는데, fender님이 자바에 대한 식견도 깊고 프로그래머로서의 역량도 있고, kldp에서 합리적으로 글을 쓰는 순위 같은 게 있다면 탑 5 안에 들 것이라고 생각하긴 합니다만, 종종 상대방의 글을 확대해석한 뒤, 그 확대해석된 결과를 놓고 비판하시는 것 같습니다.(한두 건을 가지고 이런 말씀을 드리는 것은 아닙니다.) 서로 의견 차이가 커서 논쟁이 길어진다면 그 과정에서 서로 배우는 게 많겠지만 이처럼 상대방의 글을 잘못 이해해서 논쟁이 길어진다면 피곤함만 커지겠지요. 조금 더 열심히 읽어주셨으면 합니다.

fender의 이미지

저에 대한 칭찬은 감사하고 지적 하신 부분은 겸허하게 듣겠습니다. 하지만 이번 건에 대해선 다시 제글과 윗글을 읽어봐도 딱히 생각이 달라지진 않는군요...

factory에 대해선 정리하신 1->2->3의 논리 구조가 정확히 제가 이해한 그대로입니다. 그리고 저는 바로 2->3이 논리적으로 근거가 부족한, 다소 성급한 일반화가 아닌지 지적한 것입니다. 좀 더 정리해 볼까요? :

(1) 팩토리 패턴은 약간의 복잡성을 더하면서 유연성을 확보하는 트레이드 오프를 가져온다.

(2) JDom은 (이 표현이 정확하진 않습니다만) 팩토리 패턴 없이 JAXP를 대체하면서도 유연성을 크게 훼손하지 않는다.

(3) 따라서 JDO의 PersistenceManagerFactory도 유연성을 보존하면서 팩토리 패턴을 제거할 수 있을 것이다.

잘 아시다시피 JDom과 JDO는 규모나 용도도 전혀 관계가 없는 서로 다른 API입니다. 그런데 아무런 부연 설명없이 JDom에서 팩토리를 없앨 수 있으니 JDO에서도 그럴 것이다라고 논증하는 것은 사실상 JDom이나 JDO등 프로젝트 맥락을 떠난 팩토리 패턴 자체에 대한 일반론밖에 되지 않습니다.

이를 다시 표현하면, 팩토리 패턴은 대부분의 경우 유연성을 크게 훼손하지 않으면서 다른 방법으로 대체가 가능하다는 이야기가 되버립니다.

어쩌면 제가 또 하지 않은 이야기를 확대해석해서 '허수아비 논증'을 한다고 말씀하실 지 모르겠습니다만 허수아비 논증과 이 경우는 전혀 다릅니다.

물론 creativeidler님은 정확하게 그런 표현을 하신 적이 없다는 것은 잘 알고 있습니다. 실제로 그런 표현을 하셨다는 것이 핵심이 아니라 주장하시는 논리를 따라가면 결국 그런 결론에 도달하게 되기 때문에 논증에 오류가 있다는 것을 지적하려는 의도가 중요한 것입니다.

확대해석을 포함한 허수아비 논증은 논지와 관계없이 상대방이 하지 않은 이야기를 가정하고 이를 반박하는 것으로 토론에서 이기려고 하는 것이고 이 경우는 상대방이 주장하는 논거를 논리적으로 따라가면 상대방조차 받아들이기 힘든 결론에 도달하는 것을 보임으로서 애초 논거의 헛점을 증명하려는 것입니다.

의도하지 않게 순수한 궁금증에서 출발한 질문이 논리 자체를 걸고 넘어지는 토론이 되어 버려서 유감입니다만 저 역시 제 의도가 불필요하게 곡해 되는 것을 바라진 않습니다.

질문의 출발은 creativeidler님께서 TransactionAwarePersistenceManagerFactoryProxy라는 클래스의 복잡성에 대해 "설계 방향을 조금 더 앞에서 비틀었다면 저렇게까지는 안되었을 겁니다"라고 말씀하신 내용에 대해 제가 '그럼 어느 부분을 어떻게 바꾸면 개선이 가능한가?'를 여쭤 본 것입니다.

하지만 이제까지 수차례 꽤 장문의 덧글이 오갔지만 creativeidler님께서는 해당 질문에 대해 구체적인 답변을 하진 않으셨습니다.

대신,

(1) 해당 클래스는 Manager, Factory, Proxy를 포함하고 있고 이는 3배나 복잡도가 늘어난 것이다.
(2) JDom은 유연성을 훼손하지 않으면서 팩토리 패턴을 대체한다.

이 두 가지 논제로 토론을 확대하셨습니다.

(1)의 경우 저는 그렇다면 TransactionAwarePersistenceManagerFactoryProxy이 사용되는 맥락에서 Manager/Factory/Proxy를 사용하지 않는다면 대안이 무엇인가를 질문 드렸지만 그에 대한 답도 (2)로 대체하셨습니다.

그리고 (2)의 논증은 이미 말씀드린 바와 같이 별도의 JDom의 경우와 JDO 혹은 스프링의 경우 연관성을 설명하는 논증이 없다면 저로서는 성급한 일반화에 따른 비약으로 받아들일 수밖에 없습니다.

하지만 (2)에 대한 근거로는 :

"사실 처음부터 "직관"을 전제로 한 이야기였기 때문에 fender님이 원하시는 것처럼 저 클래스가 잘못된 설계임을 "입증"까지는 할 수 없습니다. 입증하려면 저도 더 들이파고 연구를 해야 하니까요. 그렇지만, 저는 이 문제가 DocumentBuilderFactory와 아주 유사하다고 보고 있기 때문에 DocumentBuilderFactory를 통해서 충분한 수준의 비확정 증거를 확보할 수 있다고 봅니다."

이와 같이 개인의 직관과 느낌을 예로 드셨을 따름입니다. 하지만 제가 그 부분을 지적하니 다시 "저는 직관을 가지고 의견을 좁히고자 한 적도 없고 직관으로 제 주장을 뒷받침하고자 한 적도 없습니다"라고 하시는 군요... 이 부분도 제가 엄청난 오해를 하고 있는 건가요?

아무튼 유감스럽게도 이미 토론 자체가 기술적인 측면 보다는 논리 싸움이 되어 버려서 말씀처럼 더 이상 생산적인 결과를 내긴 어려울 듯 합니다.

원하신다면 이 글에 대해서도 말씀하고자 하시는 내용을 더 덧붙이셔도 좋겠습니다만 저는 이 주제에 대해서는 이만 접도록 하겠습니다.

생산적인 토론이 되지 못해서 유감이네요.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

creativeidler의 이미지

정말, 직관에 대한 부분조차 다시 읽어도 전혀 생각이 바뀌지 않으셨나요? 제가 직관으로 설득을 하려고 했다고 여전히 생각하신다는? 이 정도면 전 정말 심각한 오독이라고 생각합니다. fender님은 이 쓰레드에서만 5건 가까이 오독을 범하고 있으시고, 당장 첫번째 댓글부터 오독의 증거가 보입니다. 계속 제가 뭔가 말하면 fender님이 오독해서 반박하고 또 제가 해명하면 다음 걸로 넘어가고 이런 일이 반복되고 있는데, 이런 식이라면 저도 계속 글을 쓰는 의미가 없겠지요.

머, 어쨋든 fender님도 마지막 정리를 하고 접는다고 하시니 저도 마지막 마무리를 하겠습니다.

우선, 1->2->3 부분인데, 여기서 성급한 일반화를 지적하시려면 2->3이 아니라 1->2를 지적하셨어야 합니다. 1->2가 일반화고 2->3은 일반화의 적용입니다. 1->2를 인정한다면 2->3은 달리 이의를 제기할 필요가 없이 자동인 것이죠. 저도 논리를 걸고 넘어지고 싶지는 않습니다만, 이 정도 수준의 논리적 오류를 거듭해서 범한다면 제가 아무리 이야기를 해도 제 뜻이 전달이 안될 게 뻔한데 논리적 오류부터 제거하려고 시도할 수 밖에 없지요.

그래서, 이번에는 오히려 확대해석이 아니라, 축소해석을 하신 겁니다. 제 뜻은 factory에 일반적인 대안이 있다는 게 맞습니다. 제가 확대해석했다는 것은 저는 factory만 제거할 수 있다고 했는데 마치 제가 JDOM을 근거로 저 클래스 전체를 개선할 수 있다고 이야기한 것처럼 반론하셨다는 겁니다. 어쩌면, 1->2를 축소해석했기 때문에 어쩔 수 없이 2->3을 확대해석할 수 밖에 없지 않았나 싶어 이해가 되기는 하는군요.

그럼 이제 1->2가 성급한 일반화 아니냐..라고 할 수 있겠지요. 여기에 대한 답을 하자면, factory 전체가 대체 가능하다기보다는 DOM과 JDO가 유사점을 보이는 부분에 한해서 factory가 대체 가능하다는 것입니다. fender님은 DOM과 JDO가 전혀 유사성이 없는 API라고 하셨지만 우리는 여기서 factory 부분을 이야기하고 있고 DOM과 JDO가 factory를 쓰는 이유는 아주 정확하게 일치합니다. 같은 API를 쓰되, 다른 구현체를 사용할 수 있는 유연성을 열어놓기 위함이죠.

그리고, 구체적인 답변을 하지 않았다고 했는데, 대체 어느 정도의 구체적인 답변을 바라시는지는 모르겠으나, 코드 수준까지 원하시는 게 아니라면 저는 이미 구체적인 답을 두 가지나 내놓았습니다. 하나는 전술한 factory 부분이 제거 가능하다는 것입니다. 또 하나는 Manager 부분에서 Data와 Action을 합치면 Manager가 필요 없어질 것이고 그렇게 되면 factory의 존재 의미가 사라질 가능성이 높다고 했죠. Manager에 대해서는 나쁜 패턴이며 제거 가능하다는 말을 수 차례 했습니다. 대체 어느 수준의 구체적인 대안이 필요하신 겁니까?

Quote:
(1) 해당 클래스는 Manager, Factory, Proxy를 포함하고 있고 이는 3배나 복잡도가 늘어난 것이다.
(2) JDom은 유연성을 훼손하지 않으면서 팩토리 패턴을 대체한다.

이 두 가지 논제로 토론을 확대하셨습니다.

1번이 왜 토론의 확대인가요? 이 이야기는 저 클래스 이름은 나쁜 설계의 증상이라는 것에서 출발했습니다. 그래서 저 설계가 왜 나쁜지를 이야기하는 것인데 왜 확대죠?

그리고, 1번의 대안을 물으니까 2번이라고 대답했다고 하시는데, 다시 읽어보시길 권합니다. 저는 거듭 Manager와 Factory 모두를 공략했고 2번은 Factory 부분만 공략한 것입니다.

2에 대한 근거로 직관을 사용했다고 했는데 이건 전술했듯, 명백한 오독입니다. 직관을 이야기한 문장과, DocumentBuilderFactory를 이야기하는 문장 사이에 그렇지만이라는 접속사를 유의해서 보시기 바랍니다. 저는 직관이기 때문에 확정 증거를 제시할 수 없다고 했지, 제가 제시하는 모든 비확정 증거들이 직관이라고 이야기한 것은 아닙니다. 오히려, 저는 직관에서 나온 이야기는 단 한 가지도 제 주장을 강화하기 위해 쓰지 않았습니다.

이 오독을 보면서 fender님의 오독 패턴이 조금 보이는데요. 이런 경향이 있는 것 같습니다. 보통 사람들이 글을 쓸 때 A를 주장하고 싶을 경우, B, C, D, E, F를 이야기합니다. 그런데 이렇게 글을 쓸 때 보통 이런 구조를 취하게 됩니다.
* B->C->D
* E->F
* D & F -> A

그런데 fender님은 이런 글을 보면 B->A, C->A, D->A, E->A, F->A 라는 구조로 이해를 하시는 것 같습니다. 게다가 B,C,D,E,F가 다 관련이 있는 것처럼 받아들이죠. 직관이라는 이야기가 나왔으니, 아 직관으로 뒷받침하려나보다, 다른 이야기도 다 직관인가보지? 하는 식인 거죠. 첫 댓글의 네이밍에 대한 오독도 그렇고, factory 논리의 오독도 그렇고 이번 쓰레드에 발생한 오독이 모두 이런 패턴인 것 같습니다.

뭐, 사람이 살다보면 오독도 할 수 있고 논리적 오류도 범할 수 있죠. 하지만, fender님의 경우 본인의 주장 전개에는 거의 논리적 결함이 없습니다. 이 쓰레드의 글들도 제 글 떼놓고 fender님 글만 딱 본다면 거의 결함이 없습니다. 그런 점을 보면 논리적인 사고력은 충분한 사람인데 왜 이렇게 다른 사람의 글을 읽을 때는 자주 오독이 발생할까 궁금해서 지난 번과 같은 이야기를 했던 것입니다. 혹시, 이번 쓰레드도 순수한 궁금증이라고 하셨지만 사실은 미리 생각이 정해져 있었던 것은 아닌가요?

마지막으로 하나만 더 묻겠습니다. 아, 더 답을 달지 않겠다고 하셨으니 꼭 답을 달지는 않으셔도 됩니다.

혹시 저 클래스의 설계에 개선의 여지도 없고, 문제도 없다고 생각하십니까? 진심으로?

fender의 이미지

인용 : "마지막으로 하나만 더 묻겠습니다. 아, 더 답을 달지 않겠다고 하셨으니 꼭 답을 달지는 않으셔도 됩니다.

혹시 저 클래스의 설계에 개선의 여지도 없고, 문제도 없다고 생각하십니까? 진심으로?"

아니요. 전혀 그렇게 생각하지 않습니다. 그리고 처음부터 끝까지 한 번도 그렇게 주장하거나 그런 내용을 근거로 든적도 없습니다.

creativeidler님이 볼 때는 제 '오독'이겠지만 제 입장에서는 creativeidler님의 심각한 논리 결함일뿐입니다. 그 이야기를 더 반복할 필요는 없겠군요.

서로 할 이야기는 다 한 것 같으니 읽는 분들이 판단하시면 될 것 같습니다.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

꼬마앙마의 이미지

무슨 클래스 인가 했더니, JDO PersistenceManagerFactory를 위한 프록시 클래스군요.

그 사촌격인 클래스로 WebLogicServerTransactionManagerFactoryBean라는 아주 긴~ 이름의 클래스도 있구요.

사실 어쩔수 없는게, 스프링 프레임워크는 애초에 자바 1.3 스펙에 맞추어서 개발되어서 왔고, 그 위에 1.5에서 지원하는 제너릭이나 어노테이션을 추가하다 보니 지나치게 복잡해진것이 사실입니다.

또한 JEE에서 스프링 프레임워크가 거대 기업들이 참여하는 EJB와 같은 성격을 띄게 되어서, 개발자들이 지나치다 싶을 정도로 프레임워크에 하위 호환성을 유지하려고 노력하다 보니 그러한 구조로 발전해 온것 같습니다.

지나친 설계 문제는 대부분의 설계에서 나타나는 문제이지만, 하위 호환성때문에 리팩토링에 제약이 있는 프레임워크에서 스프링의 해결책 이외의 방법이 딱히 떠오르지 않는군요.

fender의 이미지

공감합니다. 그런데 하위호환성은 creativeidler님이 지적하신 프록시 등의 사용과는 조금 다른 문제가 아닐까 싶기도 합니다.

트랜잭션 문제에 집중해보자면 핵심은 '어느 써드파티 API를 쓰던지 누가 제공하는 트랜잭션을 쓰던지 별도 코딩없이 선언적 방식으로 알아서 통합해주겠다'입니다. WebLogicServerTransactionManagerFactoryBean는 '누가 제공하는'에 대한 부분이고 TransactionAware...Proxy는 '어느 API를 쓰던지'에 해당하는 부분입니다.

설사 스프링이나 웹로직이 처음부터 자바 5이상을 타겟으로 개발했다고 해도 예를들어 자바 언어 자체에 내부적으로 자동화된 트랜잭션 처리나 아니면 AOP 같은 후킹 기능이 빌트인되어있는 것이 아니라면 저런식의 설계는 불가피하다고 생각합니다.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

t3RRa의 이미지

영어에 모국어인 사람들에겐 너무 딱 와닿을 이름인데요;
오히려 약자로 쓰는 경우 뭐인지 일일이 찾아봐야될수도 있고..
네이밍에 규칙만 있다면 하등 문제될 것은 없다고 봅니다.
길든 짧든.. 짧다면 더 좋겠지만, 짧아서 무슨 클래스인지 파악이 안된다면 안되겠죠.
저런식으로 쓴다면 검색도 더 수월할테구요.

powersys의 이미지

보기 흉하군요.

kirrie의 이미지

가장 긴 클래스 네임은 이거 인듯 싶은데요. ㅎㅎ
얼마전 rss feed에서 비슷한 주제를 본터라...

근데 전 자바놓고 스프링은 커녕 커피 밖에 안떠오르는 사람이라.. ^^;;
--->
데비안 & 우분투로 대동단결!

--->
데비안 & 우분투로 대동단결!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.