ํ•จ์ˆ˜(Function)

์ž‘๊ฒŒ ๋งŒ๋“ค๊ธฐ.

public static String renderPageWithSetupsAndTeardowns( PageData pageData, boolean isSuite) throws Exception {
    boolean isTestPage = pageData.hasAttribute("Test");
    if (isTestPage) {
        WikiPage testPage = pageData.getWikiPage();
        StringBuffer newPageContent = new StringBuffer();
        includeSetupPages(testPage, newPageContent, isSuite);
        newPageContent.append(pageData.getContent());
        includeTeardownPages(testPage, newPageContent, isSuite);
        pageData.setContent(newPageContent.toString());
    }
    return pageData.getHtml();
}

์œ„ ์ฝ”๋“œ๋„ ๊ธธ๋‹ค. ๋˜๋„๋ก ํ•œ ํ•จ์ˆ˜๋‹น 3~5์ค„ ์ด๋‚ด๋กœ ์ค„์ด๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค

public static String renderPageWithSetupsAndTeardowns( PageData pageData, boolean isSuite) throws Exception {
    if (isTestPage(pageData))
        includeSetupAndTeardownPages(pageData, isSuite);
    return pageData.getHtml();
}

๋ธ”๋ก๊ณผ ๋“ค์—ฌ์“ฐ๊ธฐ

์ค‘์ฒฉ๊ตฌ์กฐ(if/else, while๋ฌธ ๋“ฑ)์— ๋“ค์–ด๊ฐ€๋Š” ๋ธ”๋ก์€ ํ•œ ์ค„์ด์–ด์•ผ ํ•œ๋‹ค. ๊ฐ ํ•จ์ˆ˜ ๋ณ„ ๋“ค์—ฌ์“ฐ๊ธฐ ์ˆ˜์ค€์ด 2๋‹จ์„ ๋„˜์–ด์„œ์ง€ ์•Š๊ณ , ๊ฐ ํ•จ์ˆ˜๊ฐ€ ๋ช…๋ฐฑํ•˜๋‹ค๋ฉด ํ•จ์ˆ˜๋Š” ๋”์šฑ ์ฝ๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›Œ์ง„๋‹ค.

ํ•œ ๊ฐ€์ง€๋งŒ ํ•ด๋ผ

ํ•จ์ˆ˜๋Š” ํ•œ๊ฐ€์ง€๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ ํ•œ๊ฐ€์ง€๋ฅผ ์ž˜ ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ ํ•œ๊ฐ€์ง€๋งŒ์„ ํ•ด์•ผ ํ•œ๋‹ค. ์ง€์ •๋œ ํ•จ์ˆ˜ ์ด๋ฆ„ ์•„๋ž˜์—์„œ ์ถ”์ƒํ™” ์ˆ˜์ค€์ด ํ•˜๋‚˜์ธ ๋‹จ๊ณ„๋งŒ ์ˆ˜ํ–‰ํ•œ๋‹ค๋ฉด ๊ทธ ํ•จ์ˆ˜๋Š” ํ•œ ๊ฐ€์ง€ ์ž‘์—…๋งŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

ํ•จ์ˆ˜ ๋‚ด ์„น์…˜

ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ ์„น์…˜(์„ ์–ธ, ์ดˆ๊ธฐํ™” ๋“ฑ๋“ฑ)์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ทธ ํ•จ์ˆ˜๋Š” ์—ฌ๋Ÿฌ์ž‘์—…์„ ํ•˜๋Š” ์…ˆ์ด๋‹ค.

ํ•จ์ˆ˜ ๋‹น ์ถ”์ƒํ™” ์ˆ˜์ค€์€ ํ•˜๋‚˜๋กœ ํ•˜๊ธฐ

