SlideShare a Scribd company logo
1 of 81
Download to read offline
오픈에스엔에스
AA팀
조영석
 소프트웨어 품질
 소프트웨어 구현
 SonarQube 기능 및 특징
 SonarQube 사용방법
 소스 품질을 위한 코딩
 Q&A
 기능적 요구사항(Functional Requirements)
- 수행될 기능과 관련되어 입력과 출력 및 그들 사이의 처리과정
- 목표로 하는 제품의 구현을 위해 소프트웨어가 가져야 하는 기능
적 속성
 비기능적 요구사항(Non-Functional Requirements)
◦ 제품의 품질 기준 등을 만족시키기 위해 소프트웨어가 가져야 하
는 성능, 사용의 용의성, 안전성과 같은 행위적 특성
◦ 시스템의 기능에 관련되지 않는 사항을 나타냄
기능 비기능
효율적인 SW 개발 관리
가치있는 SW
계 획
명확한 목표수립
수 행
효율적인 개발활동
검 증
지속적인 모니터링 및 통재
“계획 기반의
지속적 검증”
“시각적 검증을
위한 시스템 활용”
Subversion
Eclipse
Jenkins
Ant,Script
NSIQConllector
PMD,CPPCheck
Emma,gcov
Junit,CPPUnit
Impasse
Redmine
SonarQube
요구사항 테스트 구현 형상관리
1. 소스코드를 바이너리 파일로 컴파일 한다.
2. 바이너리 파일을 배포 형태로 패키징 한다.
3. 단위테스트(커버리지 포함) 수행한다.
4. 정적분석을 수행한다.
5. 분석 결과를 리포팅한다.
6. 패키징한 파일을 테스트 서버에 배포한다.
 SW 구현은 SW 공학의 가장 기본적인 활동으로 코드작성, 디버깅, SW통합, 개발
자 테스팅 활동들로 이루어진다.
 SW 구현할 때 고려해야 할 4가지 주요원칙
- 코딩의 복잡성을 최소화
- 향후에 일어날 변화를 고려
- 소프트웨어 구현은 검증이 가능해야 한다는 것
- 표준을 활용하는 것
 코딩 규칙이나 표준을 수립하여 모든 개발자가 프로젝트에서 조화롭게 작업할
수 있도록 해야 한다. 이렇게 해서 좋아진 소스 코드의 가독성은 개발자가 SW 시
스템을 이해하는데 영향을 미치게 되고, 가독성이 향상되면 이해가 용이해지고
유지보수가 수월해지며 일반적으로 코드의 품질도 좋아진다.
 품질 관리 도구의 주요기능
 잠재적 오류 소스 코드 검출
 개발 표준 준수
 쉬운 룰 생성 및 편집
 자동 룰 업데이트
 정적 분석 도구를 통해 검색 되는 내용
 공유된 코딩 스타일 위반
 잠재적 버그의 코딩
 설계상의 문제가 되는 코드
 중복되고 보안에 위반되는 코드
 등등……
 정적 분석 도구로 소스코드에 대한 전반적인 품질
을 확보할 수 있도록 정보를 제공하는 통합 플랫폼
 Server / Client 구조
 C/C++/Java 등 15개 이상의 다양한 프로그램 언
어 지원
 플러그인 설치로 다양한 도구와 유연한 통합
 웹 기반 애플리케이션으로 다양한 결과를 서버에
서 통합 관리 용이
 프로젝트 소스 품질을 관리할 수 있도록 여러가지 모니
터링 툴을 제공하는 오픈소스 플랫폼
 보통 SonarQube는 단독으로 사용되기 보다는 Jenkins
같은 CI 서버와 연동이 되어서 사용이 되어지고 있으며
Java를 포함한 20가지가 넘는 프로그램밍 언어로 제작된
프로젝트의 모니터링을 제공
 Java 기반의 정적분석 툴로써, 다양한 항목에 대해 분석
및 결과를 볼 수 있는 품질관리 대시보드 툴
- 소스코드관리 하는 오픈소스기반의 무료툴
- 자바검증도구(PMD, findbugs, Checkstyle)가 PlugIn
형태로 들어가 있음
- 중복코드(Squid, CPD) 체크
- 코드 커버리지(Cobertura, jaCoCo)
 JDK 환경에서 동작, 웹서버 및 DBMS 필요
 다양한 OS를 지원 : Windows, Linux, Mac OS X, Unix
 DBMS 필요
=> Derby(기본 제공), MSSQL, MySQL, Oracle
 웹서버(WAS : Web Application Server) 필요
=> Jetty6, Apache Tomcat
 자바 기반 프로그램 : JDK 1.5 이상 필요
- Sonar 자체는 분석결과를 보여주는 툴. 실제분석은 Sonar 내의
Plug-in을 통하여 분석
- 기본적으로 제공되는 분석 툴
1) PMD : 소스코드의 표준준수 분석
2) FindBugs : 자바바이트코드를 분석하여 정적분석
3) CheckStyle : 코드 스타일체크
4) Cobertura : 테스트 커버리지체크
5) Surefire : 유닛테스트
- Sonar에서 분석결과를 보기 위해 분석을 위한 Client의 종류
1) Sonar runner : 권장되는 기본 클라이언트
2) Maven : Maven 기반으로 작성된 프로젝트에 적합
3) Ant Task : Ant 작성된 프로젝트에 적합
- Sonar는 Checkstyle, PMD, FindBugs, Coberbura 등의
분석툴 들을 이용하여 소스의 정적분석을 실시하고, 이
를 웹브라우저를 통하여 전체적인 분석결과를 보여주는
툴
SonarQube
Analysers Eclipse
Database
Server
- Sonar가 제공하는 분석결과는 다음과 같음
- 코드 중복 체크
- 코드의 표준
- 코드 coverage
- 코드 복잡도
- 주석
- 디자인 과 아키텍쳐
- 기본적으로는 Java 언어를 분석할 수 있지만, 추가 플러
그인을 통하여 다른 대부분의 언어에 대해서도 검사 가
능
 JAVA, C/C++등의 다수 프로그램 언어 지원
 플러그인 설치로 다양한 도구와 유연한 통합
 여러가지 분석 툴을 통합하여 여러 항목들을 한번에 검
사 가능(Checkstyle, PMD, FindBugs, CPPCheck,
Cobertura 등)
 웹기반 애플리케이션으로 다양한 분석 결과들을 확인 가
능
(버그&잠재버그체크, 코딩 표준 위반 체크,
중복 코드 체크, 단위 테스트 커버리지 체크,
소스 복잡도 체크, 주석 처리량 체크)
 분석을 위한 여러 클라이언트를 제공
(Sonar runner, Maven, Ant T ask)
 정적 코드 분석 도구 선정부터 적용까지 모든 프로
세스에 개발자 참여
 코드에 알맞은 도구 선택
 새롭게 작성하는 코드에 집중하기. 이미 작성된 코
드에 너무 신경쓰지 말 것
 결함 찾는데 혈안 되지 말고 개발 생산성에 집중
 정적코드 분석 및 결과에 대한 이슈 관리를 자동화
 https://nemo.sonarqube.org/
 코딩 규칙(Rules)
