Spring과 SpringBoot

Spring

정의

* 자바(JAVA) 플랫폼을 위한 오픈소스(Open Source) 애플리케이션 프레임워크(Framework)
* 자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 경량급 애플리케이션 프레임워크
* 자바 개발을 위한 프레임워크로 종속 객체를 생성해주고, 조립해주는 도구
* POJO(Plain Old Java Object) BEAN CONTAINNER

특징

* 경량 컨테이너로 자바 객체를 직접 관리하기때문에 각각의 객체 생성, 소멸과 같은 라이프 사이클을 관리하며 스프링으로부터 필요한 객체를 얻어올 수 있다.
* 스프링은 POJO(Plain Old Java Object) 방식의 프레임워크로 일반적인 J2EE 프레임워크에 비해 구현을 위해 특정한 인터페이스를 구현하거나 상속을 받을 필요가 없어 기존에 존재하는 라이브러리 등을 지원하기에 용이하고 객체가 가볍다.
* 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드를 호출한다.
* 스프링은 의존성 주입(DI : Dependency Injection)을 지원하여 각각의 계층이나 서비스들 간에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.
* 관점 지향 프로그래밍(AOP : Aspect-Oriented Programming)을 지원한다.
따라서 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리할 수 있다.
* 이미 완성도가 높은 데이터베이스 처리 라이브러리와 연결할 수 있는 인터페이스를 제공하는 등 영속성과 관련된 다양한 서비스를 지원한다.
* 확장성이 높다. 수많은 라이브러리가 이미 스프링에서 지원되고 있고 스프링에서 사용되는 라이브러리를 별도로 분리하기도 용이하다.

++ Plain Object Java Object : 기본적으로 사용자가 만들어낸 객체를 의미한다. 스프링은 사용자가 만들 객체들에 대해서도 라이프사이클 관리를 위임해서 수행하며, 이들의 조합으로 어플리케이션을 만들 수 있다.
++ AOP : 관점지향형 프로그램으로 사용자들이 트랜젝션 처리/로깅/예외 처리들의 로직을 공통으로 처리할 수 있는 기능을 지원하며 해당 기능을 잘 사용하면 비지니스로직와 기타 공통모듈이 섞이는 것을 방지하여 비지니스 로직에 집중할 수 있도록 한다.
++ DI : IoC 구현을 통해 의존관계 해결을 위한 디자인 패턴으로 xml 설정이나 애노테이션을 통해 의존성 주입을 쉽게 할 수 있는 방법을 제공한다.
++ IoC : 컴퓨터 프로그램의 사용자 지정 부분(프로그래머가 작성한 소스코드)이 프레임워크의 흐름제어를 받는 디자인 패턴이다.

Spring Boot

정의

어플리케이션을 개발하는데 있어서 필요한 라이브러리 의존성들을 안전성이 확인된 버전으로 조합하여 미리 준비된 구성으로 제공하며 MVC 환경을 만들거나 여기에 필요한 데이터베이스, 뷰 템플릿 등을 구성하는데 있어서 자동구성을 지원한다.
기본적으로 요구되는 요구사항들을 처리하기 위해 프로퍼티를 통한 설정값을 제어할 수 있도록 하고, 스프링부트를 시작하기 위해 XML 기반 설정파일이나 코드를 요구하지도 않는다.
내장된 웹서버를 이용해 별도의 웹서버 환경없이 즉시 단독으로 애플리케이션을 실행할 수도 있다. 이에 개발자들이 어플리케이션 로직 개발을 쉽게! 그리고 바로! 시작할 수 있다.

특징

* 어플리케이션의 기능적 요소 뿐만 아니라 임베디드 서버, 시큐리티, 외부 설정 연계등 개발의 모든 사이클을 제공한다.
* 로직에 집중 할 수 있도록 설정을 없앴다.

– 참고 :
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

Spring과 Springboot 차이

기존 spring framework가 기본적으로 해야할 셋팅이 너무 많고 어려웠던 점을 해소하기 위해 나온 것이 spring boot!