ํ•จ์ˆ˜๊ฐ€ โ€˜ํ•œ๊ฐ€์ง€โ€™ ์ž‘์—…๋งŒ ํ•˜๋ ค๋ฉด ํ•จ์ˆ˜ ๋‚ด ๋ชจ๋“  ๋ฌธ์žฅ์˜ ์ถ”์ƒํ™” ์ˆ˜์ค€์ด ๋™์ผํ•ด์•ผ ๋œ๋‹ค. ๋งŒ์•ฝ ํ•œ ํ•จ์ˆ˜ ๋‚ด์— ์ถ”์ƒํ™” ์ˆ˜์ค€์ด ์„ž์ด๊ฒŒ ๋œ๋‹ค๋ฉด ์ฝ๋Š” ์‚ฌ๋žŒ์ด ํ—ท๊ฐˆ๋ฆฐ๋‹ค.

์œ„์—์„œ ์•„๋ž˜๋กœ ์ฝ”๋“œ ์ฝ๊ธฐ:๋‚ด๋ ค๊ฐ€๊ธฐ ๊ทœ์น™

์ฝ”๋“œ๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ ์ด์•ผ๊ธฐ์ฒ˜๋Ÿผ ์ฝํ˜€์•ผ ์ข‹๋‹ค. ํ•จ์ˆ˜ ์ถ”์ƒํ™” ๋ถ€๋ถ„์ด ํ•œ๋ฒˆ์— ํ•œ๋‹จ๊ณ„์”ฉ ๋‚ฎ์•„์ง€๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ด์ƒ์ ์ด๋‹ค.(๋‚ด๋ ค๊ฐ€๊ธฐ ๊ทœ์น™)

Switch๋ฌธ

Bad Example

public Money calculatePay(Employee e) throws InvalidEmployeeType {
    switch (e.type) {
        case COMMISSIONED:
            return calculateCommissionedPay(e);
        case HOURLY:
            return calculateHourlyPay(e);
        case SALARIED:
            return calculateSalariedPay(e);
        default:
            throw new InvalidEmployeeType(e.type);
    }
}
  • ํ•จ์ˆ˜๊ฐ€ ๊ธธ๋‹ค. (์ƒˆ ์ง์› ์œ ํ˜•์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋” ๊ธธ์–ด์ง„๋‹ค.)
  • ํ•œ ๊ฐ€์ง€์ž‘์—…๋งŒ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • SRP(Single Responsibility Principle)๋ฅผ ์œ„๋ฐ˜ํ•œ๋‹ค. (์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ด์œ ๊ฐ€ ์—ฌ๋Ÿฟ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.)
  • OCP(Open Closed Principle)๋ฅผ ์œ„๋ฐ˜ํ•œ๋‹ค.(์ƒˆ ์ง์› ์œ ํ˜•์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.)

Good Example

public abstract class Employee {
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliverPay(Money pay);
}
-----------------
public interface EmployeeFactory {
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
-----------------
public class EmployeeFactoryImpl implements EmployeeFactory {
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
        switch (r.type) {
            case COMMISSIONED:
                return new CommissionedEmployee(r) ;
            case HOURLY:
                return new HourlyEmployee(r);
            case SALARIED:
                return new SalariedEmploye(r);
            default:
                throw new InvalidEmployeeType(r.type);
        }
    }
}

switch๋ฌธ์€ ์ž‘๊ฒŒ ๋งŒ๋“ค๊ธฐ ์–ด๋ ต์ง€๋งŒ(if/else์˜ ์—ฐ์† ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€!), ๋‹คํ˜•์„ฑ์„ ์ด์šฉํ•˜์—ฌ switch๋ฌธ์„ abstract factory์— ์ˆจ๊ฒจ ๋‹คํ˜•์  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ ์•ˆ์—์„œ๋งŒ switch๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค.

์„œ์ˆ ์ ์ธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ธฐ