◦ Lanauage : Java
◦ Tag : Security, performance
"@Deprecated" code should not be used
이 Annotation은 가급적 사용을 자제해달라는 의미로 사용된다. 예를들어 어떤
method 앞에 @Deprecated가 붙으면, 이 메소드를 사용하거나 오버라이드 할 경우,
컴파일 할 때 경고가 뜬다.
더 나은, 개선된 메소드가 있음을 나타내고자 할 때에 주로 사용한다. 개발자가 어떤 메
소드를 썼는데, 이 메소드가 deprecated annotation 처리 되어있다면, 이 메소드는 다
음 버젼에서 사라지거나 더 개선된 메소드로 대체될 것이기 때문에, 이용을 자제해야한
다. (요약 하자면, 더 나은 기능을 제공하고 있으니, 차선책을 찾아보라는 의미로 쓰인
다)
/**
* @deprecated As of release 1.3, replaced by {@link #Fee}
*/@Deprecated
class Fum { ... }
public class Bar extends Fum { // Noncompliant; Fum is deprecated
public void myMethod() {
Foo foo = new Foo(); // okay; the class isn't deprecated
foo.doTheThing(); // Noncompliant
}
}
"ConcurrentLinkedQueue.size()" should not be used
ConcurrentLinkedQueue.size() 를 사용을 자제 해라.
해당 명령문은 Queue의 크기가 클 경우 작업시간이 오래 걸릴 수가 있다.
또는 Queue가 실행 중에 변경되는 경우 또한 결과가 정확하지 않을 수가 있다.
단지, 크기만을 위해서 체크해야 할 경우 isEmpty() 메소드와 함께 사용해야 합니다.
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
//...
log.info("Queue contains " + queue.size() + " elements");
"Exception" should not be caught when not required by called
methods
예외처리를 위해 try~catch 구문이 사용될때, catch 문에서 잡는 예외는 예외사항 별로
세부대응을 하도록 코딩한다. 광역 대응이 꼭 필요한 경우에는 앞에서 적용 가능한 세
부 대응을 먼저 사용 한 후 맨 마지막에 대응하도록 한다.
try {
// do something that might throw an UnsupportedDataTypeException or
UnsupportedEncodingException
} catch (Exception e) { // Noncompliant
// log exception ...
}
try {
// do something
} catch (UnsupportedEncodingException|UnsupportedDataTypeException|RuntimeException e) {
// log exception ...
}
"HttpServletRequest.getRequestedSessionId()" should not be used
- getRequestedSessionId 메소드 는?
: 클라이언트로 부터 지정된 세션ID를 반환한다. 이는 요청에 대한 현재 유효한 세션 ID
와 동일하지 않을 수 있다. 클라이언트가 세션 ID를 지정하지 않은 경우,이 메소드는
null를 돌려주게 됩니다.
세션ID가 어떠한 HTTP의 요청에 의해 변경이 될 수 있기 때문에 사용하지 않는다.
if(isActiveSession(request.getRequestedSessionId()) ){
...
}
"java.lang.Error" should not be extended
Java.lang.Error 클래스와 그 서브 클래스 들은 시스템의 뭔가 비정상적인 상황이 발생
했을 경우 사용된다.
그래서 주로 자바 VM에서 발생시키는 것이고 어플리케이션 코드에서 잡으려고 하면 안
된다.
OutofMemoryError나 ThreadDeath 같은 에러는 catch 블럭으로 잡아도 대응 방법이
없다.
따라서 시스템 레벨에서 특별한 작업을 하는 게 아니라면 어플리케이션에서는 이런 에
러에 대한 처리는 신경 쓰지 않아도 된다.
public class MyException extends Error { /* ... */ } // Noncompliant
public class MyException extends Exception { /* ... */ } // Compliant
"main" should not "throw" anything
main 메소드에서는 throw 를 사용하지 않는다.
Exception이 발생할 경우 던질 곳이 없다.
public static void main(String args[]) throws Exception { // Noncompliant
public static void main(String args[]) {
"NullPointerException" should not be caught
NullPointerException 이 발생할 수 있는 부분을 try catch로 구현하려는 것보다 발생
할 수 있는 부분에 미리 null 체크를 하여 발생하지 않도록 한다.
public int lengthPlus(String str) {
int len = 2;
try {
len += str.length();
}
catch (NullPointerException e) {
log.info("argument was null");
}
return len;
}
public int lengthPlus(String str) {
int len = 2;
if (str != null) {
len += str.length();
}
else {
log.info("argument was null");
}
return len;
}
"Object.finalize()" should remain protected (versus public) when
overriding
Object.finalize()를 오버라이드할 때 protected 상태를 유지 해야 한다.
finalize는 Garbage Collector에 의해 호출 됩니다.
따라서 어디에서나 호출할 수 있는 public을 사용하는 것은 잘못된 방법 입니다.
보통 finalize() 메소드를 override 하여 사용하고, System.gc() 메소드를 통해 가비지
컬렉션이 발생되도록 하여 정의된 finalize() 메소드를 수행시킨다.
public class MyClass {
@Override
public void finalize() { // Noncompliant
/* ... */
}
}
"public static" fields should be constant
public static 필드는 변하지 않아야 합니다.
final을 선언하지 않고 public 과 static 필드를 선언할 이유가 없다.
static 으로 변수를 선언하게 되면은 한 클래스의 모든 인스턴스에서 해당 static 변수를
공유할 수 있다.
public class Greeter {
public static Foo foo = new Foo();
...
}
public class Greeter {
public static final Foo FOO = new Foo();
...
}
"runFinalizersOnExit" should not be called
"runFinalizersOnExit"는 호출할 수 없다.
System.gc() 와 System.runFinalization() 메소드들을 사용하지 말자.
그 메소드들은 파이널라이저가 실행될 가능성을 높여주긴 하지만, 실행됨을 보장하지는 않는다.
파이널라이즈를 보장하는 유일한 메소드들은 System.runFinalizersOnExit() 와
Runtime.runFinalizersOnExit() 인데 이 메소드들은 치명적 결함이 있어 현재는 사용 금지되었다.
public static void main(String [] args) {
...
System.runFinalizersOnExit(true); // Noncompliant
...
}
protected void finalize(){
doSomething();
}
public static void main(String [] args) {
Runtime.addShutdownHook(new Runnable() {
public void run(){
doSomething();
}
});
//...
"static final" arrays should be "private"
static final 배열엔 private를 사용해라
public static final 배열 필드를 두거나, 배열 필드를 반환하는 접근자를 정의 하면 안
된다. 그런 멤버를 두면 클라이언트가 배열 내용을 변경할 수 있게 되므로, 보안에 문제
가 생긴다. 이 문제를 고치는 첫번째는 public으로 선언되었던 배열은 private으로 바
꾸고 변경이 불가능한 public 리스트를 하나 만드는 것이다.
public class Estate {
// Noncompliant; array contents can be modified
public static final String [] HEIRS = new String [] {
"Betty", "Suzy" };
}
public class Malicious {
public void changeWill() {
Estate.HEIRS[0] = "Biff";
if (Estate.HEIRS.length > 1) {
for (int i = 1; i < Estate.HEIRS.length; i++) {
Estate.HEIRS[i] = "";
}
}
}
public class Estate {
private static final String [] HEIRS = new String [] {
"Betty", "Suzy" };
public String [] getHeirs() {
// return copy of HEIRS
}
}
 클래스와 멤버의 접근 권한은 최소화 하라
- 각 클래스와 멤버는 가능한 접근 불가능하도록 만들어라
: 정보은닉 또는 캡슐화는 시스템을 구성하는 모듈 사이의 의존성을 낮춰서 개발 속도 및 유지보
수에 효율적이다.
- 객체필드(instance field)는 절대로 public으로 선언하면 안된다.
: 변경 가능 public 필드를 가진 클레스는 다중 스레드에 안전하지 않다. 변경 불가능 객체를 참조
하는 final 필드라 해도 public으로 선언하면 클래스 내부 데이터 표현 형태를 유연하게 바꿀 수
없게 된다
- static으로 선언된 필드에도 똑같이 적용되지만 한가지 예외가 있다. 어떤
상수들이 클래스로 추상화된 결과물의 핵심적 부분을 구성한다고 판단되는
경우, 해당 상수들을 public static final 필드들로 선언하여 공개할 수 있다.
(public static final 필드가 참조하는 객체는 변경 불가능 객체로 만들어라.)
- 길이가 0 아닌 배열은 언제나 변경 가능하므로, public static final 배열 필
드를 두거나, 배열 필드를 반환하는 접근자를 정의하면 안 된다. 그런 멤버
를 두면 클라이언트가 배열 내용을 변경할 수 있게 되므로, 보안에 문제가
생긴다.
//보안 문제를 초래할 수 있는 코드
public static final Thing[] VALUES { ... };
이 문제를 고치는 방법 중 첫 번째는 public으로 선언되었던 배열은 private으
로 바꾸고, 변경이 불가능한 public 리스트를 하나 만드는 것이다.
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUE));
두 번째 방법은 배열은 private으로 선언하고, 해당 배열을 복사해서 반환하는
public 메서드를 하나 추가하는 것이다.
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values(){ return PRIVATE_VALUES.clone(); }
"wait(...)" should be used instead of "Thread.sleep(...)" when a lock is
held
실행 대기 할 경우 Thread.sleep(…) 대신에 wait(…)를 사용하여라.
Thread.sleep()은 대상 Thread가 sleep 상태가 되는 것인데 lock을 획득한 상태로 sleep 합니다
Object에 대해 wait()을 수행하게 되면 해당 Object lock을 소유하고 있다면 lock을 반환하고 wait()
후 깨어나게 됩니다.
즉, wait()하게 되면 lock을 획득한 상태에서 lock를 반환하고 wait()하게됩니다.
그러면 lock 대기중인 다음 Thread가 lock을 획득하게 됩니다.
public void doSomething(){
synchronized(monitor) {
while(notReady()){
Thread.sleep(200);
}
process();
}
...
}
public void doSomething(){
synchronized(monitor) {
while(notReady()){
monitor.wait(200);
}
process();
}
...
}
Checked Exception should not be thrown
Checked Exception 은 발생하지 않아야 한다.
검증된 예외는 컴파일러나 jvm에 의해 말그대로 ‘걸러낸/확인된’ 자동화된 예외처리
방법이고 자바에서는 예외처리하도록 강제하기 위해 예외처리 하지 않으면 에러라 간
주하고 진행되지 않는다.
public void myMethod1() throws CheckedException {
...
throw new CheckedException(message); // Noncompliant
...
throw new IllegalArgumentException(message); // Compliant; IllegalArgumentException is unchecked
}
public void myMethod2() throws CheckedException { // Compliant; propagation allowed
myMethod1();
}
Classes should not be compared by name
클래스는 이름으로 비교해서는 안된다.
클래스의 이름은 패키지 내에서 고유하지만 패키지가 다를 경우 고유하지 않습니다. 따
라서 해당 클래스의 이름을 기준으로 비교는 위험 합니다.
악의적인 사용자가 비교 할 클래스의 이름과 같은 객체를 전송하여 액세스 할 경우 위
험할 수 있습니다.
package computer;
class Pear extends Laptop { ... }
package food;
class Pear extends Fruit { ... }
class Store {
public boolean hasSellByDate(Object item) {
if
("Pear".equals(item.getClass().getSimpleName()))
{ // Noncompliant
return true; // Results in throwing away week-
old computers
}
}
}
class Store {
public boolean hasSellByDate(Object item) {
if (item instanceof food.Pear) {
return true;
}
}
}
Cookies should be "secure"
쿠키는 secure로 사용해야 한다.
setSecure는 쿠키의 보안 설정으로 true로 설정할 경우 HTTPS나 SSL과 같은 secure
protocol 에서만 사용 할 수 있다.
Cookie c = new Cookie(SECRET, secret); // Noncompliant; cookie is not secure
response.addCookie(c);
Cookie c = new Cookie(SECRET, secret);
c.setSecure(true);
response.addCookie(c);
Credentials should not be hard-coded
자격증명은 하드코딩하지 말아라
하드코딩 할 경우 컴파일된 응용프로그램에서 문자열을 추출하기 쉽기 때문이다.
자격증명은 암호화된 외부 구성 파일이나 데이터베이스에 저장해야 합니다.
Connection conn = null;
try {
conn =
DriverManager.getConnection("jdbc:mysql://localh
ost/test?" +"user=steve&password=blue"); //
Noncompliant
String uname = "steve";
String password = "blue";
conn =
DriverManager.getConnection("jdbc:mysql://localh
ost/test?" +
"user=" + uname + "&password=" +
password); // Noncompliant
Connection conn = null;
try {
String uname = getEncryptedUser();
String password = getEncryptedPass();
conn =
DriverManager.getConnection("jdbc:mysql://localh
ost/test?" + "user=" + uname + "&password=" +
password);
Exception classes should be immutable
Exception classes는 불변해야 합니다.
Exception은 에러가 발생하는 어플리케이션의 상태를 표현하는 것을 의미한다.
public class MyException extends Exception {
private int status; // Noncompliant
public MyException(String message) {
super(message);
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
public class MyException extends Exception {
private final int status; // Compliant
public MyException(String message, int status) {
super(message);
this.status = status;
}
public int getStatus() {
return status;
}
}
Exception handlers should preserve the original exception
Exception handlers 는 원래 Excepion을 보존한다.
발생된 에러를 처리할 때, 발생한 예외를 그대로 호출한 쪽으로 전달되어야 합니다.
// Noncompliant - exception is lost
try { /* ... */ }catch (Exception e)
{ LOGGER.info("context"); }
// Noncompliant - exception is lost (only message
is preserved)
try { /* ... */ } catch (Exception e)
{ LOGGER.info(e.getMessage()); }
// Noncompliant - exception is lost
try { /* ... */ } catch (Exception e) { throw new
RuntimeException("context"); }
try { /* ... */ } catch (Exception e) { LOGGER.info(e); }
try { /* ... */ } catch (Exception e) { throw new
RuntimeException(e); }
try {
/* ... */
} catch (RuntimeException e) {
doSomething();
throw e;
} catch (Exception e) {
// Conversion into unchecked exception is also
allowed
throw new RuntimeException(e);
}
Exception types should not be tested using "instanceof" in catch
blocks
예외 유형은 catch 블록 안에서 “instanceof” 를 사용해서 테스트 해서는 안된다.
일반예외로 캐치한 다음에 유형에 따라서 처리하는 대신에 여러 유형에 맞는 catch 블
록에 처리 해야 한다.
try {
/* ... */
} catch (Exception e) {
if(e instanceof IOException) { /* ... */ } // Noncompliant
if(e instanceof NullPointerException{ /* ... */ } // Noncompliant
}
try {
/* ... */
} catch (IOException e) { /* ... */ } // Compliant
} catch (NullPointerException e) { /* ... */ } // Compliant
Exceptions should not be thrown from servlet methods
예외는 servlet methods에 발생되어서는 안된다.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String ip = request.getRemoteAddr();
InetAddress addr = InetAddress.getByName(ip); // Noncompliant; getByName(String) throws
UnknownHostException
//...
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
String ip = request.getRemoteAddr();
InetAddress addr = InetAddress.getByName(ip);
//...
}
catch (UnknownHostException uhex) {
//...
}
}
Exceptions should not be thrown in finally blocks
예외 시에 finally 블록에서 thrown 을 하면 안된다
Flnally block은 프로그램의 수행 중 발생할 수 있는 어느 문제에 대해서도 자원의 손상
을 막고 원상복구를 확실히하기 위해 사용된다.
즉, try-catch 구문에서 예외의 발생 여부에 상관없이 실행되어야 할 코드를 넣는 곳이
finlly 구문이다.
try {
/* some work which end up throwing an exception */
throw new IllegalArgumentException();
} finally {
/* clean up */
throw new RuntimeException(); // Noncompliant - will mask the IllegalArgumentException
}
try {
/* some work which end up throwing an exception */
throw new IllegalArgumentException();
} finally {
/* clean up */ // Compliant
}
Generic exceptions should never be thrown
일반적인 예외는 결코 thrown 하면 안된다.
public void foo(String bar) throws Throwable { // Noncompliant
throw new RuntimeException("My Message"); // Noncompliant
}
public void foo(String bar) {
throw new MyOwnRuntimeException("My Message");
}
HTTP referers should not be relied on
http referers에 의존해서는 안된다.
Referers는 공격자에 의해 수정이 가능하기 때문에 referers 값에 대해서 신뢰하지 말
아라.
public class MyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String referer = request.getHeader("referer"); // Noncompliant
if(isTrustedReferer(referer)){
//..
}
//...
}
}
IP addresses should not be hardcoded
IP주소를 하드코딩 하지 말아라
소스코드에 IP주소를 하드 코딩하는 것에 대한 나쁜 점
• 주소가 변경될 경우 재컴파일 해야 함
• 모든 환경에서 같은 주소가 사용되지 않는다.(개발, 검증, 운영)
• 공격자가 코드를 디컴파일하여 주소를 알아낼 수 있다.
String ip = "127.0.0.1";
Socket socket = new Socket(ip, 6667);
String ip = System.getProperty("myapplication.ip");
Socket socket = new Socket(ip, 6667);
Math operands should be cast before assignment
수학 연산자는 사용하기 전에 캐스팅 해야 한다.
연산의 경우 결과는 항상 int일 것이다.
float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0
long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
long bigNegNum = Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative
one.
Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if
seconds > 2_147_483
...
public long compute(int factor){
return factor * 10_000; //Noncompliant, won't produce the expected result if factor > 214_748
}
float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667
long millisInYear = 1_000L*3_600*24*365; // 1000 promoted to long. Yields 31_536_000_000
long bigNum = Integer.MAX_VALUE + 2L; // 2 promoted to long. Yields 2_147_483_649
long bigNegNum = Integer.MIN_VALUE-1L; // Yields -2_147_483_649
Date myDate = new Date(seconds * 1_000L);
...
public long compute(int factor){
return factor * 10_000L;
}
Member variable visibility should be specified
멤버변수의 가시성을 지정해야 한다.
class Ball {
String color="red"; // Noncompliant
}
enum A {
B;
int a;
}
class Ball {
private String color="red"; // Compliant
}
enum A {
B;
private int a;
}
Neither DES (Data Encryption Standard) nor DESede (3DES) should be
used
DES(데이터 암호화 표준) 도 DESede(3DES) 도 사용하지 않는다.
표준 및 미국 국립 기술 연구소 (NIST)에 따르면, 데이터 암호화 표준 (DES)는 더 이상
안전한 것으로 간주되지 않습니다
Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
Null pointers should not be dereferenced
널포인터는 역참조해서는 안된다.
일반적으로 그 객체가 NULL이 될 수 없다’라고 하는 가정을 위반했을 때 발생한다.
@CheckForNull
String getName() {...}
public boolean isNameEmpty() {
return getName().length() == 0; // Noncompliant; the result of getName() could be null, but isn't null-
checked
}
Connection conn = null;
Statement stmt = null;
try {
conn = DriverManager.getConnection(DB_URL,USER,PASS);
stmt = conn.createStatement();
// ...
} catch(Exception e) {
e.printStackTrace();
} finally {
stmt.close(); // Noncompliant; stmt could be null if an exception was thrown in the try{} block
conn.close(); // Noncompliant; conn could be null if an exception was thrown
}
Only standard cryptographic algorithms should be used
단지 표준 알고리즘을 사용해야 한다.
중요한 민감한 데이터를 디스크에 저장하거나 외부 전송 시, SW가 해당 데이터를 암호
화하지 않을 경우 민감한 데이터가 노출될 수 있다.
표준알고리즘 : SHA-256, SHA-384, SHA-512
MyCryptographicAlgorithm extends MessageDigest {
...
}
Public methods should throw at most one checked exception
Public method 에서는 대부분 하나의 exception을 체크하여 throw 한다.
public void delete() throws IOException, SQLException { // Noncompliant
/* ... */
}
public void delete() throws SomeApplicationLevelException {
/* ... */
}
Resources should be closed
자원은 닫아야 한다.
OutputStream stream = null;
try{
for (String property : propertyList) {
stream = new FileOutputStream("myfile.txt"); // Noncompliant
// ...
}
}catch(Exception e){
// ...
}finally{
stream.close(); // Multiple streams were opened. Only the last is closed.
}
OutputStream stream = null;
try{
stream = new FileOutputStream("myfile.txt");
for (String property : propertyList) {
// ...
}
}catch(Exception e){
// ...
}finally{
stream.close();
}
Throwable and Error should not be caught
Throw 가능 객체 와 Error는 catch에 사용할 수 없다.
Throw 가능 객체는 자바의 모든 에러와 예외의 슈퍼클래스 입니다.
Error는 응용 프로그램에 의해 발생되는 의미하지 않는 모든 에러의 슈퍼클래스 입니다.
try { /* ... */ } catch (Throwable t) { /* ... */ }
try { /* ... */ } catch (Error e) { /* ... */ }
try { /* ... */ } catch (RuntimeException e) { /* ... */ }
try { /* ... */ } catch (MyException e) { /* ... */ }
Throwable.printStackTrace(...) should not be called
Throwable.printStackTrace을 호출할 수 없습니다.
Throw 가능 객체를 사용하는 대신에 Loggers를 사용할 수 있습니다.
사용자는 쉽게 logs를 찾을 수 있습니다.
try {
/* ... */
} catch(Exception e) {
e.printStackTrace(); // Noncompliant
}
try {
/* ... */
} catch(Exception e) {
LOGGER.log("context", e); // Compliant
}
Untrusted data should not be stored in sessions
신뢰할 수 없는 데이터는 세션에 저장하지 말아야 한다.
웹 세션에서 데이터는 “신뢰 범위”에서 내부로 간주됩니다.
즉, 신뢰할 수 있는 것 입니다.
그러나 인증되지 않는 사용자로부터 입력된 데이터를 저장하는것은 신뢰의 범위를 벗
어나는 일입니다. 그 데이터를 부적절하게 사용될 수 있습니다.
login = request.getParameter("login");
session.setAttribute("login", login); // Noncompliant
Useless "if(true) {...}" and "if(false){...}" blocks should be removed
쓸모없는 If(true)와 if(false)는 제거 되야 합니다.
if (true) {
doSomething();
}
...
if (false) {
doSomethingElse();
}
if (2 < 3 ) { ... } // Noncompliant; always false
int i = 0;
int j = 0;
// ...
j = foo();
if (j > 0 && i > 0) { ... } // Noncompliant; always false - i never set after initialization
boolean b = true;
//...
if (b || !b) { ... } // Noncompliant
doSomething();
...
Values passed to OS commands should be sanitized
OS 명령어로 전달된 값은 제거 되어야 한다.
public void listContent(String input) {
Runtime rt = Runtime.getRuntime();
rt.exec("ls " + input); // Noncompliant; input could easily contain extra commands
...
}
public void execute(String command, String argument) {
ProcessBuilder pb = new ProcessBuilder(command, argument); // Noncompliant
...
}
Web applications should not have a "main" method
웹 응용프로그램은 “main” 메소드를 사용하지 말아야 한다.
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
if (userIsAuthorized(req)) {
updatePrices(req);
}
}
public static void main(String[] args) { // Noncompliant
updatePrices(req);
}
}
Web applications should use validation filters
웹 응용프로그램에서 검증 필터를 사용해야 한다.
public class ValidatingHttpRequest extends HttpServletRequestWrapper {
// ...
}
public class ValidationFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
chain.doFilter(new ValidatingHttpRequest( (HttpServletRequest)request ), response);
}
}
<filter>
<filter-name>ValidationFilter</filter-name>
<filter-class>com.myco.servlet.ValidationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ValidationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
"ConcurrentLinkedQueue.size()" should not be used
ConcurrentLinkedQueue.size()는 사용하지 말아라.
큐의 크기를 확인하는 메소드는 일정한 시간이 필요로 하는데, 큐의 크기가 클수록 시
간이 오래 걸릴 수 있다. 그리고 큐가 실행 중 변경이 되는 경우 결과가 정확하지 않을
수 있다.
그런데, size()를 사용해야 할 경우에는 큐가 비어 있는지 확인 하기 위한 isEmpty()를
함께 사용해야 한다.
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
//...
log.info("Queue contains " + queue.size() + " elements");
"DateUtils.truncate" from Apache Commons Lang library should not be
used
Apache commons lang library 중에서 “DateUtils.truncate”는 사용할 수 없습니다.
날짜를 truncate 하는 DateUtils.truncate 보다 Java 8에서 도입된 Instant 클래스가
훨씬 빠를 수 있습니다.
public Date trunc(Date date) {
return DateUtils.truncate(date, Calendar.SECOND); // Noncompliant
}
public Date trunc(Date date) {
Instant instant = date.toInstant();
instant = instant.truncatedTo(ChronoUnit.SECONDS);
return Date.from(instant);
}
"deleteOnExit" should not be used
“deleteOnExit”는 사용하지 말아라.
File.deleteOnExit()의 사용은 다음과 같은 이유로 권장하지 않습니다.
- 삭제는 일반적으로 JVM 종료의 경우에 발생하지만, JVM이 충돌 또는 죽었을 경우에
삭제되지 않는다.
- 파일 삭제가 성공했음에도 불구하고 JVM이 종료 할 때까지 파일정보를 보관되면서
메모리가 증가
File file = new File("file.txt");
file.deleteOnExit(); // Noncompliant
"entrySet()" should be iterated when both the key and value are
needed
key와 value가 모두 필요할 때 entrySet() 을 반복해서 사용해야 한다.
HashMap에 entrySet 메소드를 호출하면 키가 들어있는 Set이 넘어 옵니다.
Set에서 iterator를 뽑아내면 while 문으로 루프를 돌려서 키를 하나씩 가져올 수 있습
니다.
public void doSomethingWithMap(Map<String,Object> map) {
for (String key : map.keySet()) { // Noncompliant; for each key the value is retrieved
Object value = map.get(key);
// ...
}
}
public void doSomethingWithMap(Map<String,Object> map) {
for (Map.Entry<String,Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// ...
}
}
"ResultSet.isLast()" should not be used
ResultSet.isLast()를 사용하지 말아라.
stmt.executeQuery("SELECT name, address FROM PERSON");
ResultSet rs = stmt.getResultSet();
while (! rs.isLast()) { // Noncompliant
// process row
}
ResultSet rs = stmt.executeQuery("SELECT name, address FROM PERSON");
while (! rs.next()) {
// process row
}
"URL.hashCode" and "URL.equals" should be avoided
“URL.hashCode” 와 “URL.equals”는 피해야 한다.
Equals와 hashCode 메소드는 java.net.URL
public void checkUrl(URL url) {
Set<URL> sites = new HashSet<URL>(); // Noncompliant
URL homepage = new URL("http://sonarsource.com"); // Compliant
if (homepage.equals(url)) { // Noncompliant
// ...
}
}
public void checkUrl(URL url) {
Set<URI> sites = new HashSet<URI>(); // Compliant
URI homepage = new URI("http://sonarsource.com"); // Compliant
URI uri = url.toURI();
if (homepage.equals(uri)) { // Compliant
// ...
}
}
"wait(...)" should be used instead of "Thread.sleep(...)" when a lock is
held
“Thread.sleep(…)” 대신에 “wait(…)”의 사용은 잠금이 유지 된다.
Wait() : 동기화된 다중스레드가 같은 오브젝트에 접근하고자 할 때 중지시킨다.
Sleep() : 동기화된 다중스레드를 시간으로 중지시킨다.
public void doSomething(){
synchronized(monitor) {
while(notReady()){
Thread.sleep(200);
}
process();
}
...
}
public void doSomething(){
synchronized(monitor) {
while(notReady()){
monitor.wait(200);
}
process();
}
...
}
Multiple loops over the same set should be combined
같은 설정의 여러 루프는 결합해서 사용한다.
public void doSomethingToAList(List<String>
strings) {
for (String str : strings) {
doStep1(str);
}
for (String str : strings) { // Noncompliant
doStep2(str);
}
}
public void doSomethingToAList(List<String>
strings) {
for (String str : strings) {
doStep1(str);
doStep2(str);
}
}
Objects should not be created only to "getClass"
Object를 단지 getClass로 생성하지 말아라
getClass의 호출의 목적은 객체를 생성하는 것인데, 객체를 생성하게 되면 메모리 낭비
가 발생하므로 단순히 class를 사용합니다.
MyObject myOb = new MyObject(); // Noncompliant
Class c = myOb.getClass();
Class c = MyObject.class;
Sets with elements that are enum values should be replaced with
EnumSet
열거 값이 있는 elements set는 EnumSet 으로 대체해야 합니다.
public class MyClass {
public enum COLOR {
RED, GREEN, BLUE, ORANGE;
}
public void doSomething() {
Set<COLOR> warm = new HashSet<COLOR>();
warm.add(COLORS.RED);
warm.add(COLORS.ORANGE);
}
}
public class MyClass {
public enum COLOR {
RED, GREEN, BLUE, ORANGE;
}
public void doSomething() {
EnumSet<COLOR> warm =
EnumSet.of(COLOR.RED, COLOR.ORANGE);
}
}
String function use should be optimized for single characters
String function은 하나의 기호에 적합하다.
String myStr = "Hello World";
// ...
int pos = myStr.indexOf("W"); // Noncompliant
// ...
int otherPos = myStr.lastIndexOf("r"); // Noncompliant
// ...
String myStr = "Hello World";
// ...
int pos = myStr.indexOf('W');
// ...
int otherPos = myStr.lastIndexOf('r');
// ...
Strings should not be concatenated using '+' in a loop
문자열은 루프에서 ‘+’을 사용하여 연결되어서는 안된다.
문자열은 불변객체 입니다. 그래서 연결은 단순히 기존의 문자열 끝에 새로운 문자열을
추가 하지 않습니다. 대신 각 루프가 반복되면서 첫번째 문자열이 연결되는 문자열 형
식으로 변환됩니다. 이런식으로 문자열이 길어지면 작업의 성능의 저하가 발생하게 됩
니다. 따라서 StringBuilder의 사용이 바람직합니다.
String str = "";
for (int i = 0; i < arrayOfStrings.length ; ++i) {
str = str + arrayOfStrings[i];
}
StringBuilder bld = new StringBuilder();
for (int i = 0; i < arrayOfStrings.length; ++i) {
bld.append(arrayOfStrings[i]);
}
String str = bld.toString();
Synchronized classes Vector, Hashtable, Stack and StringBuffer should
not be used
동기화(Synchronized) classes는 Vector, Hashtable, Stack and StringBuffer를 사용
하면 안된다.
Vertor의 경우 무조건 동기화이기 때문에 단일 스레드를 사용할 경우에는 성능저하를
가져오게됩니다.
- Vector 대신에 ArrayList 또는 LinkedList를 사용
- Stack 대신에 Deque를 사용
- Hashtable 대신에 HashMap 사용
- StringBuffer 대신에 StringBuilder 사용
Vector cats = new Vector();
ArrayList cats = new ArrayList();
Sonarqube 20160509

