Reflection을 사용한 String Destroyer

Posted by epicdev Archive : 2011. 11. 16. 21:09
출처: http://snippets.dzone.com/posts/show/7920


출력 결과
Java World!

Note:
The original string ("Hello World") should be smaller or equal in size when compared to the new string ("Java World!") or else you will end up in ArrayIndexOufofBoundsException.

If the original string is smaller than the new string, then the new string will be truncated. In the above code if i use 'value.set("Hello World", "Java World$Rocks!".toCharArray());' then the output is 'Java World$'

If the original string is larger than the new string then you will end up in ArrayIndexOutOfBoundsException
Stack trace below:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at java.lang.String.getChars(Unknown Source)
at java.io.BufferedWriter.write(Unknown Source)
at java.io.Writer.write(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at com.test.reflection.StringDestroyer.main(StringDestroyer.java:16)

I digged into String.java source code and found that there is a variable int count declared final. Once assigned, the value for count variable cannot be changed. The System.arraycopy(in the above exception) statement uses this count variable for copying the char array to another one. 
  
출력 결과
  

Java에서 현재 스택 상황을 보는 방법

Posted by epicdev Archive : 2011. 11. 16. 20:17
출력 결과
  
읽어보고 article 새로 쓰기: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html

출처: http://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java

Arrays of generic types are not allowed because they're not sound. The problem is due to the interaction of Java arrays, which are not statically sound but are dynamically checked, with generics, which are statically sound and not dynamically checked. Here is how you could exploit the loophole:


출처: http://download.oracle.com/javase/tutorial/java/generics/erasure.html

Type Erasure

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.

For instance, Box<String> is translated to type Box, which is called the raw type — a raw type is a generic class or interface name without any type arguments. This means that you can't find out what type of Object a generic class is using at runtime. The following operations are not possible:

public class MyClass<E> {
    public static void myMethod(Object item) {
        if (item instanceof E) {  //Compiler error
            ...
        }
        E item2 = new E();       //Compiler error
        E[] iArray = new E[10];  //Compiler error
        E obj = (E)new Object(); //Unchecked cast warning
    }
}

The operations shown in bold are meaningless at runtime because the compiler removes all information about the actual type argument (represented by the type parameter E) at compile time.

Type erasure exists so that new code may continue to interface with legacy code. Using a raw type for any other reason is considered bad programming practice and should be avoided whenever possible.

When mixing legacy code with generic code, you may encounter warning messages similar to the following:

Note: WarningDemo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

This can happen when using an older API that operates on raw types, as shown in the following WarningDemo program:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

Recompiling with -Xlint:unchecked reveals the following additional information:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^ 
1 warning 

'Archive' 카테고리의 다른 글

Java에서 현재 스택 상황을 보는 방법  (0) 2011.11.16
Java에서 메소드명(String)으로 메소드 호출하기  (0) 2011.11.16
In Praise Of Small Code  (0) 2011.11.15
Hollywood Principle  (0) 2011.11.15
A Taxonomy for "Bad Code Smells"  (0) 2011.11.15
  

In Praise Of Small Code

Posted by epicdev Archive : 2011. 11. 15. 16:08
출처: http://www.informationweek.com/news/development/architecture-design/231000038

In Praise Of Small Code

Keeping class size small--no more than fits on one screen--goes a long way to reducing complexity in code, which also leads to code that's easier to test.

If you've been doing object-oriented programming for a while, you've surely run into the seemingly endless essays on testability. The debate focuses on how to write code to make it more amenable to automated testing. The topic is particularly intriguing to exponents of test-driven development, who argue that if you write tests first, your code will be inherently testable.

In real life, however, this is not always how it happens. Developers using test-driven development frequently shift to the standard code-before-tests approach when hacking away at a complex problem or one in which testability isn't easily attained. They then write tests after the fact to exercise the code; then modify the code to increase code coverage. There are good reasons why code can be hard to test, even for the most disciplined developers.

What makes code untestable, however, frequently isn't any of these things. Rather, it's excessive complexity. High levels of complexity, generally measured with the suboptimal cyclomatic complexity measure (CCR), is what the agile folks correctly term a "code smell." Intricate code doesn't smell right. It generally contains a higher number of defects and it's hard--sometimes impossible--to maintain. Fortunately, there are many techniques available to the modern programmer to reduce complexity. One could argue that Martin Fowler's masterpiece, Refactoring, is dedicated almost entirely to this topic. (Michael Feathers' Working Effectively With Legacy Code is the equivalent tome for the poor schlemiels who are handed a high-CCR code base and told to fix it.)A simple example is testing private methods; a more complex one is handling singletons. These are issues at the unit testing level. At higher levels, such as user acceptance testing (UAT), a host of tools help provide testability. Those products, however, tend to focus principally on the user interface aspect (and startlingly few handle GUIs on mobile devices). In other areas, such as document creation, there is no software that provides automated UAT-level validation because parsing and recreating the content of a report or output document is often an insuperable task.