์ด๋ฆ„์ด ๊ธธ์–ด๋„ ๊ดœ์ฐฎ๋‹ค. ๊ฒ๋จน์„ ํ•„์š”์—†๋‹ค. ๊ธธ๊ณ  ์„œ์ˆ ์ ์ธ ์ด๋ฆ„์ด ์งง๊ณ  ์–ด๋ ค์šด ์ด๋ฆ„๋ณด๋‹ค ์ข‹๋‹ค.

ํ•จ์ˆ˜ ์ธ์ˆ˜

ํ•จ์ˆ˜์—์„œ ์ด์ƒ์ ์ธ ์ธ์ˆ˜ ๊ฐœ์ˆ˜๋Š” 0๊ฐœ(๋ฌดํ•ญ). ์ธ์ˆ˜๋Š” ์ฝ”๋“œ ์ดํ•ด์— ๋ฐฉํ•ด๊ฐ€ ๋˜๋Š” ์š”์†Œ์ด๋ฏ€๋กœ ์ตœ์„ ์€ 0๊ฐœ์ด๊ณ , ์ฐจ์„ ์€ 1๊ฐœ๋ฟ์ธ ๊ฒฝ์šฐ์ด๋‹ค. ์ถœ๋ ฅ์ธ์ˆ˜(ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์ด ์•„๋‹Œ ์ž…๋ ฅ ์ธ์ˆ˜๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ)๋Š” ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šฐ๋ฏ€๋กœ ์™ ๋งŒํ•˜๋ฉด ์“ฐ์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ๋‹ค.

๋‹จํ•ญ ํ˜•์‹

  • ์ธ์ˆ˜์— ์งˆ๋ฌธ์„ ๋˜์ง€๋Š” ๊ฒฝ์šฐ : boolean fileExists(โ€œMyFileโ€);
  • ์ธ์ˆ˜๋ฅผ ๋ญ”๊ฐ€๋กœ ๋ณ€ํ™˜ํ•ด ๊ฒฐ๊ณผ๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ : InputStream fileOpen("MyFile");
  • ์ด๋ฒคํŠธ ํ•จ์ˆ˜์ผ ๊ฒฝ์šฐ (์ด ๊ฒฝ์šฐ์—๋Š” ์ด๋ฒคํŠธ๋ผ๋Š” ์‚ฌ์‹ค์ด ์ฝ”๋“œ์— ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚˜์•ผ ํ•œ๋‹ค.)

ํ”Œ๋ž˜๊ทธ ์ธ์ˆ˜

ํ”Œ๋ž˜๊ทธ ์ธ์ˆ˜๋Š” ์ถ”ํ•˜๋‹ค. ์“ฐ์ง€๋งˆ๋ผ. bool ๊ฐ’์„ ๋„˜๊ธฐ๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๊ทธ ํ•จ์ˆ˜๋Š” ํ•œ๊บผ๋ฒˆ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ผ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค๊ณ  ๊ณตํ‘œํ•˜๋Š” ๊ฒƒ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค.

์ดํ•ญ ํ•จ์ˆ˜

๋‹จํ•ญ ํ•จ์ˆ˜๋ณด๋‹ค ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค. Point ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ์—๋Š” ์ดํ•ญ ํ•จ์ˆ˜๊ฐ€ ์ ์ ˆํ•˜๋‹ค. 2๊ฐœ์˜ ์ธ์ˆ˜๊ฐ„์˜ ์ž์—ฐ์ ์ธ ์ˆœ์„œ๊ฐ€ ์žˆ์–ด์•ผํ•จ ๋ฌด์กฐ๊ฑด ๋‚˜์œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์ธ์ˆ˜๊ฐ€ 2๊ฐœ์ด๋‹ˆ ๋งŒํผ ์ดํ•ด๊ฐ€ ์–ด๋ ต๊ณ  ์œ„ํ—˜์ด ๋”ฐ๋ฅด๋ฏ€๋กœ ๊ฐ€๋Šฅํ•˜๋ฉด ๋‹จํ•ญ์œผ๋กœ ๋ฐ”๊พธ๋„๋ก

  • ์ž์—ฐ์Šค๋Ÿฌ์šด ์ดํ•ด : assertEquals(expected, actual), Point p = new Point(x,y);