More Related Content

What's hot

테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체Mickey SJ Lee
 
테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)KH Park (박경훈)
 
TDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDTDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDSuwon Chae
 
행복한 개발을 위한_테스트_케이스
행복한 개발을 위한_테스트_케이스행복한 개발을 위한_테스트_케이스
행복한 개발을 위한_테스트_케이스도형 임
 
C Language II
C Language IIC Language II
C Language IISuho Kwon
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례SangIn Choung
 
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)SangIn Choung
 
린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)영기 김
 
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자Taeyeop Kim
 
위험기반테스트접근 테스트계획 사례
위험기반테스트접근 테스트계획 사례위험기반테스트접근 테스트계획 사례
위험기반테스트접근 테스트계획 사례SangIn Choung
 
testing for agile?, agile for testing
testing for agile?, agile for testingtesting for agile?, agile for testing
testing for agile?, agile for testingSangIn Choung
 
2010 SW Testing Trend
2010 SW Testing Trend2010 SW Testing Trend
2010 SW Testing TrendMurian Song
 
애자일 하라
애자일 하라애자일 하라
애자일 하라진수 허
 

What's hot (18)

테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체
 
TEST?
TEST?TEST?
TEST?
 
테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)
 
TDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDTDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDD
 
C++과 TDD
C++과 TDDC++과 TDD
C++과 TDD
 