sonarcube

sonarcube는
지속적으로 코드의 품질을 높이고 유지 보수하는데 도움을 주는 정적 분석 애플리케이션으로 분석 기능이 탁월하고 개선 사항도 자세하게 안내해 준다.
간단하게는 코딩 컨벤션부터 코드의 잠재적인 위험 사항까지 안내해주어 올바른 코딩 습관과 코드의 품질향상에 많은 도움을 준다.

다운로드 및 설치
https://www.sonarqube.org/downloads/ 에서 다운로드 받고 압축을 해제.

issue 1. 

Either log or rethrow this exception (5)
 – cause : When handling a caught exception, the original exception’s message and stack trace should be logged or passed forward.
noncompliant code example
// 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");
}
compliant code example
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);
}

issue 2. 

Define and throw a dedicated exception instead of using a generic one (7)
 – cause : Using such generic exceptions as ErrorRuntimeExceptionThrowable, and Exception prevents calling methods from handling true, system-generated exceptions differently than application-generated errors.
noncompliant code example
public void foo(String bar) throws Throwable {  // Noncompliant 
throw new RuntimeException("My Message"); // Noncompliant
}
compliant code example
public void foo(String bar) { 
throw new MyOwnRuntimeException("My Message");
}

issue 3. 

Use isEmpty() to check whether the collection is empty or not. (1)
 – cause : Using Collection.size() to test for emptiness works, but using Collection.isEmpty() makes the code more readable and can be more performant. The time complexity of any isEmpty() method implementation should be O(1) whereas some implementations of size() can be O(n).
noncompliant code example
if (myCollection.size() == 0) {  // Noncompliant 
/* ... */
}
compliant code example
if (myCollection.isEmpty()) { 
/* ... */
}

issue 4.

Move the “update” string literal on the left side of this string comparison.
noncompliant code example
String myString = null;

System.out.println("Equal? " + myString.equals("foo"));
// Noncompliant; will raise a NPE

System.out.println("Equal? " + (myString != null && myString.equals("foo")));
// Noncompliant; null check could be removed
compliant code example
System.out.println("Equal?" + "foo".equals(myString)); 
// properly deals with the null case

issue 5.

Merge this if statement with the enclosing one. (4)
 – cause : Merging collapsible if statements increases the code’s readability.
noncompliant code example
if (file != null) { 
if (file.isFile() || file.isDirectory()) {
/* ... */
}
}
compliant code example
if (file != null && isFileOrDirectory(file)) { 
/* ... */
}
private static boolean isFileOrDirectory(File file) {
return file.isFile() || file.isDirectory();
}

issue 6.

Remove this unused “변수명”  (33)
 – cause : If a private field is declared but not used in the program, it can be considered dead code and should therefore be removed. This will improve maintainability because developers will not wonder what the variable is used for. (주로 도메인 객체)
noncompliant code example
public class MyClass {
private int foo = 42;

public int compute(int a) {
return a * 42;
}
}
compliant code example
public class MyClass {
public int compute(int a) {
return a * 42;
}
}

issue 7. 

The Cyclomatic Complexity of this method 메소드명. (9)
 – cause : The cyclomatic complexity of methods should not exceed a defined threshold. 
                  Complex code can perform poorly and will in any case be difficult to understand and therefore to maintain.
noncompliant code example
-
compliant code example
-

issue 8.

duplicated blocks of code must be removed. (3)
 – cause : An issue is created on a file as soon as there is at least one block of duplicated code on this file.
noncompliant code example
-
compliant code example
-

issue 9.

The type of the “input” object should be an interface such as “Map” rather than the implementation “HashMap”. (2)
 – cause : The purpose of the Java Collections API is to provide a well defined hierarchy of interfaces in order to hide implementation details.
  Implementing classes must be used to instantiate new collections, but the result of an instantiation should ideally be stored in a variable whose type is a Java Collection interface.
  This rule raises an issue when an implementation class:
  • is returned from a public method.
  • is accepted as an argument to a public method.
  • is exposed as a public member.
