ì£ ìˆ˜ì•„ 블로치는 êµ¬ê¸€ì˜ ì†Œí”„íŠ¸ì›¨ì–´ 아키í…ì³ë¡œ ìœ ëª…í•œ 사람입니다.
아래 ë‚´ìš©ì€ 2007ë…„ 1ì›” 24ì¼ Google Tech Talks ì—ì„œ 발표한 내용입니다.
API 를 개발하면서 í•œ 번쯤 ê³ ë¯¼í–ˆë˜ ë‚´ìš©ë“¤ì´ ëª¨ë‘ ë“¤ì–´ìžˆìŠµë‹ˆë‹¤.
API 를 개발하는 개발ìžë¼ë©´ ê±°ì˜ í•˜ë‚˜ë„ ë†“ì¹ ê²Œ 없는 경험ì´ë¼ê³ ìƒê°í•©ë‹ˆë‹¤.
ê·¸ë§Œí¼ ë§Žì´ ë²ˆì—ë˜ê³ ë¸”ë¡œê·¸ì— í¼ì¡Œë˜ 글들입니다.
좀 길지만, ë§Žì€ ê°œë°œìžë“¤ì´ ë‘ê³ ë‘ê³ ì°¸ì¡°í–ˆìœ¼ë©´ 하는 ë°”ëžŒì´ ìžˆìŠµë‹ˆë‹¤.
ì›ì œ : How to Design a Good API and Why it Matters(Google Tech Talks, 2007.1.24)
ì €ìž : Joshua Bloch, Principal Software Engineer, Google
- API ë””ìžì¸ì´ 왜 중요한가?
API는 회사가 가진 중요한 ìžì‚°ì¼ 수 있다.
- ê³ ê°ë“¤ì€ 무ì„게 투ìží•œë‹¤ : êµ¬ë§¤í•˜ê³ , ì‚¬ìš©í•˜ê³ , 배운다.
- ìš´ì˜ì¤‘ì¸ API를 중단시키는 ë¹„ìš©ì€ ì—„ë‘ë„ ë‚¼ 수 없다.
- 성공ì ì¸ public API 는 ê³ ê°ì„ 잡는다.Public API 는 ì˜ì›í•˜ë‹¤. – ê·¸ê²ƒì„ ì œëŒ€ë¡œ 만들 기회는 ì˜¤ì§ ë”± í•œ 번 ë¿ì´ë‹¤.
- API ê°€ 왜 ë‹¹ì‹ ì—게 중요한가?
ë‹¹ì‹ ì´ ë§Œì¼ í”„ë¡œê·¸ëž˜ë¨¸ë¼ë©´, ë‹¹ì‹ ì€ ì´ë¯¸ API ë””ìžì´ë„ˆì´ê¸° 때문ì´ë‹¤.
- ì¢‹ì€ ì½”ë“œëŠ” 모듈화ë˜ì–´ ìžˆê³ , ëª¨ë“ ëª¨ë“ˆë“¤ì€ API 를 ê°€ì§€ê³ ìžˆë‹¤.ìœ ìš©í•œ ëª¨ë“ˆë“¤ì€ ìž¬ì‚¬ìš©ë˜ì–´ì§€ê¸° 때문ì´ë‹¤.
- ì¼ë‹¨ ëª¨ë“ˆì´ ì‚¬ìš©ìžë¥¼ 가지기 시작하면, ìž„ì˜ë¡œ API를 바꿀 수 없다.
- ì¢‹ì€ ë°©í–¥ìœ¼ë¡œ 재사용ë˜ì–´ì§€ëŠ” ëª¨ë“ˆë“¤ì€ íšŒì‚¬ì˜ ìžì‚°ì´ë‹¤.
APIë¼ëŠ” ê´€ì ì—ì„œ ìƒê°í•˜ëŠ” ê²ƒì€ Code ì˜ Quality를 높ì´ê¸° 때문ì´ë‹¤.
- ì¢‹ì€ APIì˜ íŠ¹ì§•
배우기 쉬울 것
문서가 ì—†ì–´ë„ ì‚¬ìš©í•˜ê¸° 쉬울 것.
잘못 사용하기 ì–´ë ¤ìš¸ 것.
ì½ê¸° ì‰½ê³ , API를 사용하는 코드를 ìœ ì§€ë³´ìˆ˜í•˜ê¸° 쉬울 것
요구사í•ì„ ë§Œì¡±ì‹œí‚¤ê¸°ì— ì¶©ë¶„ížˆ ê°•í• ê²ƒ.
확장하기 쉬울 것
사용하는 ì‚¬ëžŒë“¤ì˜ ìˆ˜ì¤€ì— ë§žì„ ê²ƒ
첫째. The Process of API Design
- ì 당한 수준ì—ì„œ 회ì˜ì 태ë„ë¡œ ìš”êµ¬ì‚¬í• ìˆ˜ì§‘í•˜ê¸°ë‹¹ì‹ ì€ ì¢…ì¢… ì†”ë£¨ì…˜ë“¤ì„ ì œì•ˆë°›ì„ìˆ˜ë„ ìžˆë‹¤.
- ë§Œì¼ ë” ë‚˜ì€ ì†”ë£¨ì…˜ë“¤ì´ ìžˆì„ ìˆ˜ 있다면,ë‹¹ì‹ ì˜ ì¼ì€ 진짜 요구사í•ì„ 수집하는 것ì´ì–´ì•¼ 한다.
- ìœ ì¦ˆì¼€ì´ìŠ¤ 형태로 ìˆ˜ì§‘ì„ í•´ì•¼ 한다.
ë” ì¼ë°˜ì ì¼ìˆ˜ë¡ ë” ì‰¬ì›Œì§€ê±°ë‚˜ ë” ë³´ìƒì´ ë 수 있다.
- ì§§ì€ ìŠ¤íŽ™ìœ¼ë¡œ ì‹œìž‘í•˜ë¼ â€“ 1페ì´ì§€ëŠ” ì´ìƒì´ë‹¤.ì´ ë‹¨ê³„ì—서는 Agility ê°€ ì™„ë²½í•¨ì„ ì´ê¸´ë‹¤.
가능한 ë§Žì€ ì‚¬ëžŒë“¤ë¡œë¶€í„° ë°˜ì‘ì„ ì‚´íŽ´ë¼.
- ê·¸ë“¤ì˜ input ì— ëŒ€í•´ 귀기울여 ë“£ê³ , 심ê°í•˜ê²Œ 받아들여ë¼.
ìŠ¤íŽ™ì„ ìž‘ê²Œ í• ìˆ˜ë¡, ê³ ì¹˜ê¸° 쉽다.
ìžì‹ ê°ì„ ì–»ì„ ë•Œê¹Œì§€ ì‚´ì„ ë¶™ì—¬ë¼.
- ì´ê²ƒì€ í•„ì—°ì 으로 ì½”ë”©ì„ í¬í•¨í•œë‹¤.
- 미리 ìžì£¼ API ì— ê¸€ì„ ì ì–´ë¼.(그냥 function ë‚´ì— í•„ìš”í• ê¸°ëŠ¥ì„ ìŠ¤í¬ë¦½íŠ¸ 형ì‹ìœ¼ë¡œ ì 어넣는다.)API를 구현하기 ì „ì— ì‹œìž‘í•˜ë¼.
- 구현하는 ì‹œê°„ì„ ì ˆì•½í•´ì¤€ë‹¤.가능한 ìŠ¤íŽ™ì„ ìž¡ê¸° ì´ì „부터 시작하ë¼.
- ìŠ¤íŽ™ì„ ìž¡ëŠ” ì‹œê°„ì„ ì ˆì•½í•´ì¤€ë‹¤.
ì‚´ì´ ë¶™ì„ ë•Œê¹Œì§€ API ì— ê¸€ì„ ì ì–´ë¼.
- ë”ì°í•œ 실패를 예방해준다.
- 코드는 ì˜ˆì œì™€ unit test 를 ë¨¹ê³ ì‚°ë‹¤.
- SPI ì— ê¸€ì„ ì 는 ê²ƒì€ ë” ì¤‘ìš”í•˜ë‹¤.Service Provider Interface (SPI)
- í”ŒëŸ¬ê·¸ì¸ ë°©ì‹ì˜ ì¸í„°íŽ˜ì´ìŠ¤ëŠ” 여러 ê°œì˜ êµ¬í˜„ì„ ê°€ëŠ¥í•˜ê²Œ 한다.
- 예 : Java Ctyptography Extension (JCE)ë°°í¬í•˜ê¸° ì „ì— multiple plug-in ë“¤ì„ ë§Œë“¤ì–´ë¼. (윌 íŠ¸ëž™ì€ â€œì„¸ê°œì˜ ë²•ì¹™â€ì´ë¼ê³ 부른다.)
- ë§Œì¼ í”ŒëŸ¬ê·¸ì¸ í•˜ë‚˜ë¥¼ 만들면, ì•„ë§ˆë„ APIê°€ 다른 ê²ƒì€ ì§€ì›í•˜ì§€ 못하게 ë 것ì´ë‹¤.
- ë‘ ê°œë¥¼ ë§Œë“ ë‹¤ë©´, ì–´ë µê²Œë¼ë„ 여러개를 지ì›í•˜ê¸°ëŠ” í• ê²ƒì´ë‹¤.
- 세 개를 ë§Œë“ ë‹¤ë©´, ê·¸ê²ƒì€ ì•„ì£¼ 잘 ìž‘ë™í• 것ì´ë‹¤.
- 현실ì ê¸°ëŒ€ìˆ˜ì¤€ì„ ë°›ì•„ë“¤ì—¬ë¼.ëŒ€ë¶€ë¶„ì˜ API 설계는 지나치게 ì œì•½ë˜ì–´ 있다.
- ë‹¹ì‹ ì€ ëª¨ë“ ì‚¬ëžŒì„ ë§Œì¡±ì‹œì¼œì¤„ 수 없다.
- ëª¨ë“ ì‚¬ëžŒë“¤ì„ ë˜‘ê°™ì´ ë¶ˆë§Œì¡±í•˜ê²Œ 만드는 ê²ƒì— ì´ˆì ì„ ë§žì¶”ì–´ë¼.실수하기를 기대하ë¼
- 몇 ë…„ ê°„ ì‹¤ì‚¬ìš©ì´ ë˜ë©´, 실수따위는 잊어버리게 ëœë‹¤.
- 실수를 통해 API를 진화시켜ë¼.
둘째. General Principles (ì¼ë°˜ ì›ì¹™)
- API는 í•˜ë‚˜ì˜ ì¼ë§Œ 해야 í•˜ê³ , ê·¸ê²ƒì„ ì•„ì£¼ 잘 해야 한다.ê¸°ëŠ¥ì´ ì„¤ëª…í•˜ê¸° 쉬워야 한다.
- ì´ë¦„짓기 힘들다면, 통ìƒì 으로 잘못 만들어진 것ì´ë‹¤.
- ì¢‹ì€ ì´ë¦„ì´ ìžì—°ìŠ¤ëŸ½ê²Œ 개발로 ì´ì–´ì§€ê²Œ ë§Œë“ ë‹¤.
- ëª¨ë“ˆì„ ìª¼ê°œê±°ë‚˜ í•©ì¹ ìˆ˜ 있어야 한다.
- API는 가능한한 작게 만들어야 하지만, ë” ìž‘ì•„ì ¸ì„œëŠ” 안ëœë‹¤.API는 요구사í•ì„ 만족시켜야 한다.
ì˜ì‹¬ì´ 들면 그대로 ë‘ì–´ë¼.
- 기능, í´ëž˜ìŠ¤, ë©”ì˜ë“œ, 파ë¼ë¯¸í„°ê¹Œì§€.
- ë”가를 ë”í• ìˆ˜ëŠ” 있지만, ê²°ì½” ì œê±°í• ìˆ˜ëŠ” 없다. (ë°°í¬ë˜ë©´ 회수불가)ê°œë…ì ì¸ ë¬´ê²Œê°€ 규모보다 ë” ì¤‘ìš”í•˜ë‹¤.
(APIì˜) 힘과 무게(power-to-weight ratio) ê°„ì˜ ê· í˜•ë¹„ë¥¼ 찾아ë¼.
- Implementation ì´ APIì— ì˜í–¥ì„ 주어서는 안ëœë‹¤.êµ¬í˜„ì´ ë„ˆë¬´ 세세해지면
- 사용ìžë¥¼ 혼란스럽게 한다.
- implemenation ì„ ë°”ê¿€ ìžìœ 를 방해한다.세세한 êµ¬í˜„ì´ ë¬´ì—‡ì¸ì§€ë¥¼ ì •í™•ížˆ 알아ë¼.
- method behavior ìŠ¤íŽ™ì„ ë„ˆë¬´ 과하게 잡지 마ë¼.
- 예를 들면 : hash function ë“¤ì€ ìŠ¤íŽ™í™”í•˜ì§€ 마ë¼.
- ëª¨ë“ íŠœë‹ íŒŒë¼ë¯¸í„°ë“¤ì€ ì˜ì‹¬í•´ì•¼ 한다. (ì´ê²Œ ë§Žë‹¤ê³ ì¢‹ì€ APIê°€ 아니ë¼ëŠ” 뜻)
세세한 êµ¬í˜„ì´ API ë¡œ í˜ëŸ¬ë“¤ì–´ê°€ê²Œ 해서는 안ëœë‹¤.
- ë””ìŠ¤í¬ ìƒì´ë‚˜, ë„¤íŠ¸ì›Œí¬ ìƒì´ë‚˜, 예외로ë¼ë„ !!!
- ëª¨ë“ ê²ƒì˜ ì ‘ê·¼ì„ ìµœì†Œí™”í•˜ë¼.가능한 private 하게 class 와 member를 만들어ë¼.
public class ê°€ (ìƒìˆ˜ì— 대한 예외와 함께) public field를 ê°€ì ¸ì„œëŠ” 안ëœë‹¤.ì´ë ‡ê²Œ í•´ì„œ ì •ë³´ì€í를 최대화하ë¼. (밖으로 드러나지 않게 Capsulation 하ë¼ëŠ” 뜻.)
ëª¨ë“ˆì´ ë…립ì 으로 debug ë˜ê³ , ì´í•´ë˜ì–´ì§€ê³ , 구축ë˜ì–´ì§€ê³ , 테스트 ë˜ì–´ì§€ë„ë¡ í•˜ë¼.
- ì´ë¦„ì´ ì¤‘ìš”í•˜ë‹¤. – API 는 ìž‘ì€ ì–¸ì–´ë‹¤.ì´ë¦„ì€ êµ³ì´ ì„¤ëª…í•˜ì§€ ì•Šì•„ë„ ì´í•´ë 수 있어야 한다.
- 기호나 ì¶•ì•½ì„ ì‚¬ìš©í•˜ì§€ 마ë¼.Consistent 하게 í•˜ë¼ â€“ ë˜‘ê°™ì€ ë‹¨ì–´ëŠ” ê°™ì€ ê²ƒì´ì–´ì•¼ 한다.
- API ì „ë°˜ì— ê±¸ì³ì„œ (API í”Œëž«í¼ ì „ë°˜ì— ê±¸ì³ì„œ!!!)
규칙ì ì´ì–´ì•¼ 한다. – 대ì¹ê³¼ ê· í˜•ì„ ê°ˆêµ¬í•˜ë¼.
코드는 산문처럼 ì½íž 수 있어야 한다. (얼마나 ì½ê¸° 쉬운가?)
if (car.speed() > 2 * SPEED_LIMIT)
generateAlert(“Watch out for cops!â€);
- 문서화가 중요하다.
ìž¬ì‚¬ìš©ì„±ì€ â€œìž¬ì‚¬ìš©í•œë‹¤â€ëŠ” Action 보다 â€œìž¬ì‚¬ìš©í•˜ê² ë‹¤.â€ê³ 쉽게 ë§í• 수 있는 ì–´ë–¤ 것ì´ì–´ì•¼ 한다. Action ì€ ì¢‹ì€ ë””ìžì¸ê³¼ ì¢‹ì€ ë¬¸ì„œë¥¼ 필요로 한다. ë¹„ë¡ ì•„ì£¼ ê°€ë” ìš°ë¦¬ê°€ ì¢‹ì€ ë””ìžì¸(설계, 아키í…ì³)ì„ ë³´ê²Œ ë˜ì—ˆë‹¤ê³ 하ë”ë¼ë„, 우리가 문서 ì—†ì´ ìž¬ì‚¬ìš©ë˜ì–´ì§ˆ ì •ë„ë¡œ ì¢‹ì€ ì»´í¬ë„ŒíŠ¸ë¥¼ ë³¼ 수는 없다. – D.L.Parnas, Software Aging, 1994
- 종êµì²˜ëŸ¼ 문서화하ë¼.â€ëª¨ë“ †class, interface, method, constructor, parameter, and exception ì„ ë¬¸ì„œí™”í•˜ë¼.
- class : instance í™” ë˜ëŠ” 것들
- method : method 와 ê·¸ client ë“¤ê°„ì˜ ê³„ì•½ë“¤ì´ë‹¤.
- parameter : units, form, ownership ë“±ì„ ì§€ì¹í•œë‹¤.state-space(ìƒíƒœê³µê°„, ì „ì²´ì ì¸ ê²ƒì— ëŒ€í•´)ì„ ì£¼ì˜ê¹Šê²Œ 문서화하ë¼.
- API ë””ìžì¸ì— 대한 ì„±ëŠ¥ê²°ê³¼ì— ëŒ€í•´ ê³ ë ¤í•˜ë¼.
ë‚˜ìœ ì˜ì‚¬ê²°ì •ì€ 성능 한계를 ë§Œë“¤ê¸°ë„ í•œë‹¤.
- type ì„ ìƒí˜¸ êµí™˜ê°€ëŠ¥í•˜ê²Œ 만들어ë¼.
- static factory ëŒ€ì‹ constructor 를 ì œê³µí•˜ë¼.
- interface ëŒ€ì‹ ì— implementation type ì„ ì‚¬ìš©í•˜ë¼.ì„±ëŠ¥ì„ ì–»ê¸° 위해 API를 뒤틀지 마ë¼. (변형하지 마ë¼)
- 기본ì ì¸ ì„±ëŠ¥ ì´ìŠˆëŠ” ê³ ì³ì§ˆ 것ì´ë‹¤. 하지만 ë‘í†µì´ ê·¸ëŒ€ì™€ 함께 ì˜ì›í• 것ì´ë‹¤.
- ì¢‹ì€ ë””ìžì¸ì€ ì¼ë°˜ì 으로 ì¢‹ì€ ì„±ëŠ¥ê³¼ ì¼ì¹˜í•œë‹¤.
- ì„±ëŠ¥ì„ ê³ ë ¤í•œ API 설계는 실질ì ì¸ íš¨ê³¼ë¡œ ë‚˜íƒ€ë‚ ë¿ ì•„ë‹ˆë¼ ì˜ì›í•˜ë‹¤.
- Component.getSize()는 Dimensionì„ return 한다.
- Dimension ì€ mutual 하다.
- ëª¨ë“ getSize call ì€ Dimensionì„ í• ë‹¹í•´ì•¼ë§Œ 한다.
- ìˆ˜ë§Žì€ ë¶ˆí•„ìš”í•œ object allocation ì´ ë°œìƒí•œë‹¤.
- ëŒ€ì²´ì•ˆì´ 1.2 ë²„ì „ì— ì¶”ê°€ëœë‹¤ : old client code 는 ì—¬ì „ížˆ ëŠë¦¬ë‹¤.
- API 는 플랫í¼ê³¼ í‰í™”ì 으로 공존해야만 한다.관습ì ì¸ ê²ƒì„ ë”°ë¼ë¼.
- 표준 naming rule ì„ ë”°ë¼ë¼.
- ë…ìžì ì¸ íŒŒë¼ë¯¸í„°ë‚˜ Return Typeì„ ì“°ì§€ë§ˆë¼.
- 코어 API나 ì–¸ì–´ì— ìžˆëŠ” íŒ¨í„´ì„ í‰ë‚´ë‚´ì–´ ì¨ë¼.API 친화ì ì¸ íŠ¹ì§•ì„ ì´ìš©í•˜ë¼.
- Generics, varargs, enums, default arguments
API ì˜ ìœ„í—˜ê³¼ 단ì ë“¤ì„ ìž˜ ì•Œê³ íšŒí”¼í•˜ë¼.
- Finalizers, public static final arrays
셋째. Class Design
- ë³€ê²½ì„ ìµœì†Œí™”í•˜ë¼.ë§Œì¼ ë‹¤ë¥¸ ì¼ì„ 해야 í• ì¶©ë¶„í•œ ì´ìœ ê°€ 없다면, class 는 ë¶ˆë³€ì˜ ê²ƒì´ì–´ì•¼ 한다.
- 장ì : simple, thread-safe, reusable
- 단ì : ê° value 별로 ë¶„ë¦¬ëœ object
ë§Œì¼ ë³€ê²½í•´ì•¼ 한다면, ìƒíƒœê³µê°„(state-space)를 작게 ìœ ì§€í•˜ê³ , ì •ì˜ë¥¼ 잘 ìœ ì§€í•˜ë¼.
- ì–¸ì œ, ì–´ë–¤ method를 부르는게 합리ì ì¸ì§€ë¥¼ 명확히 하ë¼.
Bad: Date, Calendar
Good: TimerTask
- subclass는 substitutability (대체성)를 ì˜ë¯¸í•œë‹¤.
- (..ì€..ì´ë‹¤)ë¼ëŠ” 관계가 ì¡´ìž¬í• ë•Œë§Œ subclass 를 ì¨ë¼.
- ê·¸ë ‡ì§€ 않으면, composition ì„ ì‚¬ìš©í•˜ë¼.Bad: Properties extends Hashtable, Stack extends Vector
Good: Set extends Collection
- ìƒì†ì„ 위해 ì„¤ê³„í•˜ê³ ë¬¸ì„œë¥¼ 남겨ë¼.
설계가 ê·¸ë ‡ê²Œ ë˜ì–´ 있지 ì•Šê³ ë¬¸ì„œê°€ 없다면, ìƒì†ì„ 못하게 만들어ë¼.ìƒì†ì´ëž€ 캡ìŠí™”와 ìƒì¶©í•œë‹¤.
- subclass 는 superclass ì˜ ì„¸ì„¸í•œ êµ¬í˜„ì— ë¯¼ê°í•˜ë‹¤.
ë§Œì¼ subclass 를 í—ˆë½í•œë‹¤ë©´, self-use를 문서화하ë¼.
- method가 어떻게 다른 method 를 사용하는지?
보수ì ì¸ ì •ì±… : ëª¨ë“ êµ¬ì²´ì ì¸ class 는 final ì´ë‹¤.
Bad: Many concrete classes in J2SE libraries
Good: AbstractSet, AbstractMap
넷째. Method Design
- ëª¨ë“ˆì´ í• ìˆ˜ 있는 ê²ƒì„ client ê°€ 하게 하지 마ë¼.boilerplate code ì— ëŒ€í•œ 필요를 줄여ë¼.
- boilerplate code 란 ì¼ë°˜ì 으로 cut-and-paste ë¡œ 행해지는 코드를 ë§í•œë‹¤.
- (ëª¨ë“ˆì„ cut&pasteí•´ì„œ client ë‚´ì— ë„£ì–´ë²„ë¦¬ë©´) 아주 ì¶”í•˜ê³ ë²ˆê±°ë¡ê³ , 오류 ë°œìƒì´ 잦다.
import org.w3c.dom.*;
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
// DOM code to write an XML document to a specified output stream.
private static final void writeDoc(Document doc, OutputStream out)throws IOException{
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId());
t.transform(new DOMSource(doc), new StreamResult(out));
} catch(TransformerException e) {
throw new AssertionError(e); // Can’t happen!
}
}
- “사용ìžë¥¼ 놀ë¼ê²Œ 하지 않기†ì›ì¹™ì„ 준수하ë¼.
API 사용ìžëŠ” behavior ì— ì˜í•´ 놀ë¼ì„œëŠ” 안ëœë‹¤.
- ê·¸ë ‡ê²Œ 하기 위해 êµ¬í˜„ì— ì¶”ê°€ì ì¸ ë…¸ë ¥ì„ ê¸°ìš¸ì¼ë§Œí•œ 가치가 있다.
- ê·¸ë¦¬ê³ , 조금 ì„±ëŠ¥ì„ ê¹Žì—¬ë„ ë 만한 가치가 있다.
public class Thread implements Runnable {
// Tests whether current thread has been interrupted.
// Clears the interrupted status of current thread.
public static boolean interrupted();
}
- 빨리 ì‹¤íŒ¨í•˜ë¼ â€“ ìž¥ì• ê°€ ë°œìƒë˜ë©´ 가능한한 빨리 ì—러를 ì•Œë ¤ë¼.ì»´íŒŒì¼ ì‹œê°„ì´ ì œì¼ ì¢‹ë‹¤. – static typing, generics
런타임ì—, 첫 ìž˜ëª»ëœ method invocation ì´ ì œì¼ ì¢‹ë‹¤.
- method 는 반드시 failure-atomic 해야 한다.
// A Properties instance maps strings to strings
public class Properties extends Hashtable {
public Object put(Object key, Object value);
// Throws ClassCastException if this properties
// contains any keys or values that are not strings
public void save(OutputStream out, String comments);
}
- String í¬ë§·ìœ¼ë¡œ 있는 ëª¨ë“ ë°ì´í„°ë¥¼ 프로그램 구조로 바꾸어ë¼.ê·¸ë ‡ê²Œ 하지 않으면, client 는 string ì„ parse 해야 한다.
- client 는 ê´´ë¡ë‹¤.
- ë” ë‚˜ìœ ê±´, string ì´ ì‚¬ì‹¤ìƒì˜ API ë¡œ 변질ë˜ì–´ 버린다.
public class Throwable {
public void printStackTrace(PrintStream s);
public StackTraceElement[] getStackTrace(); // Since 1.4
}
public final class StackTraceElement {
public String getFileName();
public int getLineNumber();
public String getClassName();
public String getMethodName();
public boolean isNativeMethod();
}
- 주ì˜ë¥¼ ê°€ì§€ê³ ì˜¤ë²„ë¡œë”© 하ë¼.모호한 오버로드는 피하ë¼.
- 여러 ê°œì˜ ì˜¤ë²„ë¡œë”©ì´ ë™ì‹œì— ì ìš©ë 수 있다.
- 보수ì ì´ ë˜ì–´ë¼ : ë™ì¼í•œ argument 숫ìžê°€ ì—†ë„ë¡ í•˜ë¼.ë‹¹ì‹ ì´ ëª¨í˜¸í•œ ì˜¤ë²„ë¡œë”©ì„ ì œê³µí•´ì•¼ 한다면, ë™ì¼í•œ argumentsì— ëŒ€í•´ì„œëŠ” ë™ì¼í•œ behavior ê°€ ì¼ì–´ë‚˜ê²Œ 하ë¼.
public TreeSet(Collection c); // Ignores order
public TreeSet(SortedSet s); // Respects order
- ì ì ˆí•œ 파ë¼ë¯¸í„°ì™€ ë¦¬í„´íƒ€ìž…ì„ ì‚¬ìš©í•˜ë¼.Input ì„ ìœ„í•´ class ì „ë°˜ì— interface type ì„ ìž¥ë ¤í•˜ë¼.
- ìœ ì—°ì„±ê³¼ ì„±ëŠ¥ì„ ì œê³µí•˜ë¼.가장 구체ì ì´ë©´ì„œ 가능한 input parameter type ë“¤ì„ ì‚¬ìš©í•˜ë¼.
- 런타임 시간으로부터 ì»´íŒŒì¼ ì‹œê°„ê¹Œì§€ ì—러를 옮겨ë¼.
ë” ì¢‹ì€ type ì´ ìžˆìœ¼ë©´, string ì„ ì‚¬ìš©í•˜ì§€ 마ë¼.
- string ì€ ë¬´ê²ê³ , ì—러가 나기 ì‰½ê³ , ëŠë¦¬ê¸°ê¹Œì§€ 하다.
통화를 í‘œí˜„í•˜ëŠ”ë° floating point 를 사용하지 마ë¼
- binary floating point 는 ë¶€ì •í™•í•œ 결과를 야기시킨다.
float(32 bits) 보다 double(64 bits)를 사용하ë¼.
- ì •í™•ì„± ì†ì‹¤ì€ 현실ì´ê³ , 성능 ì†ì‹¤ì€ ë¬´ì‹œí• ë§Œ 하다.
- method ì „ë°˜ì— ê±¸ì³ ì¼ê´€ì ì¸ parameter odering ì„ ì‚¬ìš©í•˜ë¼.특히 parameter type ë“¤ì´ ë™ì¼í• ë•Œ ë”ìš± 중요하다.
#include
char *strcpy (char *dest, char *src);
void bcopy (void *src, void *dst, int n);
java.util.Collections first parameter always collection to be modified or queried
java.util.concurrent – time always specified as long delay, TimeUnit unit
- Avoid Long Parameter Lists세 ê°œ, ë˜ëŠ” ë” ì ì€ ìˆ˜ì˜ íŒŒë¼ë¯¸í„°ë“¤ì´ ì´ìƒì ì´ë‹¤.
- ë” ë§Žë‹¤ë©´, 사용ìžë“¤ì€ 문서를 ì°¸ì¡°í•˜ë ¤ í• ê²ƒì´ë‹¤.ë˜‘ê°™ì´ íƒ€ì´í•‘ëœ íŒŒë¼ë¯¸í„°ë“¤ì˜ 긴 리스트는 위험하다.
- í”„ë¡œê·¸ëž˜ë¨¸ë“¤ì´ parameter 순서를 실수로 바꾸어버릴 ìˆ˜ë„ ìžˆë‹¤.
- í”„ë¡œê·¸ëž˜ë¨¸ë“¤ì´ ì—¬ì „ížˆ 컴파ì¼í•˜ê³ , 실행한다. 그러나 ê·¸ê²ƒì´ ìž˜ëª»ì¼ ìˆ˜ 있다.
파ë¼ë¯¸í„° 리스트를 ì§§ê²Œí• ìˆ˜ 있는 ë‘가지 ê¸°ë²•ì´ ìžˆë‹¤.
- method 를 ë‘개로 나누어ë¼.
- 파ë¼ë¯¸í„°ë¥¼ ìœ ì§€í• ìˆ˜ 있ë„ë¡ helper class 를 만들어ë¼.
// Eleven parameters including four consecutive ints
HWND CreateWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName,
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
LPVOID lpParam);
- 예외처리를 요구하는 return value를 만들지 마ë¼zero-length array를 리털하거나 빈 collection ì„ ë¦¬í„´í•˜ë¼. null ì„ ë¦¬í„´í•˜ì§€ 마ë¼.
package java.awt.image;
public interface BufferedImageOp {
// Returns the rendering hints for this operation,
// or null if no hints have been set.
public RenderingHints getRenderingHints();
}
다섯째. Exception Design
- 예외 ìƒí™©ì„ 표시하기 위해 exeption ì„ ë˜ì ¸ë¼.client ê°€ control flow 를 위해 exceptionì„ ì‚¬ìš©í•˜ë„ë¡ í•´ì„œëŠ” 안ëœë‹¤.
private byte[] a = new byte[BUF_SIZE];
void processBuffer (ByteBuffer buf) {
try {
while (true) {
buf.get(a);
processBytes(tmp, BUF_SIZE);
}
} catch (BufferUnderflowException e) {
int remaining = buf.remaining();
buf.get(a, 0, remaining);
processBytes(bufArray, remaining);
}
}
ì •ë°˜ëŒ€ë¡œ, 조용하게 fail ì´ ë‚˜ì„œëŠ” 안ëœë‹¤.
ThreadGroup.enumerate(Thread[] list)
- Unchecked Exceptions ì„ ì‚¬ìš©í•˜ë¼.. Checked – client ê°€ recovery action ì„ í•´ì•¼ 한다
. Unchecked – programming error
. Checked exceptions ì˜ ê³¼í•œ ì‚¬ìš©ì€ boilerplate 를 야기시킨다.
try {
Foo f = (Foo) super.clone();
….
} catch (CloneNotSupportedException e) {
// This can’t happen, since we’re Cloneable
throw new AssertionError();
}
- 예외 ì•ˆì— ì—ëŸ¬ì •ë³´(failure-capture information)를 í¬í•¨ì‹œì¼œë¼.ì§„ë‹¨ì„ í—ˆìš©í•˜ê³ repair 하거나 recovery 하ë¼.
unchecked exceptionì— ëŒ€í•´ì„œëŠ” 메시지로 충분하다.
checked exceptionì— ëŒ€í•´ì„œëŠ” accessor 를 ì œê³µí•˜ë¼.
여섯째. Refactoring API Designs
- Sublist Operations in Vector
public class Vector {
public int indexOf(Object elem, int index);
public int lastIndexOf(Object elem, int index);
…
}
매우 파워풀하지 않다. – 단지 ê²€ìƒ‰ë§Œì„ ì§€ì›í•œë‹¤.
ë¬¸ì„œì—†ì´ ì‚¬ìš©í•˜ê¸° 힘들다.
* Sublist Operations Refactored
public interface List {
List subList(int fromIndex, int toIndex);
…
}
매우 파워풀하다. ëª¨ë“ ë™ìž‘ì„ ì§€ì›í•œë‹¤.
ì¸í„°íŽ˜ì´ìŠ¤ ì‚¬ìš©ì´ ê°œë…ì 무게를 작게한다.
- power-to-weight ratio ê°€ 올ë¼ê°„다.
문서 ì—†ì´ë„ ì‚¬ìš©í• ìˆ˜ 있다.
- Thread-Local Variables
// Broken – inappropriate use of String as capability.
// Keys constitute a shared global namespace.
public class ThreadLocal {
private ThreadLocal() { } // Non-instantiable
// Sets current thread’s value for named variable.
public static void set(String key, Object value);
// Returns current thread’s value for named variable.
public static Object get(String key);
}
* Thread-Local Variables Refactored (1)
public class ThreadLocal {
private ThreadLocal() { } // Noninstantiable
public static class Key { Key() { } }
// Generates a unique, unforgeable key
public static Key getKey() { return new Key(); }
public static void set(Key key, Object value);
public static Object get(Key key);
}
ë™ìž‘하기는 한다. 그러나 ì‚¬ìš©í•˜ë ¤ë©´ boilerplate code ê°€ 필요하다.
static ThreadLocal.Key serialNumberKey = ThreadLocal.getKey();
ThreadLocal.set(serialNumberKey, nextSerialNumber());
System.out.println(ThreadLocal.get(serialNumberKey));
* Thread-Local Variables Refactored (2)
public class ThreadLocal {
public ThreadLocal() { }
public void set(Object value);
public Object get();
}
API나 client code 로부터 ìž¡ë™ì‚¬ë‹ˆë¥¼ ì—†ì• ë¼.
static ThreadLocal serialNumber = new ThreadLocal();
serialNumber.set(nextSerialNumber());
System.out.println(serialNumber.get());
ì¼ê³±ì§¸. ê²°ë¡
- API ë””ìžì¸ì€ ìš°ì•„í•˜ë©´ì„œë„ ëˆì„ 벌 수 있는 행위ì´ë‹¤.
- ë§Žì€ í”„ë¡œê·¸ëž˜ë¨¸ì™€ 사용ìžë“¤ê³¼ íšŒì‚¬ë“¤ì„ ì´ë¡ê²Œ 한다.
- ì´ ì´ì•¼ê¸°ëŠ” ì–´ë–¤ ì˜ë¯¸ì—ì„œ 휴리스틱한 ê¸°ë²•ë“¤ì„ ë®ì–´ë²„린다.
- ë…¸ì˜ˆê°™ì´ íœ´ë¦¬ìŠ¤í‹±í•œ ê¸°ìˆ ë“¤ì— ë‹¬ë¼ë¶™ì§€ 마ë¼.
- 충분한 ì´ìœ ì—†ì´ ê·¸ë“¤ì„ ì¹¨ë²”í•˜ì§€ë„ ë§ˆë¼.
- API ë””ìžì¸ì€ 힘들다.
- 혼ìží•˜ëŠ” ìž‘ì—…ì´ ì•„ë‹ˆë‹¤.
- ì™„ë²½í• ìˆ˜ 없다. 그러나 ì™„ë²½í•´ì§€ë ¤ê³ ì‹œë„하ë¼.
- 뻔뻔하게 스스로 Promotion 하ë¼.
최근 답글