행복한 개발을 위한_테스트_케이스
행복한 개발을 위한_테스트_케이스행복한 개발을 위한_테스트_케이스
행복한 개발을 위한_테스트_케이스
 
C Language II
C Language IIC Language II
C Language II
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례
 
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
 
린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)린 소프트웨어 개발(Lean software development)
린 소프트웨어 개발(Lean software development)
 
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
 
위험기반테스트접근 테스트계획 사례
위험기반테스트접근 테스트계획 사례위험기반테스트접근 테스트계획 사례
위험기반테스트접근 테스트계획 사례
 
Tdd with JUnit 1
Tdd with JUnit 1Tdd with JUnit 1
Tdd with JUnit 1
 
The Introduction to Refactoring
The Introduction to Refactoring The Introduction to Refactoring
The Introduction to Refactoring
 
Work With Engineer
Work With EngineerWork With Engineer
Work With Engineer
 
testing for agile?, agile for testing
testing for agile?, agile for testingtesting for agile?, agile for testing
testing for agile?, agile for testing
 
2010 SW Testing Trend
2010 SW Testing Trend2010 SW Testing Trend
2010 SW Testing Trend
 
애자일 하라
애자일 하라애자일 하라
애자일 하라
 

Viewers also liked

SVN에서 GIT으로 전환하기
SVN에서 GIT으로 전환하기SVN에서 GIT으로 전환하기
SVN에서 GIT으로 전환하기재윤 정
 
Softskills
SoftskillsSoftskills
Softskills혁 권
 
신입웹개발자교육
신입웹개발자교육신입웹개발자교육
신입웹개발자교육은숙 이
 
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)JiandSon
 
SonarQube 로 Unity 프로젝트 관리
SonarQube 로 Unity 프로젝트 관리SonarQube 로 Unity 프로젝트 관리
SonarQube 로 Unity 프로젝트 관리EG Lim
 
리눅스 환경에서 SonarQube 간단하게 사용해보기
리눅스 환경에서 SonarQube 간단하게 사용해보기리눅스 환경에서 SonarQube 간단하게 사용해보기
리눅스 환경에서 SonarQube 간단하게 사용해보기flashscope
 
2015 Newguest presentation wide OT
2015 Newguest presentation wide OT2015 Newguest presentation wide OT
2015 Newguest presentation wide OTWonWoo Jo
 
Java script 신입교육
Java script 신입교육Java script 신입교육
Java script 신입교육준성 황
 
새 직원 교육
새 직원 교육새 직원 교육
새 직원 교육gahae
 
devon2013: 사내Git저장소개발사례
devon2013: 사내Git저장소개발사례devon2013: 사내Git저장소개발사례
devon2013: 사내Git저장소개발사례Daehyun Kim
 
Static Code Analysis and Cppcheck
Static Code Analysis and CppcheckStatic Code Analysis and Cppcheck
Static Code Analysis and CppcheckZachary Blair
 
