많은 회사와 개발자들이 자바로부터 새로운 언어인 Ruby, Python, Groovy, Erlang, Scala 등으로 이동했다.
여전히 자바를 사용하고 있을지 모르겠지만, 자바를 사용하더라도 프로그래밍 스타일을 바꿀 수 있고, 새로운 언어로부터 여러 이점을 취할 수 있다.
최근 15년 동안 자바의 프로그래밍 스타일은 매우 많이 변했다.
팀에 수많은 자바 프로그래머들이 final을 사용하기 시작했다.
변수를 Final로 만드는 것은 변수가 변경되는 것을 방지해 준다.
변수의 값을 재할당 하려고 하며 버그가 발생할 확률이 많아지기 때문에 새 값을 위해서 새로운 변수를 사용하는게 좋다.
final Foo bar = new Foo();
다음 링크에서 조금 더 자세한 내용을 다뤘다. All variables in Java must be final
많은 자바 개발자들은 무의식중에 - 가끔씩 IDE 라는 악마의 도움을 얻어서 - 클래스의 모든 fields에 대한 setter를 생성한다.
setter에 대해서 생각해 보자.
정말로 그 setter들이 그 field에 대해서 필요한가? 값의 변경이 필요하다면 새 객체를 만드는 것이 낫다.
getters 없이도 코드를 작성해 보자. Tell, don’t ask
함수형 언어로부터 배우자 반복(looping)이 collections를 다루는데 가장 효율적인 방법이 아니다.
persons의 list로부터 맥주를 마시는 사람(who can drink beer)을 걸러(filter)낸다면 반복(loop) 버전은 아래와 같을 것이다.
List<Person> beerDrinkers = new ArrayList<Person>();
for (Person p: persons) {
if (p.getAge() > 16) {
beerDrinkers.add(p);
}
}
위 구문을 보다 함수형 스타일로 고칠 수 있다.
Predicate<HasAge> canDrinkBeer = new Predicate<HasAge>() {
public boolean apply(HasAge hasAge) {
return hasAge.getAge() > 16;
}
}
List<Person> beerDrinkers = filter(persons, canDrinkBeer);
Predicate canDrinkBeer = new Predicate() {
public boolean apply(HasAge hasAge) {
return hasAge.isOlderThan( 16 );
}
}
조금 더 깔끔하게 고쳐보자.
Predicate canDrinkBeer = new Predicate() {
public boolean apply( HasAge hasAge, HasAge otherAge ) {
return hasAge.isOlderThan( otherAge );
}
}
아래 버전(predicate version)에 코드가 약간 더 길지만, 역활이 명확하게 구분되어 있다.
반복(loop) 버전은 새로운 요구사항을 추가햐면 빠르게 가독성이 떨어진다.
그러나 함수형 버전은 쉽게 요구사항을 추가할 수 있다.
List beerDrinkers = filter(filter(persons, canDrinkBeer), isMale);
다음 링크에서 더 자세한 내용을 다룬다. Metaphysical Developer
짧은 코드를 작성해라. 자바는 기본적으로 시끄러운 언어다. 그러나 필요 이상으로 잡음을 만들지 말아야 한다.
다음과 같이 적는 대신
public int add( int a, int b ) {
int result = a + b;
return result;
}
다음과 같이 적어라
public int add(int a, int b) { return a + b; }
IDEA와 Eclipse등 IDE는 한줄 포멧을 유지하는 것을 허용한다.
Domain driven design 현재 많은 사람들의 관심사다. makes a big splash.
class는 많은 role로 나눠지고 많은 interfaces가 구현된다. 그리고 class는 재사용 된다.
public class Person implements Nameable, Hireable, LivesAt {
...
}
public interface Nameable {
String getName();
}
Method는 어떤 종류로서가 아니라, 오직 한가지 역할로만 쓰여져야 한다.
이런 종류의 methods들은 보다 많은 objects들과 동작할수 있고, 또다른 이점으로 결합도를 낮춰줄 것이다.
public void print( Nameable name ) {
System.out.println( name.getName() );
}
다음 링크에서 더 자세한 내용을 다룬다. Never, never, never use String in Java
lock이나 synchronized와 같은 자바의 동시성에 대한 원시값은 너무 저수준 이며 쓰기가 어렵다는 것이 증명됬다.
자바에는 보다 나은 방법의 동시성 코드를 쓰는 다양한 방법이 있다.
Erlang Style 동시성이 그것들 중에 하나다. 링크 에서 자세한 내용을 다룬다.
또 Akka 나Actorom과 같이 새로운 것들도 있다.
또한 Join/Fork 혹은 java.util.concurrent의 수많은 자료구조를 사용할 수도 있다.
유연한 interfaces는 코드를 보다 짧고 읽기 쉽게 만든다. 아주 좋은 예로 Google Collections의 MapMaker API가 있다.
ConcurrentMap graphs = new MapMaker()
.concurrencyLevel(32)
.softKeys()
.weakValues()
.expiration(30, TimeUnit.MINUTES)
.makeComputingMap(
new Function() {
public Graph apply(Key key) {
return createExpensiveGraph(key);
}
});
간단한 data holders나 혹은 data transfer objets를 가지고 있다면 getters와 setters 같은 지저분한 코드를 절대로 적지 마라.
나는 이것이 자바에서 이단 이란것을 알고 있다. 그래도 public field를 사용해라.
다음 같이 쓰는 대신에
public class Point {
private int x;
private int y;
pulic Point(int x, int y) {
this.x = x;
this.y = y;
}
public int setX(int newX) {
x = newX;
}
public int getX() {
return x;
}
...
}
...
int x = p.getX();
int y= p.getY();
다음과 같이 적어라
public class Point {
public final int x;
public final int y;
pulic Point(int x, int y) {
this.x = x;
this.y = y;
}
}
...
int x = p.x;
int y = p.y;
이 팁으로 자바 코드가 더 좋아질 것이다. 위 내용을 사용중인 Java class에 적용해 보자.
어떤가?
당신의 자바 코딩 스타일이 지난 10년간 어떻게 변해 왔는지를 듣고 싶다.
August 10, 2009 by Stephan Schmidt