My question, though, is how do you avoid creating complexity in the first place? This topic too has been richly mined by agile trainers, who offer the same basic advice: Follow the open-closed principle, obey the Hollywood principle, use the full panoply of design patterns, and so on. All of this is good advice; but ultimately, it doesn't cut it. When you're deep into a problem such as parsing text or writing business logic for a process that calls on many feeder processes, you don't think about Liskov substitution or the open-closed principle. Typically, you write the code that works, and you change it minimally once it passes the essential tests. In other words, as you're writing the code there is little to tell you, "Whoa! You're doing it wrong."

For that, you need another measure, and I've found one that is extraordinarily effective in reducing initial complexity and greatly expanding testability: class size. Small classes are much easier to understand and to test.

If small size is an objective, then the next question is, "How small?" Jeff Bay, in a brilliant essay entitled "Object Calisthenics" (in the book The Thoughtworks Anthology), suggests the number should be in the 50- to 60-line range--essentially, what fits on one screen.

Most developers, endowed as we are with the belief that our craft does not and should not be constrained to hard numerical limits, will scoff at this number of lines--or any number of lines--and will surely conjure up an example that is irreducible to such a small size. Let them enjoy their big classes. But I suspect they are wrong about the irreducibility.

Lately, I've been doing a complete rewrite of some major packages in a project I contribute to. These are packages that were written in part by a contributor whose style I never got the hang of. Now that he's moved on, I want to understand what he wrote and convert it to a development style that looks familiar to me and is more or less consistent with the rest of the project. Since I was dealing with lots of large classes, I decided this would be a good time to hew closely to Bay's guideline. At first, predictably, it felt like a silly straitjacket. But I persevered, and things began to change under my feet. Here is what was different.

Big classes became collections of small classes. I began to group these classes in a natural way at the package level. My packages became a lot "bushier." I also found that I spent more time managing the package tree, but this grouping feels more natural. Previously, packages were broken up at a rough level that dealt with major program components, and they were rarely more than two or three levels deep. Now, their structure is deeper and wider and is a useful road map to the project.

Testability jumped dramatically. By breaking down complex classes into their organic parts and then reducing those parts to the minimum number of lines, each class did one small thing I could test. The top-level class, which replaced its complex forebear, became a sort of main line that simply coordinated the actions of multiple subordinate classes. This top class generally was best tested at the UAT level, rather than with unit tests.

The single-responsibility principle, which states that each class should do only one thing, became the natural result of the new code, rather than a maxim I needed to apply consciously.

And finally, I have enjoyed an advantage foretold by Bay's essay: I can see the entire class in the integrated development environment without having to scroll. Dropping in to look at something is now quick. If I use the IDE to search, the correct hit is easy to locate, because the package structure leads me directly to the right class. In sum, everything is more readable, and on a conceptual level, everything is more manageable.

  

출처: http://tech-read.com/2008/06/19/why-inner-class-can-access-only-final-variable/

Local classes can most definitely reference instance variables. The reason they cannot reference non final local variables is because the local class instance can remain in memory after the method returns. When the method returns the local variables go out of scope, so a copy of them is needed. If the variables weren’t final then the copy of the variable in the method could change, while the copy in the local class didn’t, so they’d be out of synch.

