단순해진 깨끗한 코드 - 1부
이 책에서 배운 팁, 요령 및 사례를 모아서 여러 부분으로 게시할 예정입니다.
Note that there are quotes and code examples that I’ve used from the original book in this series.
더 이상 고민하지 않고 시작하겠습니다.
#1 짧은 함수가 더 좋습니다
밥 아저씨가 함수의 길이에 대해 말하는 것은 함수가 작을수록 좋다는 것입니다.
그는
if
문, else
문 및 while
문 내의 코드 블록이 한 줄이어야 한다고 제안합니다. 또한 함수의 들여쓰기 수준은 1 또는 2를 넘지 않아야 합니다.할 수 있다면 좋은 습관입니다. 이 규칙을 항상 엄격하게 준수할 수는 없지만 가능한 한 많이 하려고 노력하십시오.
#2 가능한 경우 인스턴스 변수를 도입하십시오.
기본 매개변수 대신 인스턴스 변수를 함수에 전달하는 것은 적절할 때 좋은 생각입니다. 하지만 언제가 적당할까요?
내부에 많은 변수가 선언된 큰 함수를 고려하십시오. 해당 함수의 작은 부분을 별도의 함수로 추출하고 싶다고 가정해 보겠습니다. 그러나 추출하려는 코드는 함수에 선언된 변수 중 4개를 사용합니다.
이것은 인스턴스 변수를 전달하는 것이 좋은 생각일 수 있는 상황입니다.
class Sample
{
public function __construct()
{
}
public function render()
{
// doing some logic
$this->getHtml($var1, $var2, $var3, $var4);
}
private function getHtml($var1, $var2, $var3, $var4)
{
// doing some logic with vars
}
}
될 것입니다:
class Sample
{
private $var;
public function __construct(VarThing $var)
{
$this->var = $var;
}
public function render()
{
// doing some logic
$this->getHtml();
}
private function getHtml()
{
// $this->var is accessible here
}
}
#3 BUILD-OPERAATE-CHECK 패턴
Build-Operate-Check
패턴과 유사한 Arrange-Act-Assert 또는 AAA 패턴에 대해 들어본 적이 있을 것입니다.다음 코드를 어떻게 개선할 수 있다고 생각하십니까?
public function testGetPageHieratchyAsXml()
{
crawler()->addPage($root, PathParser()->parse("PageOne"));
crawler()->addPage($root,
PathParser()->parse("PageOne.ChildOne"));
crawler()->addPage($root, PathParser()->parse("PageTwo"));
request()->setResource("root");
request()->addInput("type", "pages");
$responder = new SerializedPageResponder();
$response = $responder->makeResponse(
new FitNesseContext($root), $request
);
$xml = $response->getContent();
assertEquals("text/xml", $response->getContentType());
assertSubString("<name>PageOne</name>", $xml);
assertSubString("<name>PageTwo</name>", $xml);
assertSubString("<name>ChildOne</name>", $xml);
}
public function testGetPageHieratchyAsXmlDoesntContainSymbolicLinks()
{
$pageOne = crawler()->addPage($root,
PathParser()->parse("PageOne"));
crawler()->addPage($root,
PathParser()->parse("PageOne.ChildOne"));
crawler()->addPage($root, PathParser()->parse("PageTwo"));
$data = $pageOne->getData();
$properties = $data->getProperties();
$symLinks = $properties->set(SymbolicPage::PROPERTY_NAME);
$symLinks.set("SymPage", "PageTwo");
$pageOne.commit($data);
request()->setResource("root");
request()->addInput("type", "pages");
$responder = new SerializedPageResponder();
$response = $responder->makeResponse(
new FitNesseContext($root), $request);
$xml = $response->getContent();
assertEquals("text/xml", $response->getContentType());
assertSubString("<name>PageOne</name>", $xml);
assertSubString("<name>PageTwo</name>", $xml);
assertSubString("<name>ChildOne</name>", $xml);
assertNotSubString("SymPage", $xml);
}
public function testGetDataAsHtml()
{
crawler()->addPage($root, PathParser()
->parse("TestPageOne"), "test page");
request()->setResource("TestPageOne");
request()->addInput("type", "data");
$responder = new SerializedPageResponder();
$response = $responder->makeResponse(
new FitNesseContext($root), $request);
$xml = $response->getContent();
assertEquals("text/xml", $response->getContentType());
assertSubString("test page", $xml);
assertSubString("<Test", $xml);
}
개선할 수 있는 방법은 다음과 같습니다.
public function testGetPageHierarchyAsXml()
{
makePages("PageOne", "PageOne.ChildOne", "PageTwo");
submitRequest("root", "type:pages");
assertResponseIsXML();
assertResponseContains("<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>");
}
public function testSymbolicLinksAreNotInXmlPageHierarchy()
{
$page = makePage("PageOne");
makePages("PageOne.ChildOne", "PageTwo");
addLinkTo($page, "PageTwo", "SymPage");
submitRequest("root", "type:pages");
assertResponseIsXML();
assertResponseContains("<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>");
assertResponseDoesNotContain("SymPage");
}
public function testGetDataAsXml()
{
makePageWithContent("TestPageOne", "test page");
submitRequest("TestPageOne", "type:data");
assertResponseIsXML();
assertResponseContains("test page", "<Test");
}
이 패턴의 이점은 대부분의 성가신 세부 사항이 제거되었다는 것입니다. 테스트는 핵심을 정확히 파악하고 실제로 필요한 데이터 유형과 기능만 사용합니다. 이 테스트를 읽는 사람은 누구나 세부 사항에 현혹되거나 압도당하지 않고 테스트가 수행하는 작업을 매우 빠르게 이해할 수 있어야 합니다.
#4 단일 책임 및 오류 처리
이것을 설명하는 가장 좋은 방법은 책에서 직접 인용하는 것입니다.
Functions should do one thing. Error handing is one thing. Thus, a function that handles errors should do nothing else. This implies that if the keyword try exists in a function, it should be the very first word in the function and that there should be nothing after the catch/finally.
#5 더 나은 오류 처리
이 코드 조각이 어떻게 더 잘 형성될 수 있다고 생각하십니까?
$port = new ACMEPort(12);
try {
$port->open();
} catch (DeviceResponseException $e) {
reportPortError($e);
logger()->log("Device response exception", $e);
} catch (ATM1212UnlockedException $e) {
reportPortError($e);
logger()->log("Unlock exception", $e);
} catch (GMXError $e) {
reportPortError($e);
logger()->log("Device response exception");
} finally {
/// ...
}
호출하는 API를 래핑하고 일반적인 예외 유형을 반환하도록 하여 코드를 상당히 단순화할 수 있습니다.
$port = new LocalPort(12);
try {
$port->open();
} catch (PortDeviceFailure $e) {
reportError($e);
logger()->log($e->getMessage(), $e);
} finally {
// ...
}
class LocalPort {
private $innerPort;
public function __construct(int $portNumber) {
$this->innerPort = new ACMEPort($portNumber);
}
public function open() {
try {
$this->innerPort->open();
} catch (DeviceResponseException $e) {
throw new PortDeviceFailure($e);
} catch (ATM1212UnlockedException $e) {
throw new PortDeviceFailure($e);
} catch (GMXError $e) {
throw new PortDeviceFailure($e);
}
}
// ...
}
ACMEPort에 대해 정의한 것과 같은 래퍼는 매우 유용할 수 있습니다.
괜찮아. 이 부분에 대한 내용입니다. 곧 다음편도 계속 올리겠습니다. 내Telegram 채널에 가입하면 최신 게시물에 대한 알림을 받을 수 있습니다. 또한 및 에서 나를 팔로우할 수 있습니다.
Reference
이 문제에 관하여(단순해진 깨끗한 코드 - 1부), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/mehradsadeghi/clean-code-made-simple-part-1-2f32텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)