noncompliant code example
public class Employees { 
private HashSet<Employee> employees = new HashSet<Employee>();
// Noncompliant - "employees" should have type "Set" rather than "HashSet"

public HashSet<Employee> getEmployees() { // Noncompliant
return employees;
}
}
compliant code example
public class Employees {  
private Set employees = new HashSet(); // Compliant
public Set getEmployees() { // Compliant
return employees;
}
}

issue 10.

Reduce the number of conditional operators {:num} used in the expression (maximum allowed :num). (3)
 – cause : The complexity of an expression is defined by the number of &&|| and condition ? ifTrue : ifFalse operators it contains. 
                   A single expression’s complexity should not become too high to keep the code readable.
noncompliant code example
With the default threshold value of 3: 
if (((condition1 && condition2) || (condition3 && condition4)) && condition5) {
...
}
compliant code example
if ( (myFirstCondition() || mySecondCondition()) && myLastCondition()) {
...
}

issue 11.

Method has {:num} parameters, which is greater than {:num} authorized. (3)
 – cause : A long parameter list can indicate that a new structure should be created to wrap the numerous parameters or that the function is doing too many things.
noncompliant code example
With a maximum number of 4 parameters:
public void doSomething(int param1, int param2, int param3, String param4, long param5) {
...
}
compliant code example
public void doSomething(int param1, int param2, int param3, String param4) {
...
}

issue 12.

Refactor this code to not nest more than 3 if/for/while/switch/try statements. (3)
 – cause : Nested ifforwhileswitch, and try statements is a key ingredient for making what’s known as “Spaghetti code”. Such code is hard to read, refactor and therefore maintain.
noncompliant code example
With the default threshold of 3: 
if (condition1) { // Compliant - depth = 1
/* ... */
if (condition2) { // Compliant - depth = 2
/* ... */
for(int i = 0; i < 10; i++) { // Compliant - depth = 3, not exceeding the limit
/* ... */
if (condition4) { // Noncompliant - depth = 4
if (condition5) { // Depth = 5, exceeding the limit, but issues are only reported on depth = 4
/* ... */
}
return;
}
}
}
}
compliant code example
-

issue 13.

Complete the task associated to this TODO comment.  (2)
 – cause : TODO tags are commonly used to mark places where some more code is required, but which the developer wants to implement later.