Anonymous inner classes require final variables because of the way they are implemented in Java. An anonymous inner class (AIC) uses local variables by creating a private instance field which holds a copy of the value of the local variable. The inner class isn’t actually using the local variable, but a copy. It should be fairly obvious at this point that a “Bad Thing”™ can happen if either the original value or the copied value changes; there will be some unexpected data synchronization problems. In order to prevent this kind of problem, Java requires you to mark local variables that will be used by the AIC as final (i.e., unchangeable). This guarantees that the inner class’ copies of local variables will always match the actual values.

  

두가지 대표적인 프로그래밍 스타일

Posted by epicdev Archive : 2011. 11. 10. 13:03
어떤 문제를 풀어야 할 때 머릿속으로 완벽한 해답이 나올 때까지 생각만 하다가 해답이 나오면 구현을 시작하는 스타일과
일단 완벽한 해답이 나오지 않더라도 불완전한 해답만 가지고 구현부터 시작한 다음 서서히 고치면서 해답을 만들어가는 스타일이 있는데
이 둘을 적재적소에 잘 사용해야 한다. 
  

가차 없는 테스트

Posted by epicdev Archive : 2011. 10. 6. 21:01
개발자 대부분은 테스트를 싫어한다. 코드가 어디에서 깨지는지 무의식적으로 알고 약한 지점을 피해 다니면서, 살살 테스트하려 한다. 실용주의 프로그래머들은 다르다. 우리는 지금 당장 버그를 찾아 나서도록 내몰리지만, 그 대신 나중에 다른 사람이 자기 버그를 발견하게 되는 수치를 피할 수 있는 것이다.

버그 찾기는 그물낚시와 비슷하다. 잔챙이를 잡기 위해 촘촘한 그물(단위 테스트)을 쓰기도 하고, 식인상어를 잡기 위해 크고 성긴 그물(통합 테스트)을 쓰기도 한다. 때때로 고기가 용케 도망가기도 한다. 그렇게 되면 프로젝트 웅덩이에서 헤엄쳐 다니는 미끌미끌한 결함들을 많이많이 잡기 위해 구멍 난 데를 있는 대로 찾아다니며 막아야 하는 것이다.

<실용주의 프로그래머 팁>
일찍 테스트하고, 자주 테스트하라. 자동으로 테스트하라.

코드를 작성하자마자 테스트해야 한다. 그 작은 잔챙이들은 꽤나 빨리 자라나 사람을 잡아먹는 거대한 상어가 되는 고약한 성질이 있다. 상어를 잡는 일은 상당히 힘들다. 하지만 그렇다고 그 모든 테스트를 손으로 할 수는 없다.

프로젝트 테스트 계획을 상세하게 짜는 팀도 많다. 심지어 그걸 쓰는 팀도 간혹 있다. 하지만 우리가 보기에 자동화 된 테스트를 사용하는 팀이 성공의 기회가 훨씬 많다. 빌드 할 때마다 하는 테스트는 책장에 꽂아 놓은 테스트 계획보다 훨씬 효과적이다.

버그가 빨리 발견 될수록 고치는 비용이 적어진다. '코드 조금, 테스트 조금'은 스몰토크 세계에서는 유명한 격언이다. 우리는 제품 코드를 만드는 것과 동시에(혹은 이전에) 테스트 코드를 만듦으로써 그 주문을 우리 것으로 할 수 있다.

사실, 훌륭한 프로젝트에는 제품 코드보다도 테스트 코드가 더 많을지 모른다. 테스트 코드를 만들기 위해 소요되는 시간에는 그 노력만큼의 가치가 있다. 길게 보면 이쪽이 훨씬 더 싸게 들며, 결함이 영어 가까운 제품을 만드는 꿈이 정말 이루어지기도 한다.

이 외에도 테스트를 통과했다는 것은 그 코드가 '완료되었다'고 말할 수 있는 높은 수준의 확신을 갖게 하는 것이다.

<실용주의 프로그래머 팁>
모든 테스트가 통과하기 전엔 코딩이 다 된 게 아니다.

우리는 프로젝트 범위에서 이루어지는 테스트의 세 가지 주요 면모를 살펴 보아야 한다. 무엇을 테스트 할지, 어떻게 테스트 할지, 그리고 언제 테스트할지.