์‚ผํ•ญ ํ•จ์ˆ˜

์ดํ•ดํ•˜๊ธฐ ํ›จ์”ฌ ์–ด๋ ค์šฐ๋ฏ€๋กœ ์ตœ๋Œ€ํ•œ ์ž์ œํ•˜์ž. ์‚ผํ•ญ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•˜๋ผ.

์ธ์ˆ˜ ๊ฐ์ฒด

๊ฐœ๋…์„ ํ‘œํ˜„ํ•˜๊ธฐ.

Circle makeCircle(double x, double y, double radius); // bad
Circle makeCircle(Point center, double radius); // good

์ธ์ˆ˜ ๋ชฉ๋ก

๋•Œ๋กœ๋Š” String.format๊ฐ™์€ ํ•จ์ˆ˜๋“ค์ฒ˜๋Ÿผ ์ธ์ˆ˜ ๊ฐœ์ˆ˜๊ฐ€ ๊ฐ€๋ณ€์ ์ธ ํ•จ์ˆ˜๋„ ํ•„์š”ํ•˜๋‹ค. String.format์˜ ์ธ์ˆ˜๋Š” Listํ˜• ์ธ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ดํ•ญํ•จ์ˆ˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋™์‚ฌ๋‚˜ ํ‚ค์›Œ๋“œ

๋‹จํ•ญ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜์™€ ์ธ์ˆ˜๊ฐ€ ๋™์‚ฌ/๋ช…์‚ฌ ์Œ์„ ์ด๋ค„์•ผํ•œ๋‹ค.

write(name); // bad
writeField(name); // good

ํ•จ์ˆ˜์ด๋ฆ„์— ํ‚ค์›Œ๋“œ(์ธ์ˆ˜ ์ด๋ฆ„)์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ธ์ˆ˜ ์ˆœ์„œ๋ฅผ ๊ธฐ์–ตํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ง„๋‹ค.

assertEquals(expected, actual);
assertExpectedEqualsActual(expected, actual);

๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์ผ์œผํ‚ค์ง€ ๋ง๊ธฐ

Bad Example

public class UserValidator {
    private Cryptographer cryptographer;
    public boolean checkPassword(String userName, String password) {
        User user = UserGateway.findByName(userName);
        if (user != User.NULL) {
            String codedPhrase = user.getPhraseEncodedByPassword();
            String phrase = cryptographer.decrypt(codedPhrase, password);
            if ("Valid Password".equals(phrase)) {
                Session.initialize(); // ๊ธฐ๋Šฅ
                return true;
            }
        }
        return false;
    }
}

๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™•์ธํ•˜๋Š” Method์— Session ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํฌํ•จ๋˜์–ด์žˆ๋‹ค. ํ•œ Method์— ๋‘๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ํ•˜๊ณ  ์žˆ๋‹ค. ์ข‹์ง€ ๋ชปํ•œ ํ•จ์ˆ˜์ด๋‹ค.

์ถœ๋ ฅ์ธ์ˆ˜

์ผ๋ฐ˜์ ์œผ๋กœ ์ถœ๋ ฅ ์ธ์ˆ˜๋Š” ํ”ผํ•ด์•ผ ํ•œ๋‹ค. ํ•จ์ˆ˜์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค๋ฉด ํ•จ์ˆ˜๊ฐ€ ์†ํ•œ ๊ฐ์ฒด ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์„ ํƒํ•˜๋ผ.

๋ช…๋ น๊ณผ ์กฐํšŒ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ผ

public boolean set(String attribute, String value); : ๋‘๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ํ•˜๊ณ  ์žˆ๋‹ค. ์„ค์ •ํ•˜๋Š” ๊ฒƒ๊ณผ ์„ค์ •์ด ์„ฑ๊ณตํ–ˆ๋Š”์ง€ ์‹คํŒจํ–ˆ๋Š”์ง€. if(set(โ€œusernameโ€, โ€œunclebobโ€))... : ์ด์ƒํ•œ ํ•จ์ˆ˜์˜ ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

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

