CleanCode TIL (2022.02.02)

Henry Choยท2022๋…„ 2์›” 1์ผ
0

๋…ธ๊ฐœ๋ถ

๋ชฉ๋ก ๋ณด๊ธฐ
13/31

DAY 13

๐Ÿ”–ย ์˜ค๋Š˜ ์ฝ์€ ๋ฒ”์œ„ : 7. ์˜ค๋ฅ˜์ฒ˜๋ฆฌ (130~137p)


๐Ÿค“ย ์ฑ…์—์„œ ๊ธฐ์–ตํ•˜๊ณ  ์‹ถ์€ ๋‚ด์šฉ

์˜ค๋ฅ˜ ์ฝ”๋“œ๋ณด๋‹ค ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

  • ์˜ˆ์™ธ์ฒ˜๋ฆฌ๊ฐ€ ์•„๋‹Œ ์˜ค๋ฅ˜ ์ฝ”๋“œ๋ฐ˜ํ™˜ ๋ฐฉ์‹์„ ์“ฐ๋ฉด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ์ฆ‰์‹œ ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•ด์•ผํ•œ๋‹ค
  • ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ ธ๋ผ โ†’ ํ˜ธ์ถœ์ž ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•ด์ง€๊ณ  ๋…ผ๋ฆฌ์™€ ์˜ค๋ฅ˜์ฒ˜๋ฆฌ๊ฐ€ ๋’ค์„ž์ด์ง€ ์•Š์Œ
    public class DeviceController {
        ...
        public void sendShutDown() {
            try {
                tryToShutDown();
            } catch (DeviceShutDownError e) {
                logger.log(e);
            }
        }
        private void tryToShutDown() throws DeviceShutDownError {
            DeviceHandle handle = getHandle(DEV1);
            DeviceRecord record = retrieveDeviceRecord(handle);
            pauseDevice(handle);
            clearDeviceWorkQueue(handle);
            closeDevice(handle);
        }
        private DeviceHandle getHandle(DeviceID id) { ...
                throw new DeviceShutDownError("Invalid handle for: " + id.toString());
                ...
            }
            ...
    }

Try-Catch-Finally ๋ฌธ๋ถ€ํ„ฐ ์ž‘์„ฑํ•˜๋ผ

  • try ๋ธ”๋ก์€ ํŠธ๋žœ์žญ์…˜๊ณผ ๋น„์Šท
  • try ๋ธ”๋ก์—์„œ ๋ฌด์Šจ ์ผ์ด ์ƒ๊ธฐ๋“ ์ง€ catch ๋ธ”๋ก์€ ํ”„๋กœ๊ทธ๋žจ ์ƒํƒœ๋ฅผ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์œ ์ง€
  • ํŒŒ์ผ์ด ์—†์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š”์ง€ ์•Œ์•„๋ณด๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
    @Test(expected = StorageException.class)
    public void retrieveSectionShouldThrowOnInvalidFileName() {
    	sectionStore.retrieveSection("invalid - file"); 
    }
    public List<RecordedGrip> retrieveSection(String sectionName) { 
    	// ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•  ๋•Œ๊นŒ์ง€ ๋น„์–ด ์žˆ๋Š” ๋”๋ฏธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    	return new ArrayList<RecordedGrip>();
    }
    ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์‹คํŒจ โ†’ ์ž˜๋ชป๋œ ํŒŒ์ผ ์ ‘๊ทผ์œผ๋กœ ๋ณ€๊ฒฝ
    public List < RecordedGrip > retrieveSection(String sectionName) {
        try {
            FileInputStream stream = new FileInputStream(sectionName)
        } catch (Exception e) {
            throw new StorageException("retrieval error", e);
        }
        return new ArrayList < RecordedGrip > ();
    }
    Refactoring: catch ์˜ˆ์™ธ ์œ ํ˜• ๋ฒ”์œ„๋ฅผ ์ขํžŒ๋‹ค Exception โ†’ FileNotFoundException
    public List < RecordedGrip > retrieveSection(String sectionName) {
        try {
            FileInputStream stream = new FileInputStream(sectionName);
            stream.close();
        } catch (FileNotFoundException e) {
            throw new StorageException("retrieval error", e);
        }
        return new ArrayList < RecordedGrip > ();
    }
    ๋‚˜๋จธ์ง€ ํ•„์š”ํ•œ ๋…ผ๋ฆฌ๋ฅผ TDD๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค
  1. ๊ฐ•์ œ๋กœ ์˜ˆ์™ธ๋ฅผ ์ผ์œผํ‚ค๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑ
  2. ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ
  3. try๋ธ”๋ก์˜ ํŠธ๋ž™์žญ์…˜ ๋ฒ”์œ„๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•˜๊ฒŒ๋˜๋ฏ€๋กœ ํŠธ๋žœ์žญ์…˜ ๋ณธ์งˆ์„ ์œ ์ง€ํ•˜๊ณ  ๋กœ์ง ์ถ”๊ฐ€์— ์šฉ์ดํ•˜๋‹ค