무엇을 테스트할지
 

수행해야 할 소프트웨어 테스트에는 대여섯 가지 주요 유형이 있다.

  • 단위 테스트
  • 통합 테스트
  • 유효성 평가와 검증
  • 자원 고갈, 에러, 그리고 복구
  • 성능 테스트
  • 사용 편의성 테스트

어떻게 테스트할지

  • 회귀 테스트
  • 테스트 데이터
  • GUI 시스템 구동
  • 테스트를 테스트하기
  • 철저히 테스트하기

테스트 데이터
 

여기에는 오직 두 종류의 데이터가 있다. 실세계 데이터와 합성 데이터다. 실제로는 이 둘을 모두 사용해야 하는데, 두 데이터가 갖는 다른 특징들이 소프트웨어에서 다른 종류의 버그를 노출시켜 주기 때문이다.

실세계 데이터는 현실에서 온다. 기존 시스템, 경쟁사의 시스템 혹은 어떤 종류의 프로토타입 등에서 자료를 수집한다. 이는 전형적인 사용자 자료이다.
합성 데이터는 어떤 통계적 조건하에서 인공적으로 생성된다.


테스트를 테스트하기
 

완벽한 소프트웨어를 작성 할 수 없기 때문에, 완벽한 소프트웨어 역시 작성 할 수 없다. 그렇다면 테스트를 테스트할 필요가 있다.
어떤 버그를 감지해 내는 테스트를 작성한 후에, 그 버그가 의도적으로 생기도록 한 다음 테스트가 불평을 해대는지 확인하라. 이렇게 하면 실제로 버그가 생겼을 때 테스트가 그걸 잡아 낼 것이라고 확신 할 수 있다.

<실용주의 프로그래머 팁>
파괴자를 써서 테스트를 테스트하라.

정말 테스트에 대해 심각하게 생각한다면, 프로젝트 파괴자를 임명 할 수 있다. 파괴자의 역할은 소스 트리의 카피를 별도로 만들어 취한 다음, 고의로 버그를 심고 테스트가 잡아 낼지 검증하는 것이다.


철저한 테스트
 

테스트가 올바르다는 확신이 들고,  여러분이 만든 버그도 찾아낸다면, 코드베이스를 충분히 철저하게 테스트했다는 것을 어떻게 알 수 있을까?
 
한마디로 답하자면 '알 수 없다'. 그리고 앞으로도 알 수 없을 것이다. 하지만 시장에는 여기에 도움되는 상품들이 있다. 커버리지 분석 도구는 테스트 중에 코드를 지켜보고, 코드의 어느 라인이 실행되지 않았는지 기억한다. 이런 도구들 덕에 여러분의 테스트가 얼마나 포괄적인지에 대한 대체적인 느낌을 가질 수 있다. 하지만 100% 커버리지를 기대하지는 마라.

우연히 코드의 모든 라인이 실행 될지라도, 그게 전부가 아니다. 정말로 중요한 것은 프로그램이 갖는 상태의 개수다. 상태는 코드 라인들과 동등하지 않다.
예컨데, 0에서 999사이의 정수 두 개를 받는 함수를 가정 해 보자.

int test(int a, int b) {
    return a / (a + b)
}

이 세 줄짜리 함수는 이론상으로 1,000,000가지의 논리적 상태를 갖는다. 그 가운데 999,999개는 제대로 작동 할 것이고, 하나는 그렇지 못할 것이다(a, b가 모두 0일 때). 코드의 이 줄을 실행했다는 것을 아는 것만으로는 이런 사실이 드러나지 않는다. 프로그램의 모든 가능한 상태를 분별해야 할 것이다. 불행히도, 일반적으로 이것은 정말로 어려운 문제다.

<실용주의 프로그래머 팁>
코드 커버리지보다 상태 커버리지를 테스트하라.

심지어 훌륭한 코드 커버리지가 있어도 테스트를 위해 사용하는 데이터는 여전히 상당한 영향을 미칠 뿐 아니라, 이보다 더 중요하게 여러분이 코드를 실행하는 순서가 가장 큰 영향을 미칠 수 있다.