[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들
[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들
[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들MinGeun Park
 
좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012Daum DNA
 
스프링군살없이세팅하기(The way to setting the Spring framework for web.)
스프링군살없이세팅하기(The way to setting the Spring framework for web.)스프링군살없이세팅하기(The way to setting the Spring framework for web.)
스프링군살없이세팅하기(The way to setting the Spring framework for web.)EunChul Shin
 
Si 프로젝트에서 바라보는...traditional vs agile
Si 프로젝트에서 바라보는...traditional vs agileSi 프로젝트에서 바라보는...traditional vs agile
Si 프로젝트에서 바라보는...traditional vs agileKiwon Kyung
 
Istqb 3-정적테스팅기법-2015
Istqb 3-정적테스팅기법-2015Istqb 3-정적테스팅기법-2015
Istqb 3-정적테스팅기법-2015Jongwon Lee
 
Agile - SCRUM을 통한 개발관리
Agile - SCRUM을 통한 개발관리Agile - SCRUM을 통한 개발관리
Agile - SCRUM을 통한 개발관리SangJin Kang
 
Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1Jongwon Lee
 

Viewers also liked (20)

SVN에서 GIT으로 전환하기
SVN에서 GIT으로 전환하기SVN에서 GIT으로 전환하기
SVN에서 GIT으로 전환하기
 
Softskills
SoftskillsSoftskills
Softskills
 
신입웹개발자교육
신입웹개발자교육신입웹개발자교육
신입웹개발자교육
 
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
2015.03.25 테크니컬 세미나 - SonarQube를 활용한 코드 품질 시각화(김모세)
 
SonarQube 로 Unity 프로젝트 관리
SonarQube 로 Unity 프로젝트 관리SonarQube 로 Unity 프로젝트 관리
SonarQube 로 Unity 프로젝트 관리
 
리눅스 환경에서 SonarQube 간단하게 사용해보기
리눅스 환경에서 SonarQube 간단하게 사용해보기리눅스 환경에서 SonarQube 간단하게 사용해보기
리눅스 환경에서 SonarQube 간단하게 사용해보기
 
Sonar 설치
Sonar 설치Sonar 설치
Sonar 설치
 
2015 Newguest presentation wide OT
2015 Newguest presentation wide OT2015 Newguest presentation wide OT
2015 Newguest presentation wide OT
 
Java script 신입교육
Java script 신입교육Java script 신입교육
Java script 신입교육
 
새 직원 교육
새 직원 교육새 직원 교육
새 직원 교육
 
devon2013: 사내Git저장소개발사례
devon2013: 사내Git저장소개발사례devon2013: 사내Git저장소개발사례
devon2013: 사내Git저장소개발사례
 
Sonarqube
SonarqubeSonarqube
Sonarqube
 
Static Code Analysis and Cppcheck
Static Code Analysis and CppcheckStatic Code Analysis and Cppcheck
Static Code Analysis and Cppcheck
 
[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들
[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들
[KGC2011_박민근] 신입 게임 개발자가 알아야 할 것들
 
좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012좌충우돌 ORM 개발기 | Devon 2012
좌충우돌 ORM 개발기 | Devon 2012
 
스프링군살없이세팅하기(The way to setting the Spring framework for web.)
스프링군살없이세팅하기(The way to setting the Spring framework for web.)스프링군살없이세팅하기(The way to setting the Spring framework for web.)
스프링군살없이세팅하기(The way to setting the Spring framework for web.)
 
Si 프로젝트에서 바라보는...traditional vs agile
Si 프로젝트에서 바라보는...traditional vs agileSi 프로젝트에서 바라보는...traditional vs agile
Si 프로젝트에서 바라보는...traditional vs agile
 
Istqb 3-정적테스팅기법-2015
Istqb 3-정적테스팅기법-2015Istqb 3-정적테스팅기법-2015
Istqb 3-정적테스팅기법-2015
 
Agile - SCRUM을 통한 개발관리
Agile - SCRUM을 통한 개발관리Agile - SCRUM을 통한 개발관리
Agile - SCRUM을 통한 개발관리
 
Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1Istqb 4-테스트설계기법-2015-1
Istqb 4-테스트설계기법-2015-1
 

Similar to Sonarqube 20160509

유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙Hyosang Hong
 
Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙Hyosang Hong
 
소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙Hong Hyo Sang
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.Ryan Park
 
Robot framework 을 이용한 기능 테스트 자동화
Robot framework 을 이용한 기능 테스트 자동화Robot framework 을 이용한 기능 테스트 자동화
Robot framework 을 이용한 기능 테스트 자동화Jaehoon Oh
 
구글테스트
구글테스트구글테스트
구글테스트진화 손
 
TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기Wonchang Song
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Testbeom kyun choi
 
Backend Master | 3.2.1 Test - JUnit
Backend Master | 3.2.1 Test - JUnitBackend Master | 3.2.1 Test - JUnit
Backend Master | 3.2.1 Test - JUnitKyunghun Jeon
 
투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2
투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2
투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2tobeware
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Ryan Park
 
回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...
回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...
回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...asfasf4
 
The Future of .NET and C#
The Future of .NET and C#The Future of .NET and C#
The Future of .NET and C#명신 김
 
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by NetflixJi-Woong Choi
 
[기본과정] 코드 테스트와 커버리지 기본 교육(개념)
[기본과정] 코드 테스트와 커버리지 기본 교육(개념)[기본과정] 코드 테스트와 커버리지 기본 교육(개념)
[기본과정] 코드 테스트와 커버리지 기본 교육(개념)SangIn Choung
 

Similar to Sonarqube 20160509 (20)

Cygnus unit test
Cygnus unit testCygnus unit test
Cygnus unit test
 
유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙유지보수 가능한 개발 원칙
유지보수 가능한 개발 원칙
 
Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙Java 유지보수 가능한 개발 원칙
Java 유지보수 가능한 개발 원칙
 
소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙소프트웨어 개선 그룹(Sig) 개발 원칙
소프트웨어 개선 그룹(Sig) 개발 원칙
 
Android unit testing
Android unit testingAndroid unit testing
Android unit testing
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.
 
Node.js 기본
Node.js 기본Node.js 기본
Node.js 기본
 
Robot framework 을 이용한 기능 테스트 자동화
Robot framework 을 이용한 기능 테스트 자동화Robot framework 을 이용한 기능 테스트 자동화
Robot framework 을 이용한 기능 테스트 자동화
 
구글테스트
구글테스트구글테스트
구글테스트
 
TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기
 
Eclipse RCP 1/2
Eclipse RCP 1/2Eclipse RCP 1/2
Eclipse RCP 1/2
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
 
4-1. javascript
4-1. javascript4-1. javascript
4-1. javascript
 
Backend Master | 3.2.1 Test - JUnit
Backend Master | 3.2.1 Test - JUnitBackend Master | 3.2.1 Test - JUnit
Backend Master | 3.2.1 Test - JUnit
 
투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2
투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2
투비웨어 AgitarOne Junit 단위테스트자동화 솔루션소개_201608_v1.2
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 
回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...
回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...
回国去哪买毕业证办迪肯大学毕业证Deakin毕业证书【Q微202-661-4433】 Deakin售澳洲毕业证原版新毕业证书出售各国毕业证买澳洲毕业证的价...
 
The Future of .NET and C#
The Future of .NET and C#The Future of .NET and C#
The Future of .NET and C#
 
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
 
[기본과정] 코드 테스트와 커버리지 기본 교육(개념)
[기본과정] 코드 테스트와 커버리지 기본 교육(개념)[기본과정] 코드 테스트와 커버리지 기본 교육(개념)
[기본과정] 코드 테스트와 커버리지 기본 교육(개념)
 

Sonarqube 20160509

  • 2.  소프트웨어 품질  소프트웨어 구현  SonarQube 기능 및 특징  SonarQube 사용방법  소스 품질을 위한 코딩  Q&A
  • 3.  기능적 요구사항(Functional Requirements) - 수행될 기능과 관련되어 입력과 출력 및 그들 사이의 처리과정 - 목표로 하는 제품의 구현을 위해 소프트웨어가 가져야 하는 기능 적 속성  비기능적 요구사항(Non-Functional Requirements) ◦ 제품의 품질 기준 등을 만족시키기 위해 소프트웨어가 가져야 하 는 성능, 사용의 용의성, 안전성과 같은 행위적 특성 ◦ 시스템의 기능에 관련되지 않는 사항을 나타냄 기능 비기능
  • 4. 효율적인 SW 개발 관리 가치있는 SW 계 획 명확한 목표수립 수 행 효율적인 개발활동 검 증 지속적인 모니터링 및 통재 “계획 기반의 지속적 검증” “시각적 검증을 위한 시스템 활용”
  • 6. 1. 소스코드를 바이너리 파일로 컴파일 한다. 2. 바이너리 파일을 배포 형태로 패키징 한다. 3. 단위테스트(커버리지 포함) 수행한다. 4. 정적분석을 수행한다. 5. 분석 결과를 리포팅한다. 6. 패키징한 파일을 테스트 서버에 배포한다.
  • 7.  SW 구현은 SW 공학의 가장 기본적인 활동으로 코드작성, 디버깅, SW통합, 개발 자 테스팅 활동들로 이루어진다.  SW 구현할 때 고려해야 할 4가지 주요원칙 - 코딩의 복잡성을 최소화 - 향후에 일어날 변화를 고려 - 소프트웨어 구현은 검증이 가능해야 한다는 것 - 표준을 활용하는 것  코딩 규칙이나 표준을 수립하여 모든 개발자가 프로젝트에서 조화롭게 작업할 수 있도록 해야 한다. 이렇게 해서 좋아진 소스 코드의 가독성은 개발자가 SW 시 스템을 이해하는데 영향을 미치게 되고, 가독성이 향상되면 이해가 용이해지고 유지보수가 수월해지며 일반적으로 코드의 품질도 좋아진다.
  • 8.  품질 관리 도구의 주요기능  잠재적 오류 소스 코드 검출  개발 표준 준수  쉬운 룰 생성 및 편집  자동 룰 업데이트  정적 분석 도구를 통해 검색 되는 내용  공유된 코딩 스타일 위반  잠재적 버그의 코딩  설계상의 문제가 되는 코드  중복되고 보안에 위반되는 코드  등등……
  • 9.  정적 분석 도구로 소스코드에 대한 전반적인 품질 을 확보할 수 있도록 정보를 제공하는 통합 플랫폼  Server / Client 구조  C/C++/Java 등 15개 이상의 다양한 프로그램 언 어 지원  플러그인 설치로 다양한 도구와 유연한 통합  웹 기반 애플리케이션으로 다양한 결과를 서버에 서 통합 관리 용이
  • 10.  프로젝트 소스 품질을 관리할 수 있도록 여러가지 모니 터링 툴을 제공하는 오픈소스 플랫폼  보통 SonarQube는 단독으로 사용되기 보다는 Jenkins 같은 CI 서버와 연동이 되어서 사용이 되어지고 있으며 Java를 포함한 20가지가 넘는 프로그램밍 언어로 제작된 프로젝트의 모니터링을 제공
  • 11.  Java 기반의 정적분석 툴로써, 다양한 항목에 대해 분석 및 결과를 볼 수 있는 품질관리 대시보드 툴 - 소스코드관리 하는 오픈소스기반의 무료툴 - 자바검증도구(PMD, findbugs, Checkstyle)가 PlugIn 형태로 들어가 있음 - 중복코드(Squid, CPD) 체크 - 코드 커버리지(Cobertura, jaCoCo)
  • 12.  JDK 환경에서 동작, 웹서버 및 DBMS 필요  다양한 OS를 지원 : Windows, Linux, Mac OS X, Unix  DBMS 필요 => Derby(기본 제공), MSSQL, MySQL, Oracle  웹서버(WAS : Web Application Server) 필요 => Jetty6, Apache Tomcat  자바 기반 프로그램 : JDK 1.5 이상 필요
  • 13. - Sonar 자체는 분석결과를 보여주는 툴. 실제분석은 Sonar 내의 Plug-in을 통하여 분석 - 기본적으로 제공되는 분석 툴 1) PMD : 소스코드의 표준준수 분석 2) FindBugs : 자바바이트코드를 분석하여 정적분석 3) CheckStyle : 코드 스타일체크 4) Cobertura : 테스트 커버리지체크 5) Surefire : 유닛테스트 - Sonar에서 분석결과를 보기 위해 분석을 위한 Client의 종류 1) Sonar runner : 권장되는 기본 클라이언트 2) Maven : Maven 기반으로 작성된 프로젝트에 적합 3) Ant Task : Ant 작성된 프로젝트에 적합
  • 14. - Sonar는 Checkstyle, PMD, FindBugs, Coberbura 등의 분석툴 들을 이용하여 소스의 정적분석을 실시하고, 이 를 웹브라우저를 통하여 전체적인 분석결과를 보여주는 툴 SonarQube Analysers Eclipse Database Server
  • 15. - Sonar가 제공하는 분석결과는 다음과 같음 - 코드 중복 체크 - 코드의 표준 - 코드 coverage - 코드 복잡도 - 주석 - 디자인 과 아키텍쳐 - 기본적으로는 Java 언어를 분석할 수 있지만, 추가 플러 그인을 통하여 다른 대부분의 언어에 대해서도 검사 가 능
  • 16.  JAVA, C/C++등의 다수 프로그램 언어 지원  플러그인 설치로 다양한 도구와 유연한 통합  여러가지 분석 툴을 통합하여 여러 항목들을 한번에 검 사 가능(Checkstyle, PMD, FindBugs, CPPCheck, Cobertura 등)  웹기반 애플리케이션으로 다양한 분석 결과들을 확인 가 능 (버그&잠재버그체크, 코딩 표준 위반 체크, 중복 코드 체크, 단위 테스트 커버리지 체크, 소스 복잡도 체크, 주석 처리량 체크)  분석을 위한 여러 클라이언트를 제공 (Sonar runner, Maven, Ant T ask)
  • 17.  정적 코드 분석 도구 선정부터 적용까지 모든 프로 세스에 개발자 참여  코드에 알맞은 도구 선택  새롭게 작성하는 코드에 집중하기. 이미 작성된 코 드에 너무 신경쓰지 말 것  결함 찾는데 혈안 되지 말고 개발 생산성에 집중  정적코드 분석 및 결과에 대한 이슈 관리를 자동화
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.  https://nemo.sonarqube.org/  코딩 규칙(Rules) ◦ Lanauage : Java ◦ Tag : Security, performance
  • 28. "@Deprecated" code should not be used 이 Annotation은 가급적 사용을 자제해달라는 의미로 사용된다. 예를들어 어떤 method 앞에 @Deprecated가 붙으면, 이 메소드를 사용하거나 오버라이드 할 경우, 컴파일 할 때 경고가 뜬다. 더 나은, 개선된 메소드가 있음을 나타내고자 할 때에 주로 사용한다. 개발자가 어떤 메 소드를 썼는데, 이 메소드가 deprecated annotation 처리 되어있다면, 이 메소드는 다 음 버젼에서 사라지거나 더 개선된 메소드로 대체될 것이기 때문에, 이용을 자제해야한 다. (요약 하자면, 더 나은 기능을 제공하고 있으니, 차선책을 찾아보라는 의미로 쓰인 다) /** * @deprecated As of release 1.3, replaced by {@link #Fee} */@Deprecated class Fum { ... } public class Bar extends Fum { // Noncompliant; Fum is deprecated public void myMethod() { Foo foo = new Foo(); // okay; the class isn't deprecated foo.doTheThing(); // Noncompliant } }
  • 29. "ConcurrentLinkedQueue.size()" should not be used ConcurrentLinkedQueue.size() 를 사용을 자제 해라. 해당 명령문은 Queue의 크기가 클 경우 작업시간이 오래 걸릴 수가 있다. 또는 Queue가 실행 중에 변경되는 경우 또한 결과가 정확하지 않을 수가 있다. 단지, 크기만을 위해서 체크해야 할 경우 isEmpty() 메소드와 함께 사용해야 합니다. ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); //... log.info("Queue contains " + queue.size() + " elements");
  • 30. "Exception" should not be caught when not required by called methods 예외처리를 위해 try~catch 구문이 사용될때, catch 문에서 잡는 예외는 예외사항 별로 세부대응을 하도록 코딩한다. 광역 대응이 꼭 필요한 경우에는 앞에서 적용 가능한 세 부 대응을 먼저 사용 한 후 맨 마지막에 대응하도록 한다. try { // do something that might throw an UnsupportedDataTypeException or UnsupportedEncodingException } catch (Exception e) { // Noncompliant // log exception ... } try { // do something } catch (UnsupportedEncodingException|UnsupportedDataTypeException|RuntimeException e) { // log exception ... }
  • 31. "HttpServletRequest.getRequestedSessionId()" should not be used - getRequestedSessionId 메소드 는? : 클라이언트로 부터 지정된 세션ID를 반환한다. 이는 요청에 대한 현재 유효한 세션 ID 와 동일하지 않을 수 있다. 클라이언트가 세션 ID를 지정하지 않은 경우,이 메소드는 null를 돌려주게 됩니다. 세션ID가 어떠한 HTTP의 요청에 의해 변경이 될 수 있기 때문에 사용하지 않는다. if(isActiveSession(request.getRequestedSessionId()) ){ ... }
  • 32. "java.lang.Error" should not be extended Java.lang.Error 클래스와 그 서브 클래스 들은 시스템의 뭔가 비정상적인 상황이 발생 했을 경우 사용된다. 그래서 주로 자바 VM에서 발생시키는 것이고 어플리케이션 코드에서 잡으려고 하면 안 된다. OutofMemoryError나 ThreadDeath 같은 에러는 catch 블럭으로 잡아도 대응 방법이 없다. 따라서 시스템 레벨에서 특별한 작업을 하는 게 아니라면 어플리케이션에서는 이런 에 러에 대한 처리는 신경 쓰지 않아도 된다. public class MyException extends Error { /* ... */ } // Noncompliant public class MyException extends Exception { /* ... */ } // Compliant
  • 33. "main" should not "throw" anything main 메소드에서는 throw 를 사용하지 않는다. Exception이 발생할 경우 던질 곳이 없다. public static void main(String args[]) throws Exception { // Noncompliant public static void main(String args[]) {
  • 34. "NullPointerException" should not be caught NullPointerException 이 발생할 수 있는 부분을 try catch로 구현하려는 것보다 발생 할 수 있는 부분에 미리 null 체크를 하여 발생하지 않도록 한다. public int lengthPlus(String str) { int len = 2; try { len += str.length(); } catch (NullPointerException e) { log.info("argument was null"); } return len; } public int lengthPlus(String str) { int len = 2; if (str != null) { len += str.length(); } else { log.info("argument was null"); } return len; }
  • 35. "Object.finalize()" should remain protected (versus public) when overriding Object.finalize()를 오버라이드할 때 protected 상태를 유지 해야 한다. finalize는 Garbage Collector에 의해 호출 됩니다. 따라서 어디에서나 호출할 수 있는 public을 사용하는 것은 잘못된 방법 입니다. 보통 finalize() 메소드를 override 하여 사용하고, System.gc() 메소드를 통해 가비지 컬렉션이 발생되도록 하여 정의된 finalize() 메소드를 수행시킨다. public class MyClass { @Override public void finalize() { // Noncompliant /* ... */ } }
  • 36. "public static" fields should be constant public static 필드는 변하지 않아야 합니다. final을 선언하지 않고 public 과 static 필드를 선언할 이유가 없다. static 으로 변수를 선언하게 되면은 한 클래스의 모든 인스턴스에서 해당 static 변수를 공유할 수 있다. public class Greeter { public static Foo foo = new Foo(); ... } public class Greeter { public static final Foo FOO = new Foo(); ... }
  • 37. "runFinalizersOnExit" should not be called "runFinalizersOnExit"는 호출할 수 없다. System.gc() 와 System.runFinalization() 메소드들을 사용하지 말자. 그 메소드들은 파이널라이저가 실행될 가능성을 높여주긴 하지만, 실행됨을 보장하지는 않는다. 파이널라이즈를 보장하는 유일한 메소드들은 System.runFinalizersOnExit() 와 Runtime.runFinalizersOnExit() 인데 이 메소드들은 치명적 결함이 있어 현재는 사용 금지되었다. public static void main(String [] args) { ... System.runFinalizersOnExit(true); // Noncompliant ... } protected void finalize(){ doSomething(); } public static void main(String [] args) { Runtime.addShutdownHook(new Runnable() { public void run(){ doSomething(); } }); //...
  • 38. "static final" arrays should be "private" static final 배열엔 private를 사용해라 public static final 배열 필드를 두거나, 배열 필드를 반환하는 접근자를 정의 하면 안 된다. 그런 멤버를 두면 클라이언트가 배열 내용을 변경할 수 있게 되므로, 보안에 문제 가 생긴다. 이 문제를 고치는 첫번째는 public으로 선언되었던 배열은 private으로 바 꾸고 변경이 불가능한 public 리스트를 하나 만드는 것이다. public class Estate { // Noncompliant; array contents can be modified public static final String [] HEIRS = new String [] { "Betty", "Suzy" }; } public class Malicious { public void changeWill() { Estate.HEIRS[0] = "Biff"; if (Estate.HEIRS.length > 1) { for (int i = 1; i < Estate.HEIRS.length; i++) { Estate.HEIRS[i] = ""; } } } public class Estate { private static final String [] HEIRS = new String [] { "Betty", "Suzy" }; public String [] getHeirs() { // return copy of HEIRS } }
  • 39.  클래스와 멤버의 접근 권한은 최소화 하라 - 각 클래스와 멤버는 가능한 접근 불가능하도록 만들어라 : 정보은닉 또는 캡슐화는 시스템을 구성하는 모듈 사이의 의존성을 낮춰서 개발 속도 및 유지보 수에 효율적이다. - 객체필드(instance field)는 절대로 public으로 선언하면 안된다. : 변경 가능 public 필드를 가진 클레스는 다중 스레드에 안전하지 않다. 변경 불가능 객체를 참조 하는 final 필드라 해도 public으로 선언하면 클래스 내부 데이터 표현 형태를 유연하게 바꿀 수 없게 된다 - static으로 선언된 필드에도 똑같이 적용되지만 한가지 예외가 있다. 어떤 상수들이 클래스로 추상화된 결과물의 핵심적 부분을 구성한다고 판단되는 경우, 해당 상수들을 public static final 필드들로 선언하여 공개할 수 있다. (public static final 필드가 참조하는 객체는 변경 불가능 객체로 만들어라.) - 길이가 0 아닌 배열은 언제나 변경 가능하므로, public static final 배열 필 드를 두거나, 배열 필드를 반환하는 접근자를 정의하면 안 된다. 그런 멤버 를 두면 클라이언트가 배열 내용을 변경할 수 있게 되므로, 보안에 문제가 생긴다.
  • 40. //보안 문제를 초래할 수 있는 코드 public static final Thing[] VALUES { ... }; 이 문제를 고치는 방법 중 첫 번째는 public으로 선언되었던 배열은 private으 로 바꾸고, 변경이 불가능한 public 리스트를 하나 만드는 것이다. private static final Thing[] PRIVATE_VALUES = { ... }; public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUE)); 두 번째 방법은 배열은 private으로 선언하고, 해당 배열을 복사해서 반환하는 public 메서드를 하나 추가하는 것이다. private static final Thing[] PRIVATE_VALUES = { ... }; public static final Thing[] values(){ return PRIVATE_VALUES.clone(); }
  • 41. "wait(...)" should be used instead of "Thread.sleep(...)" when a lock is held 실행 대기 할 경우 Thread.sleep(…) 대신에 wait(…)를 사용하여라. Thread.sleep()은 대상 Thread가 sleep 상태가 되는 것인데 lock을 획득한 상태로 sleep 합니다 Object에 대해 wait()을 수행하게 되면 해당 Object lock을 소유하고 있다면 lock을 반환하고 wait() 후 깨어나게 됩니다. 즉, wait()하게 되면 lock을 획득한 상태에서 lock를 반환하고 wait()하게됩니다. 그러면 lock 대기중인 다음 Thread가 lock을 획득하게 됩니다. public void doSomething(){ synchronized(monitor) { while(notReady()){ Thread.sleep(200); } process(); } ... } public void doSomething(){ synchronized(monitor) { while(notReady()){ monitor.wait(200); } process(); } ... }
  • 42. Checked Exception should not be thrown Checked Exception 은 발생하지 않아야 한다. 검증된 예외는 컴파일러나 jvm에 의해 말그대로 ‘걸러낸/확인된’ 자동화된 예외처리 방법이고 자바에서는 예외처리하도록 강제하기 위해 예외처리 하지 않으면 에러라 간 주하고 진행되지 않는다. public void myMethod1() throws CheckedException { ... throw new CheckedException(message); // Noncompliant ... throw new IllegalArgumentException(message); // Compliant; IllegalArgumentException is unchecked } public void myMethod2() throws CheckedException { // Compliant; propagation allowed myMethod1(); }
  • 43. Classes should not be compared by name 클래스는 이름으로 비교해서는 안된다. 클래스의 이름은 패키지 내에서 고유하지만 패키지가 다를 경우 고유하지 않습니다. 따 라서 해당 클래스의 이름을 기준으로 비교는 위험 합니다. 악의적인 사용자가 비교 할 클래스의 이름과 같은 객체를 전송하여 액세스 할 경우 위 험할 수 있습니다. package computer; class Pear extends Laptop { ... } package food; class Pear extends Fruit { ... } class Store { public boolean hasSellByDate(Object item) { if ("Pear".equals(item.getClass().getSimpleName())) { // Noncompliant return true; // Results in throwing away week- old computers } } } class Store { public boolean hasSellByDate(Object item) { if (item instanceof food.Pear) { return true; } } }
  • 44. Cookies should be "secure" 쿠키는 secure로 사용해야 한다. setSecure는 쿠키의 보안 설정으로 true로 설정할 경우 HTTPS나 SSL과 같은 secure protocol 에서만 사용 할 수 있다. Cookie c = new Cookie(SECRET, secret); // Noncompliant; cookie is not secure response.addCookie(c); Cookie c = new Cookie(SECRET, secret); c.setSecure(true); response.addCookie(c);
  • 45. Credentials should not be hard-coded 자격증명은 하드코딩하지 말아라 하드코딩 할 경우 컴파일된 응용프로그램에서 문자열을 추출하기 쉽기 때문이다. 자격증명은 암호화된 외부 구성 파일이나 데이터베이스에 저장해야 합니다. Connection conn = null; try { conn = DriverManager.getConnection("jdbc:mysql://localh ost/test?" +"user=steve&password=blue"); // Noncompliant String uname = "steve"; String password = "blue"; conn = DriverManager.getConnection("jdbc:mysql://localh ost/test?" + "user=" + uname + "&password=" + password); // Noncompliant Connection conn = null; try { String uname = getEncryptedUser(); String password = getEncryptedPass(); conn = DriverManager.getConnection("jdbc:mysql://localh ost/test?" + "user=" + uname + "&password=" + password);
  • 46. Exception classes should be immutable Exception classes는 불변해야 합니다. Exception은 에러가 발생하는 어플리케이션의 상태를 표현하는 것을 의미한다. public class MyException extends Exception { private int status; // Noncompliant public MyException(String message) { super(message); } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } } public class MyException extends Exception { private final int status; // Compliant public MyException(String message, int status) { super(message); this.status = status; } public int getStatus() { return status; } }
  • 47. Exception handlers should preserve the original exception Exception handlers 는 원래 Excepion을 보존한다. 발생된 에러를 처리할 때, 발생한 예외를 그대로 호출한 쪽으로 전달되어야 합니다. // Noncompliant - exception is lost try { /* ... */ }catch (Exception e) { LOGGER.info("context"); } // Noncompliant - exception is lost (only message is preserved) try { /* ... */ } catch (Exception e) { LOGGER.info(e.getMessage()); } // Noncompliant - exception is lost try { /* ... */ } catch (Exception e) { throw new RuntimeException("context"); } try { /* ... */ } catch (Exception e) { LOGGER.info(e); } try { /* ... */ } catch (Exception e) { throw new RuntimeException(e); } try { /* ... */ } catch (RuntimeException e) { doSomething(); throw e; } catch (Exception e) { // Conversion into unchecked exception is also allowed throw new RuntimeException(e); }
  • 48. Exception types should not be tested using "instanceof" in catch blocks 예외 유형은 catch 블록 안에서 “instanceof” 를 사용해서 테스트 해서는 안된다. 일반예외로 캐치한 다음에 유형에 따라서 처리하는 대신에 여러 유형에 맞는 catch 블 록에 처리 해야 한다. try { /* ... */ } catch (Exception e) { if(e instanceof IOException) { /* ... */ } // Noncompliant if(e instanceof NullPointerException{ /* ... */ } // Noncompliant } try { /* ... */ } catch (IOException e) { /* ... */ } // Compliant } catch (NullPointerException e) { /* ... */ } // Compliant
  • 49. Exceptions should not be thrown from servlet methods 예외는 servlet methods에 발생되어서는 안된다. public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String ip = request.getRemoteAddr(); InetAddress addr = InetAddress.getByName(ip); // Noncompliant; getByName(String) throws UnknownHostException //... } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try { String ip = request.getRemoteAddr(); InetAddress addr = InetAddress.getByName(ip); //... } catch (UnknownHostException uhex) { //... } }
  • 50. Exceptions should not be thrown in finally blocks 예외 시에 finally 블록에서 thrown 을 하면 안된다 Flnally block은 프로그램의 수행 중 발생할 수 있는 어느 문제에 대해서도 자원의 손상 을 막고 원상복구를 확실히하기 위해 사용된다. 즉, try-catch 구문에서 예외의 발생 여부에 상관없이 실행되어야 할 코드를 넣는 곳이 finlly 구문이다. try { /* some work which end up throwing an exception */ throw new IllegalArgumentException(); } finally { /* clean up */ throw new RuntimeException(); // Noncompliant - will mask the IllegalArgumentException } try { /* some work which end up throwing an exception */ throw new IllegalArgumentException(); } finally { /* clean up */ // Compliant }
  • 51. Generic exceptions should never be thrown 일반적인 예외는 결코 thrown 하면 안된다. public void foo(String bar) throws Throwable { // Noncompliant throw new RuntimeException("My Message"); // Noncompliant } public void foo(String bar) { throw new MyOwnRuntimeException("My Message"); }
  • 52. HTTP referers should not be relied on http referers에 의존해서는 안된다. Referers는 공격자에 의해 수정이 가능하기 때문에 referers 값에 대해서 신뢰하지 말 아라. public class MyServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String referer = request.getHeader("referer"); // Noncompliant if(isTrustedReferer(referer)){ //.. } //... } }
  • 53. IP addresses should not be hardcoded IP주소를 하드코딩 하지 말아라 소스코드에 IP주소를 하드 코딩하는 것에 대한 나쁜 점 • 주소가 변경될 경우 재컴파일 해야 함 • 모든 환경에서 같은 주소가 사용되지 않는다.(개발, 검증, 운영) • 공격자가 코드를 디컴파일하여 주소를 알아낼 수 있다. String ip = "127.0.0.1"; Socket socket = new Socket(ip, 6667); String ip = System.getProperty("myapplication.ip"); Socket socket = new Socket(ip, 6667);
  • 54. Math operands should be cast before assignment 수학 연산자는 사용하기 전에 캐스팅 해야 한다. 연산의 경우 결과는 항상 int일 것이다. float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0 long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928 long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647 long bigNegNum = Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative one. Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if seconds > 2_147_483 ... public long compute(int factor){ return factor * 10_000; //Noncompliant, won't produce the expected result if factor > 214_748 } float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667 long millisInYear = 1_000L*3_600*24*365; // 1000 promoted to long. Yields 31_536_000_000 long bigNum = Integer.MAX_VALUE + 2L; // 2 promoted to long. Yields 2_147_483_649 long bigNegNum = Integer.MIN_VALUE-1L; // Yields -2_147_483_649 Date myDate = new Date(seconds * 1_000L); ... public long compute(int factor){ return factor * 10_000L; }
  • 55. Member variable visibility should be specified 멤버변수의 가시성을 지정해야 한다. class Ball { String color="red"; // Noncompliant } enum A { B; int a; } class Ball { private String color="red"; // Compliant } enum A { B; private int a; }
  • 56. Neither DES (Data Encryption Standard) nor DESede (3DES) should be used DES(데이터 암호화 표준) 도 DESede(3DES) 도 사용하지 않는다. 표준 및 미국 국립 기술 연구소 (NIST)에 따르면, 데이터 암호화 표준 (DES)는 더 이상 안전한 것으로 간주되지 않습니다 Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding"); Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
  • 57. Null pointers should not be dereferenced 널포인터는 역참조해서는 안된다. 일반적으로 그 객체가 NULL이 될 수 없다’라고 하는 가정을 위반했을 때 발생한다. @CheckForNull String getName() {...} public boolean isNameEmpty() { return getName().length() == 0; // Noncompliant; the result of getName() could be null, but isn't null- checked } Connection conn = null; Statement stmt = null; try { conn = DriverManager.getConnection(DB_URL,USER,PASS); stmt = conn.createStatement(); // ... } catch(Exception e) { e.printStackTrace(); } finally { stmt.close(); // Noncompliant; stmt could be null if an exception was thrown in the try{} block conn.close(); // Noncompliant; conn could be null if an exception was thrown }
  • 58. Only standard cryptographic algorithms should be used 단지 표준 알고리즘을 사용해야 한다. 중요한 민감한 데이터를 디스크에 저장하거나 외부 전송 시, SW가 해당 데이터를 암호 화하지 않을 경우 민감한 데이터가 노출될 수 있다. 표준알고리즘 : SHA-256, SHA-384, SHA-512 MyCryptographicAlgorithm extends MessageDigest { ... }
  • 59. Public methods should throw at most one checked exception Public method 에서는 대부분 하나의 exception을 체크하여 throw 한다. public void delete() throws IOException, SQLException { // Noncompliant /* ... */ } public void delete() throws SomeApplicationLevelException { /* ... */ }
  • 60. Resources should be closed 자원은 닫아야 한다. OutputStream stream = null; try{ for (String property : propertyList) { stream = new FileOutputStream("myfile.txt"); // Noncompliant // ... } }catch(Exception e){ // ... }finally{ stream.close(); // Multiple streams were opened. Only the last is closed. } OutputStream stream = null; try{ stream = new FileOutputStream("myfile.txt"); for (String property : propertyList) { // ... } }catch(Exception e){ // ... }finally{ stream.close(); }
  • 61. Throwable and Error should not be caught Throw 가능 객체 와 Error는 catch에 사용할 수 없다. Throw 가능 객체는 자바의 모든 에러와 예외의 슈퍼클래스 입니다. Error는 응용 프로그램에 의해 발생되는 의미하지 않는 모든 에러의 슈퍼클래스 입니다. try { /* ... */ } catch (Throwable t) { /* ... */ } try { /* ... */ } catch (Error e) { /* ... */ } try { /* ... */ } catch (RuntimeException e) { /* ... */ } try { /* ... */ } catch (MyException e) { /* ... */ }
  • 62. Throwable.printStackTrace(...) should not be called Throwable.printStackTrace을 호출할 수 없습니다. Throw 가능 객체를 사용하는 대신에 Loggers를 사용할 수 있습니다. 사용자는 쉽게 logs를 찾을 수 있습니다. try { /* ... */ } catch(Exception e) { e.printStackTrace(); // Noncompliant } try { /* ... */ } catch(Exception e) { LOGGER.log("context", e); // Compliant }
  • 63. Untrusted data should not be stored in sessions 신뢰할 수 없는 데이터는 세션에 저장하지 말아야 한다. 웹 세션에서 데이터는 “신뢰 범위”에서 내부로 간주됩니다. 즉, 신뢰할 수 있는 것 입니다. 그러나 인증되지 않는 사용자로부터 입력된 데이터를 저장하는것은 신뢰의 범위를 벗 어나는 일입니다. 그 데이터를 부적절하게 사용될 수 있습니다. login = request.getParameter("login"); session.setAttribute("login", login); // Noncompliant
  • 64. Useless "if(true) {...}" and "if(false){...}" blocks should be removed 쓸모없는 If(true)와 if(false)는 제거 되야 합니다. if (true) { doSomething(); } ... if (false) { doSomethingElse(); } if (2 < 3 ) { ... } // Noncompliant; always false int i = 0; int j = 0; // ... j = foo(); if (j > 0 && i > 0) { ... } // Noncompliant; always false - i never set after initialization boolean b = true; //... if (b || !b) { ... } // Noncompliant doSomething(); ...
  • 65. Values passed to OS commands should be sanitized OS 명령어로 전달된 값은 제거 되어야 한다. public void listContent(String input) { Runtime rt = Runtime.getRuntime(); rt.exec("ls " + input); // Noncompliant; input could easily contain extra commands ... } public void execute(String command, String argument) { ProcessBuilder pb = new ProcessBuilder(command, argument); // Noncompliant ... }
  • 66. Web applications should not have a "main" method 웹 응용프로그램은 “main” 메소드를 사용하지 말아야 한다. public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if (userIsAuthorized(req)) { updatePrices(req); } } public static void main(String[] args) { // Noncompliant updatePrices(req); } }
  • 67. Web applications should use validation filters 웹 응용프로그램에서 검증 필터를 사용해야 한다. public class ValidatingHttpRequest extends HttpServletRequestWrapper { // ... } public class ValidationFilter implements javax.servlet.Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { chain.doFilter(new ValidatingHttpRequest( (HttpServletRequest)request ), response); } } <filter> <filter-name>ValidationFilter</filter-name> <filter-class>com.myco.servlet.ValidationFilter</filter-class> </filter> <filter-mapping> <filter-name>ValidationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
  • 68. "ConcurrentLinkedQueue.size()" should not be used ConcurrentLinkedQueue.size()는 사용하지 말아라. 큐의 크기를 확인하는 메소드는 일정한 시간이 필요로 하는데, 큐의 크기가 클수록 시 간이 오래 걸릴 수 있다. 그리고 큐가 실행 중 변경이 되는 경우 결과가 정확하지 않을 수 있다. 그런데, size()를 사용해야 할 경우에는 큐가 비어 있는지 확인 하기 위한 isEmpty()를 함께 사용해야 한다. ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); //... log.info("Queue contains " + queue.size() + " elements");
  • 69. "DateUtils.truncate" from Apache Commons Lang library should not be used Apache commons lang library 중에서 “DateUtils.truncate”는 사용할 수 없습니다. 날짜를 truncate 하는 DateUtils.truncate 보다 Java 8에서 도입된 Instant 클래스가 훨씬 빠를 수 있습니다. public Date trunc(Date date) { return DateUtils.truncate(date, Calendar.SECOND); // Noncompliant } public Date trunc(Date date) { Instant instant = date.toInstant(); instant = instant.truncatedTo(ChronoUnit.SECONDS); return Date.from(instant); }
  • 70. "deleteOnExit" should not be used “deleteOnExit”는 사용하지 말아라. File.deleteOnExit()의 사용은 다음과 같은 이유로 권장하지 않습니다. - 삭제는 일반적으로 JVM 종료의 경우에 발생하지만, JVM이 충돌 또는 죽었을 경우에 삭제되지 않는다. - 파일 삭제가 성공했음에도 불구하고 JVM이 종료 할 때까지 파일정보를 보관되면서 메모리가 증가 File file = new File("file.txt"); file.deleteOnExit(); // Noncompliant
  • 71. "entrySet()" should be iterated when both the key and value are needed key와 value가 모두 필요할 때 entrySet() 을 반복해서 사용해야 한다. HashMap에 entrySet 메소드를 호출하면 키가 들어있는 Set이 넘어 옵니다. Set에서 iterator를 뽑아내면 while 문으로 루프를 돌려서 키를 하나씩 가져올 수 있습 니다. public void doSomethingWithMap(Map<String,Object> map) { for (String key : map.keySet()) { // Noncompliant; for each key the value is retrieved Object value = map.get(key); // ... } } public void doSomethingWithMap(Map<String,Object> map) { for (Map.Entry<String,Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); // ... } }
  • 72. "ResultSet.isLast()" should not be used ResultSet.isLast()를 사용하지 말아라. stmt.executeQuery("SELECT name, address FROM PERSON"); ResultSet rs = stmt.getResultSet(); while (! rs.isLast()) { // Noncompliant // process row } ResultSet rs = stmt.executeQuery("SELECT name, address FROM PERSON"); while (! rs.next()) { // process row }
  • 73. "URL.hashCode" and "URL.equals" should be avoided “URL.hashCode” 와 “URL.equals”는 피해야 한다. Equals와 hashCode 메소드는 java.net.URL public void checkUrl(URL url) { Set<URL> sites = new HashSet<URL>(); // Noncompliant URL homepage = new URL("http://sonarsource.com"); // Compliant if (homepage.equals(url)) { // Noncompliant // ... } } public void checkUrl(URL url) { Set<URI> sites = new HashSet<URI>(); // Compliant URI homepage = new URI("http://sonarsource.com"); // Compliant URI uri = url.toURI(); if (homepage.equals(uri)) { // Compliant // ... } }
  • 74. "wait(...)" should be used instead of "Thread.sleep(...)" when a lock is held “Thread.sleep(…)” 대신에 “wait(…)”의 사용은 잠금이 유지 된다. Wait() : 동기화된 다중스레드가 같은 오브젝트에 접근하고자 할 때 중지시킨다. Sleep() : 동기화된 다중스레드를 시간으로 중지시킨다. public void doSomething(){ synchronized(monitor) { while(notReady()){ Thread.sleep(200); } process(); } ... } public void doSomething(){ synchronized(monitor) { while(notReady()){ monitor.wait(200); } process(); } ... }
  • 75. Multiple loops over the same set should be combined 같은 설정의 여러 루프는 결합해서 사용한다. public void doSomethingToAList(List<String> strings) { for (String str : strings) { doStep1(str); } for (String str : strings) { // Noncompliant doStep2(str); } } public void doSomethingToAList(List<String> strings) { for (String str : strings) { doStep1(str); doStep2(str); } }
  • 76. Objects should not be created only to "getClass" Object를 단지 getClass로 생성하지 말아라 getClass의 호출의 목적은 객체를 생성하는 것인데, 객체를 생성하게 되면 메모리 낭비 가 발생하므로 단순히 class를 사용합니다. MyObject myOb = new MyObject(); // Noncompliant Class c = myOb.getClass(); Class c = MyObject.class;
  • 77. Sets with elements that are enum values should be replaced with EnumSet 열거 값이 있는 elements set는 EnumSet 으로 대체해야 합니다. public class MyClass { public enum COLOR { RED, GREEN, BLUE, ORANGE; } public void doSomething() { Set<COLOR> warm = new HashSet<COLOR>(); warm.add(COLORS.RED); warm.add(COLORS.ORANGE); } } public class MyClass { public enum COLOR { RED, GREEN, BLUE, ORANGE; } public void doSomething() { EnumSet<COLOR> warm = EnumSet.of(COLOR.RED, COLOR.ORANGE); } }
  • 78. String function use should be optimized for single characters String function은 하나의 기호에 적합하다. String myStr = "Hello World"; // ... int pos = myStr.indexOf("W"); // Noncompliant // ... int otherPos = myStr.lastIndexOf("r"); // Noncompliant // ... String myStr = "Hello World"; // ... int pos = myStr.indexOf('W'); // ... int otherPos = myStr.lastIndexOf('r'); // ...
  • 79. Strings should not be concatenated using '+' in a loop 문자열은 루프에서 ‘+’을 사용하여 연결되어서는 안된다. 문자열은 불변객체 입니다. 그래서 연결은 단순히 기존의 문자열 끝에 새로운 문자열을 추가 하지 않습니다. 대신 각 루프가 반복되면서 첫번째 문자열이 연결되는 문자열 형 식으로 변환됩니다. 이런식으로 문자열이 길어지면 작업의 성능의 저하가 발생하게 됩 니다. 따라서 StringBuilder의 사용이 바람직합니다. String str = ""; for (int i = 0; i < arrayOfStrings.length ; ++i) { str = str + arrayOfStrings[i]; } StringBuilder bld = new StringBuilder(); for (int i = 0; i < arrayOfStrings.length; ++i) { bld.append(arrayOfStrings[i]); } String str = bld.toString();
  • 80. Synchronized classes Vector, Hashtable, Stack and StringBuffer should not be used 동기화(Synchronized) classes는 Vector, Hashtable, Stack and StringBuffer를 사용 하면 안된다. Vertor의 경우 무조건 동기화이기 때문에 단일 스레드를 사용할 경우에는 성능저하를 가져오게됩니다. - Vector 대신에 ArrayList 또는 LinkedList를 사용 - Stack 대신에 Deque를 사용 - Hashtable 대신에 HashMap 사용 - StringBuffer 대신에 StringBuilder 사용 Vector cats = new Vector(); ArrayList cats = new ArrayList();