아직 만들어지지 않은 음식을 먹어보는 건 현실세계에서 불가능한 일이다. 어떤 재료가 들어갔을지도 모르고, 한식인지 중식인지 혹은 일식인지도 모르는 음식을 예상하면서 맛을 추측할 수도 없는 노릇이다.
하지만 프로그래밍 세계에서 볼 때는 이야기가 완전히 달라진다. 아직 만들어지지 않은 것을 만들어졌다고 가정하고 프로그래밍하는 것이 가능하다는 이야기다. 흔히 추상적인 프로그래밍이라고 하는데, 아직 만들어지지 않은 기능을 있다고 가정하고 프로그래밍하는 것을 말한다.
추상적인 프로그래밍이 가능한 이유는 일반적으로 컴퓨터 프로그래밍의 형태가 입력과 출력(결과)가 지정되었기 때문이다. 내부적인 연산은 어떻게 되었던지 결과가 정해졌기 때문에 그것에 기인한 추상적인 프로그래밍이 가능하다.
쉬운 예로 학생이라는 추상클래스(인터페이스)를 선언해 보았다.
입력도 없고, 출력(void)도 없는 쉬운 클래스이다.
interface Student{
void study();
}
나는 이제 이 학생 클래스를 이용해서 study() 라고 호출만 하면 학생을 공부시킬 수 있다.
학생이 어떻게 공부하는지는 관심없다. 다만 study()라고 호출만 하면 각자 알아서 공부를 해야 한다는 것만 안다. 어떤 책을 보고 있고, 어떤 과목을 공부하는지는 전적으로 학생의 몫이라는 것이다. 따라서 공부하는 방법과 과정은 추상적이라는 것이다.
새로운 2명의 학생이 있고, 나는 그 두 명의 학생에게 공부하라고 명령할 것이다.
class StudentA implements Student{
public String textbook = "수학";
public void study(){
System.out.println(textbook + "을 공부합니다.");
}
}
class StudentB implements Student{
public String textbook = "원피스 만화책";
public void study(){
System.out.println(textbook + "을 공부합니다.");
}
}
Student student = new StudentA();
student.study();> 결과 : 수학을 공부합니다.
Student student = new StudentB();
student.study();
> 결과 : 원피스 만화책을 공부합니다.
Student라는 추상클래스(인터페이스)는 학생이 무엇을 공부하는지 모르지만, 공부해야 한다는 것만 알고 있고, 그것으로 여러 학생을 공부시킬 수 있었다. 수학책을 공부하던지, 몰래 원피스 만화책을 공부하는지는 학생 개개인의 몫이라는 것이다. (공부하는 방법은 추상적이라는 이야기다)
흔히 이런 것들을 '다형성'이라고 하기도 한다. 하나의 추상적인 틀(Student)을 이용하여 무수한 형태의 구현체(StudentA, StudentB, ..)를 만들 수 있는 것이다.
그리고 다른 관점에서 생각해 보면 수 많은 구현체(StudentA, StudentB, ..)는 모두 추상적인 틀(Student)로 제어가 가능하다.
사실 추상적인 것으로 구현체를 제어할 수 있다는 것은 입이 딱 벌어질 만큼 대단한 것이다.
Servlet API를 가지고 프로그래밍 한 웹서비스가 Servlet API를 구현한 각종 웹컨테이너에서 무리없이 돌아가는 것은 바로 그 실례이다.
Servlet API는 추상적이다. HTTP 프로토콜을 어떻게 다룰지에 대한 정의만 있고 그에 따른 결과만 있다.
자바 웹 개발자는 이러한 Servlet API를 가지고 웹 서비스를 개발한다. 그리고는 Servlet API를 구현한 컨테이너에 웹서비스를 올려놓고 시동을 건다.
만약 Servlet API가 추상적이지 않았다면, 다양한 컨테이너들이 존재하지 않았을 것이다. (마치 Student라는 클래스가 없으면 StudentA, StudentB가 없는것 처럼) 그리고 다양한 컨테이너를 선택할 수 있는 기회도 없을 것이다.
프로그래밍을 할 때 나는 3가지로 나누어서 생각을 한다.
1. 서비스 API
2. 서비스 API 구현체
3. 서비스 API를 이용한 어플리케이션
2번과 3번은 1번을 참고해서 개발해야 하기 때문에 1번에 의존적이지만, 2번과 3번은 서로 모르는 비의존적인 관계가 된다. (Servlet API로 바꿔말하면, Servlet API를 기반으로 만든 Tomcat 컨테이너와 내가 만든 웹서비스는 의존하지 않는 것처럼) 그 이야기는 1번만 확실하게 만들어져 있다면, 2번과 3번은 개별 진행이 가능하다는 것이다.
이것은 참 중요한데, 1번과 2번, 3번을 차례차례 진행하는 것이 아니라, 1번을 진행하고 2번과 3번은 동시에 진행할 수 있다. 대신 1번을 만들 때, 신중하게 고려해서 만들어야, 2번과 3번이 좋은 퀄리티로 나올 수 있게 된다.
나는 추상적인 프로그래밍을 좋아한다. 아직 만들어지지 않은 것들을 있다고 가정하면서 큰 틀에서 프로그래밍 하는 것을 좋아한다. 그러다 보니 Inteface를 먼저 선언해 놓고 프로그래밍을 하거나, 아니면 기존에 있는 프로그램들 중에서 공통되는 것만 모아서 Inteface를 추출해서 사용한다. 그리고 추출한 Inteface를 가지고 Strategy pattern을 접목하여 런타임에 클래스를 살짝 바꿔놓는 방법을 애용한다. 그리고 가끔은 javascript나 groovy를 이용해서 duck type을 이용한 프로그래밍을 하기도 한다.