언제 테스트할까

많은 프로젝트에서 사람들은 테스트를 마지막 일 분까지 미룬다. 데드라인의 날카로운 모서리에 닿는 순간까지. 그것보다는 훨씬 일찍 시작해야 한다. 실제 제품에 들어갈 코드는 나오자마자 테스트해야 한다.

테스트는 대부분 자동화 되어야 한다. 여기에서 중요한 것은, 우리의 '자동화'는 테스트 결과 해석의 자동화를 포함한다는 점이다.


그물 조이기

마지막으로 테스트에서 가장 중요한 개념을 밝히고자 한다. 뻔한 것이고, 거의 모든 교과서에서 이렇게 하라고 말하고 있다. 하지만 무슨 이유에서인지 대다수 프로젝트에서 지켜지지 않는다.

현존하는 테스트의 그물을 빠져 나가는 버그가 있으면, 다음번에는 그걸 잡아 낼 수 있도록 새 테스트를 추가해야 한다.

<실용주의 프로그래머 팁>
버그는 한 번만 잡아라.

 인간 테스터가 버그를 찾아내면, 그 때가 인간 테스터가 그 버그를 찾는 마지막 순간이 되어야 한다. 그 순간 이후부터는 무조건, 매번, 예외 없이, 아무리 사소한 것일지라도, 개발자가 "그건 앞으로 절대 다시 일어나지 않을 겁니다."라고 불평을 하더라도 해당 버그를 확인 할 수 있게 자동화 테스트들을 수정해야 한다.

왜냐면 그런 일은 앞으로 다시 일어날 것이기 떄문이다. 게다가 우린 자동화 테스트가 우리를 대신해 찾아 줄 버그까지 추격할 시간이 없다. 우리는 새 코드를(그리고 새 버그도) 작성하는 데 시간을 보내야 한다.


실용주의프로그래머
카테고리 컴퓨터/IT > 프로그래밍/언어
지은이 앤드류 헌트 (인사이트, 2007년)
상세보기
 
  

다익스트라의 테스팅 관련 명언

Posted by epicdev Archive : 2011. 10. 6. 19:34
다익스트라는 "테스팅은 버그의 존재만 보여 줄 수 있지 버그의 부재까지는 보여 줄 수 없다"는 명언을 했다.
그렇다면 그가 생각하는 버그를 없게 만드는 방법은? 수학적 증명과 단순화.

토니 호아의 다음 명언이 힌트가 될 것 같다. "소프트웨어 설계를 구축하는 두 가지 방법이 있다. 하나는 아주 단순하게 만들어서 명백히 결함이 없도록 하는 것이고, 다른 하나는 아주 복잡하게 만들어서 명백한 결함이 없도록 하는 것이다."

 

실용주의프로그래머
카테고리 컴퓨터/IT > 프로그래밍/언어
지은이 앤드류 헌트 (인사이트, 2007년)
상세보기


'Archive' 카테고리의 다른 글

Exception에 관하여  (0) 2011.10.08
가차 없는 테스트  (0) 2011.10.06
소프트웨어를 테스트하라  (0) 2011.10.05
테스트하기 쉬운 코드  (0) 2011.10.05
/etc/passwd 파일의 포맷  (0) 2011.10.04
  

소프트웨어를 테스트하라

Posted by epicdev Archive : 2011. 10. 5. 10:52
<실용주의 프로그래머 팁>
소프트웨어를 테스트하라. 그렇지 않으면 사용자가 테스트하게 될 것이다.


실용주의프로그래머
카테고리 컴퓨터/IT > 프로그래밍/언어
지은이 앤드류 헌트 (인사이트, 2007년)
상세보기
 

'Archive' 카테고리의 다른 글

가차 없는 테스트  (0) 2011.10.06
다익스트라의 테스팅 관련 명언  (0) 2011.10.06
테스트하기 쉬운 코드  (0) 2011.10.05
/etc/passwd 파일의 포맷  (0) 2011.10.04
Stop Over-Engineering  (0) 2011.10.04
  
 «이전 1 2 3 4 5 6  다음»