๋ฏธํ™•์ธ ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

  • ํ™•์ธ๋œ ์˜ˆ์™ธ๋Š” OpenClosedPrinciple ์„ ์œ„๋ฐ˜ํ•œ๋‹ค
    • ํ•˜์œ„ ๋‹จ๊ณ„์—์„œ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ƒ์œ„ ๋‹จ๊ณ„ ๋ฉ”์„œ๋“œ ์„ ์–ธ๋ถ€ ์ „๋ถ€ ๊ณ ์ณ์•ผํ•จ
    • throws ๊ฒฝ๋กœ์— ์œ„์น˜ํ•˜๋Š” ๋ชจ๋“  ํ•จ์ˆ˜๊ฐ€ ์ตœํ•˜์œ„ ํ•จ์ˆ˜์—์„œ ๋˜์ง€๋Š” ์˜ˆ์™ธ๋ฅผ ์•Œ์•„์•ผ ํ•˜๋ฏ€๋กœ ์บก์Šํ™”๊ฐ€ ๊นจ์ง
  • ํ™•์ธ๋œ ์˜ˆ์™ธ๋„ ์œ ์šฉํ•˜๊ธด ํ•˜์ง€๋งŒ ์˜์กด์„ฑ ๋น„์šฉ์„ ์ค„์ด๋Š”๊ฒŒ ๋” ์ค‘์š”ํ•˜๋ฏ€๋กœ ๋ฏธํ™•์ธ(unchecked) ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค

์˜ˆ์™ธ์— ์˜๋ฏธ๋ฅผ ์ œ๊ณตํ•˜๋ผ

  • ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ์ •๋ณด๋ฅผ ๋‹ด์•„ ์˜ˆ์™ธ์™€ ํ•จ๊ป˜ ๋˜์ง„๋‹ค
  • ์‹คํŒจํ•œ ์—ฐ์‚ฐ ์ด๋ฆ„๊ณผ ์‹คํŒจ ์œ ํ˜•๋„ ์–ธ๊ธ‰
  • APP ์—์„œ ๋กœ๊น…๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ• ๋•Œ ์ถฉ๋ถ„ํžˆ ์ •๋ณด๋ฅผ ํ™œ์šฉํ•˜๋„๋ก catch ๋ธ”๋ก์—์„œ ์˜ค๋ฅ˜ ์ถœ๋ ฅ

ํ˜ธ์ถœ์ž๋ฅผ ๊ณ ๋ คํ•ด ์˜ˆ์™ธ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋ผ

  • ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ด€์‹ฌ์‚ฌ๋Š” ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋‚ด๋Š” ๋ฐฉ๋ฒ•
  • wrapper ํด๋ž˜์Šค ํ™œ์šฉํ•˜์—ฌ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ
    LocalPort port = new LocalPort(12);
    try {
        port.open();
    } catch (PortDeviceFailure e) {
        reportError(e);
        logger.log(e.getMessage(), e);
    } finally {
        ...
    }
    public class LocalPort {
        private ACMEPort innerPort;
        public LocalPort(int portNumber) {
            innerPort = new ACMEPort(portNumber);
        }
        public void open() {
                try {
                    innerPort.open();
                } catch (DeviceResponseException e) {
                    throw new PortDeviceFailure(e);
                } catch (ATM1212UnlockedException e) {
                    throw new PortDeviceFailure(e);
                } catch (GMXError e) {
                    throw new PortDeviceFailure(e);
                }
            }
            ...
    }
    • ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋กœ๊ทธ๋žจ ์‚ฌ์ด์—์„œ ์˜์กด์„ฑ์ด ํฌ๊ฒŒ ์ค„์–ด๋“ฌ
    • ๋‚˜์ค‘์— ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๊ฐˆ์•„ํƒ€๋„ ๋น„์šฉ์ด ์ ์Œ
    • ์™ธ๋ถ€ API ํ˜ธ์ถœ ๋Œ€์‹  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์„œ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ๋„ ์šฉ์ด
    • ํŠน์ • ์—…์ฒด๊ฐ€ API๋ฅผ ์„ค๊ณ„ํ•œ ๋ฐฉ์‹์— ๋ฐœ๋ชฉ ์žกํžˆ์ง€ ์•Š์Œ

๐Ÿค”ย ๋– ์˜ค๋ฅด๋Š” ์ƒ๊ฐ

  • ํ•™๋ถ€์ƒ ๋•Œ๋Š” ์—๋Ÿฌ์ฒ˜๋ฆฌ๊ฐ€ ๊ท€์ฐฎ๋‹ค๊ณ ๋งŒ ๋Š๊ปด์กŒ๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ์ „, ํ›„์˜ ์ฝ”๋“œ๋ฅผ ๋†“๊ณ  ๋น„๊ตํ•˜๋‹ˆ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์—ญ์‹œ Cleanํ•ด์•ผ ํ•จ์„ ํ•œ ๋ˆˆ์— ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค

๐Ÿ”Žย ์งˆ๋ฌธ

๐Ÿ“ย ์†Œ๊ฐ 3์ค„ ์š”์•ฝ

  • ์˜ค๋ฅ˜๋ณด๋‹ค (๋ฏธํ™•์ธ)์˜ˆ์™ธ๋ฅผ ํ™œ์šฉํ•˜๋ผ
  • ์˜ˆ์™ธ๋ฅผ ์ผ์œผํ‚ค๋Š” try-catch ๋จผ์ € ์™„์„ฑ ์‹œํ‚ค๊ณ  ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜์ž
  • Error wrapper class ๋ฅผ ํ™œ์šฉํ•ด์„œ ์˜์กด์„ฑ์„ ์ค„์ด์ž
profile
Full stack tech visionary

0๊ฐœ์˜ ๋Œ“๊ธ€