Sometimes the developer will not have the time or will simply forget to get back to that tag. 
This rule is meant to track those tags, and ensure that they do not go unnoticed.
noncompliant code example
void doSomething() {   // TODO }
compliant code example
-

issue 14. issue 15. issue 16. issue 17.

Document this public class.  (17)
Document the parameter(s): page. (16)
Document this public interface. (5)
Document this public method. (70)
Document this public enum. (5)
Document this public constructor. (5) 
– cause : Try to imagine using the standard Java API (Collections, JDBC, IO, …) without Javadoc. It would be a nightmare, because Javadoc is the only way to understand of the contract of the API. Documenting an API with Javadoc increases the productivity of the developers consuming it.
The following Javadoc elements are required:
  • Parameters, using @param parameterName.
  • Method return values, using @return.
  • Generic types, using @param <T>.
The following public methods and constructors are not taken into account by this rule:
  • Getters and setters.
  • Methods with @Override annotation.
  • Empty constructors.
  • Static constants.
noncompliant code example
/**
* This is a Javadoc comment
*/
public class MyClass implements Runnable { // Noncompliant - missing '@param '
public static final DEFAULT_STATUS = 0; // Compliant - static constant
private int status; // Compliant - not public
public String message; // Noncompliant
public MyClass() { // Noncompliant - missing documentation
this.status = DEFAULT_STATUS;
}

public void setStatus(int status) { // Compliant - setter
this.status = status;
}

@Override
public void run() { // Compliant - has @Override annotation }
protected void doSomething() { // Compliant - not public }
public void doSomething2(int value) { // Noncompliant }
public int doSomething3(int value) { // Noncompliant
return value;
}
}
compliant code example
/** 
* This is a Javadoc comment
* @param ...
*/
public class MyClass implements Runnable {
public static final DEFAULT_STATUS = 0;
private int status;
/**
* This is a Javadoc comment
*/
public String message;

/**
* Class comment...
*/
public MyClass() {
this.status = DEFAULT_STATUS;
}
public void setStatus(int status) {
this.status = status;
}

@Override
public void run() { }
protected void doSomething() { }
/**
* @param value ...
*/
public void doSomething(int value) {
/**
* {@inheritDoc}
*/
public int doSomething(int value) {
return value;
}
}

issue 18.

Immediately return this expression instead of assigning it to the temporary variable (5)
– cause : Declaring a variable only to immediately return or throw it is a bad practice.
Some developers argue that the practice improves code readability, because it enables them to explicitly name what is being returned. However, this variable is an internal implementation detail that is not exposed to the callers of the method. The method name should be sufficient for callers to know exactly what will be returned.
noncompliant code example
public long computeDurationInMilliseconds() {
long duration = (((hours * 60) + minutes) * 60 + seconds ) * 1000;
return duration;
}

public void doSomething() {
RuntimeException myException = new RuntimeException();
throw myException;
}
compliant code example
public long computeDurationInMilliseconds() {
return (((hours * 60) + minutes) * 60 + seconds ) * 1000 ;
}

public void doSomething() {
throw new RuntimeException();
}

issue 19.

Define a constant instead of duplicating this literal “{:variable name}” {:num} times. (9)
– cause : Duplicated string literals make the process of refactoring error-prone, since you must be sure to update all occurrences.
On the other hand, constants can be referenced from many places, but only need to be updated in a single place.
noncompliant code example
public void run() { 
prepare("action1"); // Noncompliant - "action1" is duplicated 3 times
execute("action1");
release("action1");
}
@SuppressWarning("all") // Compliant - annotations are excluded
private void method1() {
/* ... */
}

@SuppressWarning("all")
private void method2() {
/* ... */
}

public String method3(String a) {
System.out.println("'" + a + "'"); // Compliant - literal "'" has less than 5 characters and is excluded
return ""; // Compliant - literal "" has less than 5 characters and is excluded
}
compliant code example
private static final String ACTION_1 = "action1";  // Compliant 
public void run() {
prepare(ACTION_1); // Compliant
execute(ACTION_1);
release(ACTION_1);
}

issue 20.

At most one statement is allowed per line, but {:num} statements were found on this line. (3)
– cause : For better readability, do not put more than one statement on a single line.
noncompliant code example
if(someCondition) doSomething();
compliant code example
if(someCondition) {   doSomething(); }

issue 21.

Reorder the modifiers to comply with the Java Language Specification.  (22)
– cause : The Java Language Specification recommends listing modifiers in the following order:

1. Annotations
2. public
3. protected
4. private
5. abstract
6. static
7. final
8. transient
9. volatile
10. synchronized
11. native
12. strictfp
Not following this convention has no technical impact, but will reduce the code’s readability because most developers are used to the standard order.

noncompliant code example
static public void main(String[] args) {   // Noncompliant }
compliant code example
public static void main(String[] args) {   // Compliant }

유지보수 가능한 코딩의 기술: 자바편

소프트웨어 유지 보수의 4대 유형

- 버그를 발견하고 고친다(교정형 유지보수, corrective maintenance)
- 운영 환경의 변화에 따라 시스템을 변경한다(적응형 유지보수, adaptive maintenance)
- 시스템 사용자의 요구를 반영한다(완료형 유지보수, perfective maintenance)
- 품질을 높이고, 버를 방지할 방안을 모색한다(예방형 유지보수, preventive maintenance)

유지보수성 가이드라인


코드 단위를 짧게 하라
목표 : 코드 단위는 15라인을 어가지 않게 작성한다.
  • 메서드 추출(Extract Method)
  • 메서드를 메서드 객체로 대체(Replace Method with Method Object) : 길어지는 코드를 객체로 분리
코드 단위는 간단하게 짜라
목표 : 단위당 분기점은 4개로 제한한다
  • Map 을 이용해 분기문 사용을 줄일 수 있다
  • 케이스별로 구분해서 각각 return 문을 넣으면 중첩 조건문 제거에 도움이 된다. (중첩문 보호철로 대체, Replace Nested Conditional with Guard Clauses)
  • 중첩 조건문을 별도 메서드로 추출하면 덜 복잡한 코드가 된다.
코드는 한 번만 작성하라
목표 : 코드를 복사하지 않는다.
  • 코드를 재사용 가능한 일반적인 형태로 작성하거나 기존 메서드를 대신 호출한다.
  • 상위 클래스 추출(Extract Superclass) 를 이용해 원 클래스의 상위 클래스로 생성하여 추출
단위 인터페이스를 작게 하라
목표 : 단위당 파라미터 개수는 4개 이하로 제한한다.
  • 파라미터를 객체로 추출한다
  • 세터가 전원 this를 반환하게 하여 흘러가는 인터페이스(fluent interface)를 만들 수도 있다
관심사를 모듈로 분리하라
목표 : 모듈 간결합을 느슨하게 하기 위해 큰 모듈은 삼가한다.
  • 개별 모듈로 나누어 일을 시키고 구현 상세는 인터페이스 안으로 감춘다.
  • 클래스를 나누어 관심사를 분리한다
  • 특정 구현부는 인터페이스 안에 숨긴다
  • 커스텀 코드를 서드파티 라이브러리/프레임워크로 대체한다
아키텍처 컴포넌트를 느슨하게 결합하라
목표 : 최상위 수준의 컴포넌트 간 결합도를 낮춘다
  • 다른 컴포넌트 모듈에 호출을 받는 형태로 공개도니 모듈 내부의 상대적인 코드량을 최소화 한다.
  • 모듈의 크기를 제한한다
  • 상위수준에서 컴포넌트 인터페이스를 추상화 한다(컴포넌트 경계를 넘나드는 요청 가짓수를 제한)
  • 스루풋 코드는 쓰지 않는다
아키텍처 컴포넌트의 균형을 잡아라
목표 : 최상위 수준 컴포넌트 개수와 상대적인 크기를 균형잡느다
  • 컴포넌트 개수가 9개(6~12개) 정도 되도록 소스 코드를 조직화 하고 컴포넌트 크기를 대략 균등하게 맞춘다
코드베이스를 작게 하라
목표 : 코드베이스를 가능한 작게 한다
  • 코드베이스가 커지는 걸 막고 시스템 크기를 적극적으로 줄인다
  • 코드를 복사하지 않는다
  • 기존 코드를 리팩터링 한다
  • 서드파티 라이브러리/프레임워크를 사용한다
  • 대규모 시스템을 분리한다
테스트를 자동화하라
목표 : 테스트를 자동화 한다
  • 테스트 프레임워크로 자동화한 테스트를 작성한다
클린 코드를 작성하라
목표 : 클린 코드를 작성한다
  • 규칙 1: 단위 수준의 코드 악취를 남기지 말라(커밋하기 전에 리팩터링을 마쳐야 한다)
  • 규칙 2: 나쁜 주석을 남기지 말라
  • 규칙 3: 주석 안에 코드를 남기지 말라
  • 규칙 4: 죽은 코드를 남기지 말라
  • 규칙 5: 긴 식별자 이름을 남기지 말라
  • 규칙 6: 매직 상수를 남기지 말라(매직상수, magic constant : 의미가 불분명한 숫자나 리터럴 값, 상수값은 명시적으로 정의해서 사용하는 것이 좋다.)
  • 규칙 7: 제대로 처리 안 한 예외를 남기지 말라