์žฅํ™ฉํ•œ if์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์ดํ•ด๋„๊ฐ€ ๋–จ์–ด์ง„๋‹ค.

Bad Example

if (deletePage(page) == E_OK) {
    if (registry.deleteReference(page.name) == E_OK) {
        if (configKeys.deleteKey(page.name.makeKey()) == E_OK) {
            logger.log("page deleted");
        } else {
            logger.log("configKey not deleted");
        }
    } else {
        logger.log("deleteReference from registry failed");
    }
} else {
    logger.log("delete failed"); return E_ERROR;
}

์˜ค๋ฅ˜ ์ฝ”๋“œ ๋Œ€์‹  ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์›๋ž˜ ์ฝ”๋“œ์—์„œ ๋ถ„๋ฆฌ๋˜๋ฏ€๋กœ ์ฝ”๋“œ๊ฐ€ ๊น”๊ธˆํ•ด์ง„๋‹ค.

Good Example

try{
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}catch(Exception e){
  logger.log(e.getMessage());
}

Try/Catch ๋ฝ‘์•„๋‚ด๊ธฐ

Try/Catch ๋ธ”๋ก์„ ๋ณ„๋กœ ํ•จ์ˆ˜๋กœ ๋ฝ‘์•„๋‚ด๋Š” ํŽธ์ด ์ข‹๋‹ค.

Best Example

public void delete(Page page) {
    try {
        deletePageAndAllReferences(page);
      } catch (Exception e) {
          logError(e);
      }
}
 
private void deletePageAndAllReferences(Page page) throws Exception {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name.makeKey());
}
 
private void logError(Exception e) {
    logger.log(e.getMessage());
}

์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋„ ํ•œ๊ฐ€์ง€ ์ž‘์—…์ด๋‹ค.

public enum Error {
    OK,
    INVALID,
    NO_SUCH,
    LOCKED,
    OUT_OF_RESOURCES,     
    WAITING_FOR_EVENT;
}

์˜ค๋ฅ˜ ์ฝ”๋“œ๊ฐ€ ์ •์˜๋˜์–ด์žˆ๋‹ค๋ฉด ์ƒˆ ์˜ค๋ฅ˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ํž˜๋“ค๊ณ  ์žฌ์ปดํŒŒ์ผ/์žฌ๋ฐฐ์น˜๊ฐ€ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. ๊ธฐ์กด์˜ java Exception์„ ์‚ฌ์šฉํ•˜๊ฒŒ๋œ๋‹ค๋ฉด ์žฌ์ปดํŒŒ์ผ/์žฌ๋ฐฐ์น˜ ์—†์ด๋„ ์ƒˆ ์˜ˆ์™ธ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜๋ณตํ•˜์ง€ ๋งˆ๋ผ!

์ค‘๋ณต์€ ๋ชจ๋“  ์†Œํ”„ํŠธ์›จ์–ด์—์„œ ๋ชจ๋“  ์•…์˜ ๊ทผ์›์ด๋ฏ€๋กœ ๋Š˜ ์ค‘๋ณต์„ ์—†์• ๋„๋ก ๋…ธ๋ ฅํ•ด์•ผํ•œ๋‹ค.

๊ตฌ์กฐ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ

ํ•จ์ˆ˜๋Š” return๋ฌธ์ด ํ•˜๋‚˜์—ฌ์•ผ ๋˜๋ฉฐ, ๋ฃจํ”„ ์•ˆ์—์„œ break๋‚˜ continue๋ฅผ ์‚ฌ์šฉํ•ด์„  ์•ˆ๋œ๋ฉฐ goto๋Š” ์ ˆ๋Œ€๋กœ, ์ ˆ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž.