문서를 읽다보니 dart는 tree shaking을 지원한다는 문장이 있었는데, tree shaking의 뜻을 알지 못했다.

 

프로젝트에 있지만 사용되지 않은 (죽은)코드를 제거하는 것을 말한다.

전체 라이브러리를 가져와서 함수를 하나만 사용하는 경우, 컴파일 코드의 크기를 줄여준다.

 

죽은 코드를 제거하여, 코드 크기를 줄이고 성능을 향상시킨다.

개발을 위해 문서를 찾다보면 종종 만나는 용어.

단순 번역을 하면 상용구 코드라고 나온다.

 

구글링 결과

단순한 결과를 얻기위해 반복적으로 사용되는 코드라고 한다.

 

자바에서 getter, setter 메서드와 같이 단순한 결과를 얻기 위해, 변하지 않고 반복적으로 사용되는 코드를 말한다.

아래 코드에서 변수(name, owner) 선언빼고는 모두 보일러플레이트 코드라고 할 수 있다.

public class Pet {
    private PetName name;
    private Person owner;

    public Pet(PetName name, Person owner) {
        this.name = name;
        this.owner = owner;
    }

    public PetName getName() {
        return name;
    }

    public void setName(PetName name) {
        this.name = name;
    }

    public Person getOwner() {
        return owner;
    }

    public void setOwner(Person owner) {
        this.owner = owner;
    }
}

 

스택오버플로우에서 찾은 여러 방법 중 이게 제일 깔끔하게 작동했다..

 

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    View view = getCurrentFocus();
    if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) {
        int scrcoords[] = new int[2];
        view.getLocationOnScreen(scrcoords);
        float x = ev.getRawX() + view.getLeft() - scrcoords[0];
        float y = ev.getRawY() + view.getTop() - scrcoords[1];
        if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom())
        ((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this.getWindow().getDecorView().getApplicationWindowToken()), 0);
    }
    return super.dispatchTouchEvent(ev);
}

 

출처:https://stackoverflow.com/questions/8697499/hide-keyboard-when-user-taps-anywhere-else-on-the-screen-in-android/8697635

 

hide keyboard when user taps anywhere else on the screen in android

I need to hide the softkeypad in android when user click on anywhere other than a Edittext. There are many help for iphone but not for android. I tried this code but its not working :( final

stackoverflow.com

 

간단한 예제를 통해 6분만에 이해해보자.

 

콜백이란?

간단: 다른 함수의 실행이 완료된 후 실행되는 함수입니다. - call after라고 하는 사람도 있음.

 

좀 더 자세히: 자바스크립트에서 함수는 객체입니다. 그렇기에, 함수는 다른 함수의 인자가 될 수 있고 반환될 수 도 있습니다. 콜백 함수를 호출하는 함수를 고차함수라고 하며, 인자로 전달된 함수를 콜백함수라 합니다.

 

더 자세히 알아보기 위해 예제를 살펴보겠습니다.

 

왜 콜백이 필요할까요?

중요한 이유중 하나 - 자바스크립트는 이벤트 중심 언어입니다. 이벤트를 수신하는동안 계속 작동합니다.

기본 예제를 봅시다:

 

function first(){
  console.log(1);
}
function second(){
  console.log(2);
}
first();
second();

당신이 예상하듯이 first함수가 먼저 실행되고 second가 실행되어 다음과같이 콘솔에 출력됩니다.

1
2

 

지금까지 잘 작동했습니다.

 

그런데, 함수 first에 즉시 실행할 수 없는 코드가 포함되어있다면 어떨까요? 예를 들면, 요청을 보낸뒤 응답을 기다려야하는 API 호출처럼...

 

이러한 상황을 시뮬레이션하기 위해 일정시간이 지난 후 함수를 호출하는 Javascript의 setTimeout을 사용합니다. API 호출을 시뮬레이션하기 위해 500ms동안 함수를 지연시킵니다. 그 코드는 다음과 같습니다:

 

function first(){
  // Simulate a code delay
  setTimeout( function(){
    console.log(1);
  }, 500 );
}
function second(){
  console.log(2);
}
first();
second();

setTimeout이 어떻게 작동하는지는 지금 중요하지 않습니다. 중요한 것은 우리가 500ms지연시킨 console.log(1)의 결과를 확인하는 것이죠. 이제 함수를 호출하면 어떻게 될까요?

first();
second();

2
1

first를 먼저 호출했지만 second함수 이후에 결과가 출력되었습니다.

 

순서대로 함수가 호출되지 않고, Javascript는 first의 응답을 기다리지 않고 second를 실행합니다.

 

당신은 순서대로 호출하고 싶더라도 일반적인 방법으로는 할 수 없음을 확인했습니다.

콜백은 다른 코드의 작동이 끝난 뒤 실행되도록 할 수 있습니다.

 

 

콜백 만들기

콜백을 만들어 봅시다.

 

먼저 크롬 개발자 콘솔을 열고(윈도우: Ctrl + Shift + J, 맥: Cmd + Option + J) 콘솔에 다음과 같이 함수를 선언하세요.

function doHomework(subject) {
  alert(`Starting my ${subject} homework.`);
}

 

위의 doHomework 함수는 과목이라는 하나의 변수를 가집니다. 콘솔에 다음과 같이 입력하여 함수를 호출하세요.

 

doHomework('math');
// Alerts: Starting my math homework.

 

이제 콜백함수를 추가해봅시다. doHomework 함수의 매개변수로 콜백함수를 전달할 수 있습니다.

 

function doHomework(subject, callback) {
  alert(`Starting my ${subject} homework.`);
  callback();
}

doHomework('math', function() {
  alert('Finished my homework');
});

 

위의 코드를 콘솔에 입력하면 볼수 있듯이, 경고창이 2회 뜨게됩니다.: starting homework 경고와 finished homework

 

콜백 함수는 다음과 같이 따로 정의될 수 있습니다.

 

function doHomework(subject, callback) {
  alert(`Starting my ${subject} homework.`);
  callback();
}
function alertFinished(){
  alert('Finished my homework');
}
doHomework('math', alertFinished);

 

 

콜백함수는 어떤 작업이 끝나고 나서 작동하길 원하는 작업이 있는 경우 사용합니다.

 

 

출처:

https://codeburst.io/javascript-what-the-heck-is-a-callback-aba4da2deced

 

JavaScript: What the heck is a Callback?

Learn and understand the basics of callbacks in just 6 minutes with easy examples.

codeburst.io

 

'개발 > 개념' 카테고리의 다른 글

SOLID 원칙을 위한 완전한(Solid) 가이드  (0) 2020.03.24

Introduction

이 튜토리얼에서는 객체지향의 SOLID원칙에 대해서 얘기합니다.

먼저, SOLID원칙이 생긴 어떻게 생겨났는지와 소프트웨어 설계 시 고려해야할 것을 알아봅니다.

그리고, 핵심을 파악하기 위해 각 원리의 예제를 통해 설명합니다.

 

 

SOLID 원칙의 이유

SOLID원칙은 Robert C. Martin의 2000년도 논문(Design Principles ans Design Patterns)에서 소개되었습니다.

이후 이 개념은 Michael Feathers에 의해 SOLID로 알려졌습니다.

지난 20년 동안, 이 5가지 원칙은 객체지향 프로그래밍에 혁명을 일으켜 소프트웨어 작성방식을 변화시켰습니다.

 

그럼, SOLID는 무엇이고 어떻게 더 좋은 코드를 작성하도록 도울까요?

Martin과 Feathers의 디자인 원칙은 유지보수와 이해하는 것이 쉽고 유연한 소프트웨어를 만들도록 합니다.

결과적으로, 이 원칙은 애플리케이션의 크기가 커질 때, 앱의 복잡성을 줄이고 문제생길 수 있는 부분을 제거합니다.

 

SOLID원칙은 다음과 같습니다:

  1. Single Responsibility
  2. Open/Closed
  3. Liskov Substitution
  4. Interface Segregation
  5. Dependency Inversion

이 단어 중 일부는 무슨 소리인지 알기 어렵지만, 간단한 코드 예제로 쉽게 이해할 수 있습니다.

다음 섹션에서 각 원칙의 의미를 자바 예제와 함께 설명합니다.

 

1. Single Responsibility (단일 책임의 원칙)

단일 책임의 원칙부터 살펴봅시다.

우리가 예상하듯이, 이 원칙은 "클래스는 하나의 책임만을 가져야한다."입니다.

또한 변경해야할 이유는 한가지여야한다고 말합니다.

 

이 원칙은 더 좋은 소프트웨어를 만드는데 어떻게 도움이 될까요?

이 원칙의 이점을 살펴봅시다:

  1. 테스팅 - 하나의 책임만 갖는 클래스는 테스트 케이스가 훨씬 적습니다.
  2. 낮은 결합(coupling) - 단일 클래스의 기능이 적을수록 종속성이 줄어듭니다.
  3. 조직, 구성(Organization) - 소규모의 잘 구성된 클래스는 모놀리식(monolithic) 클래스보다 보기 쉽습니다.

 

예로 간단한 책을 나타내는 클래스를 봅시다.

public class Book {
 
    private String name;
    private String author;
    private String text;
 
    //constructor, getters and setters
}

이 코드에서, 우리는 책 인스턴스와 관련된 이름, 저자, 텍스트를 저장합니다.

이제 텍스트를 쿼리하는 몇가지 메서드를 추가해 봅시다.

public class Book {
 
    private String name;
    private String author;
    private String text;
 
    //constructor, getters and setters
 
    // methods that directly relate to the book properties
    public String replaceWordInText(String word){
        return text.replaceAll(word, text);
    }
 
    public boolean isWordInText(String word){
        return text.contains(word);
    }
}

이제 우리의 책 클래스는 잘 작동합니다. 그리고 우리는 우리의 앱에 우리가 좋아하는 만큼 많은 책을 저장할 수 있습니다. 그러나 텍스트를 콘솔에 출력하고 읽을 수 없다면, 정보를 저장해서 무얼 할까요

출력 메서드를 추가해보겠습니다.

public class Book {
    //...
 
    void printTextToConsole(){
        // our code for formatting and printing the text
    }
}

근데, 이 코드는 앞에서 설명한 단일 책임 원칙을 위반합니다.

이를 바로잡기 위해서, 우리는 텍스트 출력에만 관련이 있는 별도의 클래스를 구현해야합니다.

public class BookPrinter {
 
    // methods for outputting text
    void printTextToConsole(String text){
        //our code for formatting and printing the text
    }
 
    void printTextToAnotherMedium(String text){
        // code for writing to any other location..
    }
}

어썸! 우리는 우리는 책 클래스의 출력 책임을 줄여주는 클래스를 개발한 것 뿐만아니라, 우리는 또한 BookPrinter 클래스를 사용해서 다른 미디어에 텍스트를 보낼 수 있습니다.

이메일이든 log를 남기는 것이든 상관없이, 우리는 출력을 담당하는 별도의 클래스를 갖게 되었습니다.

 

2. Open for Extension, Closed for Modification (개방폐쇄원칙)

개방 폐쇄 원칙으로 알려진 원칙을 살펴봅시다. 

간단히 말해서, 클래스는 확장을 위해서 열려야하지만, 수정을 위해서는 닫혀야합니다.

이렇게 함으로써, 우리는 기존의 코드를 수정하거나 앱에 잠재적인 버그를 만드는 것을 막습니다.

 

물론, 기존 코드의 버그를 수정하는 경우는 예외입니다.

 

간단한 예제 코드를 통해 개념을 자세히 살펴보겠습니다. 새로운 프로젝트로 기타 클래스를 구현했다고 가정해봅시다.

이것은 볼륨 노브를 갖출정도로 완전합니다.

public class Guitar {
 
    private String make;
    private String model;
    private int volume;
 
    //Constructors, getters & setters
}

우리는 이 앱을 런칭했고 모두들 이것을 좋아합니다. 그러나, 몇달뒤 우리는 기타(Guitar)가 밋밋하다고 생각했고, 불꽃문양을 넣어 좀더 락 앤 롤스럽게 만들 수 있다고 생각했습니다.

 

이 시점에 기타(Guitar)클래스를 열어 불꽃 문양을 추가하고 싶을 수 있습니다. 하지만 (이미 런칭한) 앱에 어떤 에러가 발생할지 모릅니다.

 

기타 클래스에 추가하는 대신, 개방 폐쇄 원칙을 고수하고 간단하게 Guitar클래스를 확장하세요.(extend, 상속)

public class SuperCoolGuitarWithFlames extends Guitar {
 
    private String flameColor;
 
    //constructor, getters + setters
}

기타 클래스를 확장해서, 우리는 기존의 앱이 영향받지 않도록 할 수 있습니다.

 

 

3. Liskov Substitution (리스코프 치환)

다음은 리스코프 치환입니다. 이것은 5가지 원칙 중 가장 복잡합니다.

간단히 말해서, 클래스 A가 클래스 B의 하위 유형(subtype)이라면, 프로그램이 동작하는데 문제 없이 B를 A로 교체할 수 있어야 합니다.

 

이 개념을 이해하는데 도움이 되도록 예제코드를 보겠습니다.

public interface Car {
 
    void turnOnEngine();
    void accelerate();
}

위에, 우리는 간단한 차 인터페이스를 정의했습니다. 이 인터페이스의 몇가지 메서드는 모든 자동차가 충족시켜야할 것들입니다. - 엔진 시동을 걸기, 가속하기.

 

인터페이스를 구현하고 메서드에 관련된 코드를 작성해봅시다.

public class MotorCar implements Car {
 
    private Engine engine;
 
    //Constructors, getters + setters
 
    public void turnOnEngine() {
        //turn on the engine!
        engine.on();
    }
 
    public void accelerate() {
        //move forward!
        engine.powerOn(1000);
    }
}

코드가 나타내는 것 처럼, 우리는 시동을 걸 수 있는 엔진을 가지고 있고, 파워를 증가시킬 수 있습니다.

잠시만... 2019년 엘론 머스크는 바빴습니다.

 

우리는 이제 전기차의 시대에 살고있습니다.

public class ElectricCar implements Car {
 
    public void turnOnEngine() {
        throw new AssertionError("I don't have an engine!");
    }
 
    public void accelerate() {
        //this acceleration is crazy!
    }
}

엔진없는 차를 포함하면서, 우리는 본질적인 프로그램의 메서드를 바꾸고 있습니다.

(메서드의 원래 의도대로 작동하지 않음)

이는 리스코프 치환에 대한 명백한 위반입니다. 그리고 이전 2개의 원칙보다 바로잡기 어렵습니다.

 

바로잡기 위한 한가지 가능한 방법은 엔진 없는 자동차의 상태를 고려한 인터페이스로 새로 작업하는 것 입니다.

 

 

4. Interface Segregation (인터페이스 분리 원칙)

이번에는 인터페이스 분리 원칙입니다. 이 원칙은 간단히 설명하자면 "큰 인터페이스는 작은 인터페이스들로 나뉘어야 한다"입니다. 이렇게 해서, 우리는 클래스를 구현할 때  관심있는 메서드만 신경쓸 수 있습니다.

 

이번 예제에서, 우리는 동물원 사육사로서 우리의 손을 시험해보도록 하겠습니다. 구체적으로, 우리는 곰 우리에서 일할 것 입니다.

 

곰 사육사의 역할을 간단하게 나타내는 인터페이스로부터 시작하겠습니다:

public interface BearKeeper {
    void washTheBear();
    void feedTheBear();
    void petTheBear();
}

 

열렬한 사육사이기 때문에, 우리는 사랑하는 곰들을 씻기고 먹이는 것을 더 기쁘게 생각합니다. 그러나 우리는 곰을 쓰다듬는 것의 위험함을 너무 잘 알고 있습니다. 하지만 불행하게도, 우리의 인터페이스는 꽤 비대해서, 우리는 곰을 쓰다듬는 코드를 구현하는 선택밖에 할 수 없습니다.

 

우리의 비대한 인터페이스를 3개의 개별 인터페이스로 나누어 이 문제를 해결해 보겠습니다:

public interface BearCleaner {
    void washTheBear();
}
 
public interface BearFeeder {
    void feedTheBear();
}
 
public interface BearPetter {
    void petTheBear();
}

 

이제 인터페이스 분리 원칙으로, 우리는 우리에게 중요한 메서드만 구현할 수 있습니다.

 

public class BearCarer implements BearCleaner, BearFeeder {
 
    public void washTheBear() {
        //I think we missed a spot...
    }
 
    public void feedTheBear() {
        //Tuna Tuesdays...
    }
}

 

그리고 마침내, 우리는 그 위험한 것(곰 쓰다듬기)을 미친사람에게 둘 수 있습니다.

 

public class CrazyPerson implements BearPetter {
 
    public void petTheBear() {
        //Good luck with that!
    }
}

더 나아가서, 우리는 이전 예제인 BookPrint 클래스를 인터페이스 분리원칙으로 분리할 수 있습니다.

Printer 인터페이스를 단일 print 메서드로 구현함으로서, 우리는 ConsoleBookPrinter와 OtherMediaBookPrinter 클래스를 각각 인스턴스화 할 수 있습니다.

 

 

5. Dependency Inversion (의존성 역전 원칙)

의존성 역전의 원칙은 소프트웨어 모듈의 디커플링을 말합니다. 이 방법은, 상위 수준의 모듈이 하위 수준 모듈에 의존하는 대신, 모두 추상화에 의존합니다.

 

이를 보여주기 위해서, 구시대로 돌아가서 코드로 윈도우98을 만들어 봅시다.

public class Windows98Machine {}

 

근데, 모니터와 키보드가 없으면 소용이 없죠. 각 생성자에 하나씩 추가해서, 우리가 인스턴스화하는 모든 윈도우98 컴퓨터에 모니터와 표준키보드가 포함되도록 합시다.

 

public class Windows98Machine {
 
    private final StandardKeyboard keyboard;
    private final Monitor monitor;
 
    public Windows98Machine() {
        monitor = new Monitor();
        keyboard = new StandardKeyboard();
    }
 
}

 

이 코드는 작동하고, 우리는 윈도우98 컴퓨터 클래스에서 표준 키보드와 모니터를 자유롭게 사용할 수 있을 겁니다.

문제가 해결되었나요? 그렇지 않죠.. 

새로운 키워드로 표준 키보드와 모니터를 선언함으로써, 3가지 클래스를 밀접하게 묶었습니다.

 

이로 인해 윈도우98컴퓨터를 더욱 테스트하기 어렵게 만들었을 뿐만 아니라, 우리는 표준 키보드를 다른 키보드로 바꿔야하는 상황이 오더라도 바꿀 수 없게 되었습니다. 그리고 모니터도 그렇습니다.

 

우리의 머신을 표준 키보드로부터 분리(decouple)시켜봅시다. 더 일반적인 키보드 인터페이스를 추가하고 이것을 우리 클래스 안에서 사용합시다.

 

public interface Keyboard { }
public class Windows98Machine{
 
    private final Keyboard keyboard;
    private final Monitor monitor;
 
    public Windows98Machine(Keyboard keyboard, Monitor monitor) {
        this.keyboard = keyboard;
        this.monitor = monitor;
    }
}

여기서 우리는 의존성 주입 패턴을 사용해서 윈도우98머신 클래스에 키보드 종속성을 쉽게 추가할 수 있습니다.

 

윈도우98머신 클래스에 적합하도록, 표준키보드클래스를 키보드 인터페이스를 구현하여 수정해봅시다:

public class StandardKeyboard implements Keyboard { }

이제 우리 클래스는 분리(decouple)되었습니다. 그리고 키보드 추상을 통해서 소통합니다. 만약 우리가 원한다면, 우리는 쉽게 인터페이스를 구현하여 다른 키보드로 바꿀 수 있습니다. 모니터 클래스에 대해서도 같은 원칙을 적용할 수 있습니다.

 

엑설런트! 우리는 의존성을 분리(decouple)했으며 우리가 어떤 테스트 프레임워크를 사용하든 윈도우98머신을 자유롭게 테스트할 수 있습니다.

 

 

결론

우리는 이 튜토리얼에서 객체지향 설계의 SOLID원칙에 대해 자세히 살펴보았습니다.

우리는 간략히 SOLID의 역사와 이 원칙의 존재 이유로 설명을 시작했습니다.

SOLID의 문자별로, 원칙을 위반하는 예제 코드로 의미를 설명했고 SOLID원칙에 맞도록 바로잡는 방법을 살펴보았습니다.

 

이 코드는 깃허브에서 볼 수 있습니다.

 

 

 

출처:

https://www.baeldung.com/solid-principles

 

A Solid Guide to SOLID Principles | Baeldung

A quick and practical introduction to SOLID with examples.

www.baeldung.com

 

'개발 > 개념' 카테고리의 다른 글

[자바스크립트/javascript] 콜백은 무엇인가?  (0) 2020.03.24

CI(Continuous Integration)란?

개발자를 위한 자동화 프로세스를 말한다.

코드의 변경사항이 정기적으로 빌드, 테스트되어 리포지토리에 올라간다.

 

여럿이서 개발하는 프로젝트의 경우, 각자 다른 기능을 동시에 개발한다.

이경우 문제는 통합할 때 일어난다.

한 개발자가 변경한 기능이 다른 기능에 영향을 줄 수 있다.

 

CI를 통해 개발자는 위 작업을 더 쉽게 자주 수행할 수 있다.

개발자의 변경사항이 통합(Merge)되면 자동으로 빌드 되고, 단위테스트와 통합테스트를 통해 변경사항에 문제가 없는지 확인한다.

테스트하면서 충돌이 발생하면 버그를 더욱 빠르게 수정할 가능성이 높아진다. 작은 변경사항을 정기적으로 테스트하기 때문에 완성도 높은 결과물을 만들게 된다.

 

CD(Continuous Delivery/Deployment)란?

Continuous Delivery는 변경사항이 테스트를 거쳐 리포지토리에 자동으로 업로드 되는 것을 말한다.

운영팀은 이 리포지토리로 애플리케이션을 배포할 수 있다.

이는 개발팀과 비즈니스팀간의 커뮤니케이션 문제를 해결해준다.

테스트 자동화와 코드 릴리즈 자동화가 추가된다.

 

Continuous Deployment는 리포지토리의 변경사항을 고객이 사용할 수 있는 상태로 자동 릴리즈하는 것을 말한다.

이는 고객에게 애플리케이션을 빠르게 제공할 수 있게 한다.

CI/CD 파이프라인의 마지막 단계이다.

변경사항을 한번에 릴리스하지 않고 작은 조각으로 세분화하여 릴리즈하기에 애플리케이션 배포의 위험성을 줄여준다.

 

 

https://coding-start.tistory.com/246?category=808950

 

디자인패턴 - 옵저버패턴(Observer Pattern)

어떤 클래스에 변화가 일어났을 때, 이를 감지하여 다른 클래스에 통보해주는 것이 observer 패턴이다. 그림을 보면 이 패턴은 외부 객체의 상태 변화에 따라(subject 클래스) observer 객체(observer 인터페이스..

coding-start.tistory.com

 

'참고 링크 > 개발' 카테고리의 다른 글

[데이터베이스] DB모델링용 사이트  (0) 2020.04.24
유니티 로컬 파일 저장  (0) 2020.03.20
플러터 개발  (0) 2020.03.18
[안드로이드] OpenGL 참고용  (0) 2020.03.13
이펙티브 자바  (0) 2020.03.09

https://wergia.tistory.com/92

 

[Unity3D] 안드로이드 버전의 빌드에서 디바이스의 로컬 저장소에 파일을 저장하는 법

안드로이드 버전의 빌드에서 디바이스의 로컬 저장소에 파일을 저장하는 법 유니티에서 게임을 만들 때, 네트워크로 받아온 파일을 로컬에 저장해야 하는 일이 많다. 특히 게임의 패치 시스템(Patch System)을 만..

wergia.tistory.com

 

'참고 링크 > 개발' 카테고리의 다른 글

[데이터베이스] DB모델링용 사이트  (0) 2020.04.24
디자인패턴  (0) 2020.03.22
플러터 개발  (0) 2020.03.18
[안드로이드] OpenGL 참고용  (0) 2020.03.13
이펙티브 자바  (0) 2020.03.09

+ Recent posts