소프트웨어를 테스트하라

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
  

테스트하기 쉬운 코드

Posted by epicdev Archive : 2011. 10. 5. 09:45
테스트 가능성이 높은 코드는 디자인에 좋다. 재미있게도, 디자인을 잘 만들려고 할 때보다 테스트 가능성을 높이려고 했을 때 결과 코드의 디자인이 더 나은 경우가 많다.


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

'Archive' 카테고리의 다른 글

다익스트라의 테스팅 관련 명언  (0) 2011.10.06
소프트웨어를 테스트하라  (0) 2011.10.05
/etc/passwd 파일의 포맷  (0) 2011.10.04
Stop Over-Engineering  (0) 2011.10.04
디자인 패턴 공부 순서  (0) 2011.10.04
  

/etc/passwd 파일의 포맷

Posted by epicdev Archive : 2011. 10. 4. 21:50
출처: http://www.cyberciti.biz/faq/understanding-etcpasswd-file-format/

Can you explain /etc/passwd file format for Linux and UNIX operating systems?

/etc/passwd file stores essential information, which is required during login i.e. user account information. /etc/passwd is a text file, that contains a list of the system's accounts, giving for each account some useful information like user ID, group ID, home directory, shell, etc. It should have general read permission as many utilities, like ls use it to map user IDs to user names, but write access only for the superuser (root).

Understanding fields in /etc/passwd

The /etc/passwd contains one entry per line for each user (or user account) of the system. All fields are separated by a colon (:) symbol. Total seven fields as follows.

Generally, passwd file entry looks as follows (click to enlarge image):


(Fig.01: /etc/passwd file format - click to enlarge)

  1. Username: It is used when user logs in. It should be between 1 and 32 characters in length.
  2. Password: An x character indicates that encrypted password is stored in /etc/shadow file.
  3. User ID (UID): Each user must be assigned a user ID (UID). UID 0 (zero) is reserved for root and UIDs 1-99 are reserved for other predefined accounts. Further UID 100-999 are reserved by system for administrative and system accounts/groups.
  4. Group ID (GID): The primary group ID (stored in /etc/group file)
  5. User ID Info: The comment field. It allow you to add extra information about the users such as user's full name, phone number etc. This field use by finger command.
  6. Home directory: The absolute path to the directory the user will be in when they log in. If this directory does not exists then users directory becomes /
  7. Command/shell: The absolute path of a command or shell (/bin/bash). Typically, this is a shell. Please note that it does not have to be a shell.

Task: See User List

/etc/passwd is only used for local users only. To see list of all users, enter:
$ cat /etc/passwd
To search for a username called tom, enter:
$ grep tom /etc/passwd

/etc/passwd file permission

The permission on the /etc/passwd file should be read only to users (-rw-r--r--) and the owner must be root:
$ ls -l /etc/passwd
Output:

-rw-r--r-- 1 root root 2659 Sep 17 01:46 /etc/passwd

Reading /etc/passwd file

You can read /etc/passwd file using the while loop and IFS separator as follows:

#!/bin/bash
# seven fields from /etc/passwd stored in $f1,f2...,$f7
#
while IFS=: read -r f1 f2 f3 f4 f5 f6 f7
do
 echo "User $f1 use $f7 shell and stores files in $f6 directory."
done < /etc/passwd
 

Your password is stored in /etc/shadow file

Your encrpted password is not stored in /etc/passwd file. It is stored in /etc/shadow file. In the good old days there was no great problem with this general read permission. Everybody could read the encrypted passwords, but the hardware was too slow to crack a well-chosen password, and moreover, the basic assumption used to be that of a friendly user-community.

Almost, all modern Linux / UNIX line operating systems use some sort of the shadow password suite, where /etc/passwd has asterisks (*) instead of encrypted passwords, and the encrypted passwords are in /etc/shadow which is readable by the superuser only. 

'Archive' 카테고리의 다른 글

소프트웨어를 테스트하라  (0) 2011.10.05
테스트하기 쉬운 코드  (0) 2011.10.05
Stop Over-Engineering  (0) 2011.10.04
디자인 패턴 공부 순서  (0) 2011.10.04
프로그래머를 위한 공부론 - 김창준  (0) 2011.10.04
  

Stop Over-Engineering

Posted by epicdev Archive : 2011. 10. 4. 20:54
출처: http://www.industriallogic.com/papers/StopOverEngineering.pdf

Patterns are a cornerstone of object-oriented design, while test-first programming and merciless refactoring are cornerstones of evolutionary design. To stop over- or underengineering, balance these practices and evolve only what you need.
By Joshua Kerievsky
 
The great thing about software patterns is that they convey many useful design ideas. It follows, therefore, that if you learn a bunch of these patterns, you'll be a pretty good software designer, right? I considered myself just that once I'd learned and used dozens of patterns. They helped me develop flexible frameworks and build robust and extensible software systems. After a couple of years, however, I discovered that my knowledge of patterns and the way I used them frequently led me to over-engineer my work.
 
Once my design skills had improved, I found myself using patterns in a different way: I began refactoring to patterns, instead of using them for up-front design or introducing them too early into my code. My new way of working with patterns emerged from my adoption of Extreme Programming design practices, which helped me avoid both over- and under-engineering.

Zapping Productivity
What does it mean to over-engineer? When you make your code more flexible or sophisticated than it needs to be, you overengineer it. Some do this because they believe they know their system's future requirements. They reason that it's best to make a design more flexible or sophisticated today, so it can accommodate the needs of tomorrow. That sounds reasonable, if you happen to be a psychic.
 
But if your predictions are wrong, you waste precious time and money. It's not uncommon to spend days or weeks fine-tuning an overly flexible or unnecessarily sophisticated software design—leaving you with less time to add new behavior or remove defects from a system.
 
What typically happens with code you produce in anticipation of needs that never materialize? It doesn't get removed, because it's inconvenient to do so, or because you expect that one day the code will be needed. Regardless of the reason, as overly flexible or unnecessarily sophisticated code accumulates, you and the rest of the programmers on your team, especially new members, must operate within a code base that's bigger and more complicated than it needs to be.

To compensate for this, folks decide to work in discrete areas of the system. This seems to make their jobs easier, but it has the unpleasant side effect of generating copious amounts of duplicate code, since everyone works in his or her own comfortable area of the system, rarely looking elsewhere for code that already does what he or she needs.
 
Over-engineered code affects productivity because when someone inherits an over-engineered design, they must spend time learning the nuances of that design before they can comfortably extend or maintain it.
 
Over-engineering tends to happen quietly: Many architects and programmers aren't even aware they do it. And while their organizations may discern a decline in team productivity, few know that over-engineering is playing a role in the problem.

Perhaps the main reason programmers over-engineer is that they don't want to get stuck with a bad design. A bad design can weave its way so deeply into code that improving it becomes an enormous challenge. I've been there, and that's why up-front design with patterns appealed to me so much.

The Patterns Panacea
When I first began learning patterns, they represented a flexible, sophisticated and even elegant way of doing object-oriented design that I very much wanted to master. After thoroughly studying the patterns, I used them to improve systems I'd already built and to formulate designs for systems I was about to build. Since the results of these efforts were promising, I was sure I was on the right path.
 
But over time, the power of patterns led me to lose sight of simpler ways of writing code. After learning that there were two or three different ways to do a calculation, I'd immediately race toward implementing the Strategy pattern, when, in fact, a simple conditional expression would have been a perfectly sufficient solution.
 
On one occasion, my preoccupation with patterns became quite apparent. I was pair programming, and my partner and I had written a class that implemented Java's TreeModel interface in order to display a graph of Spec objects in a tree widget. Our code worked, but the tree widget was displaying each Spec by calling its toString() method, which didn't return the Spec information we wanted. We couldn't change Spec's toString() method since other parts of the system relied on its contents. So we reflected on how to proceed. As was my habit, I considered which patterns could help. The Decorator pattern came to mind, and I suggested that we use it to wrap Spec with an object that could override the toString() method. My partner's response to this suggestion surprised me. "Using a Decorator here would be like applying a sledgehammer when a few light taps with a small hammer would do." His solution was to create a small class called NodeDisplay, whose constructor took a Spec instance, and whose one public method, toString(), obtained the correct display information from the Spec instance. NodeDisplay took no time to program, since it was less than 10 simple lines of code. My Decorator solution would have involved creating more than 50 lines of code, with many repetitive delegation calls to the Spec instance.

Experiences like this made me aware that I needed to stop thinking so much about patterns and refocus on writing small, simple, straightforward code. I was at a crossroads: I'd worked hard to learn patterns to become a better software designer, but now I needed to relax my reliance on them in order to become truly better.

Going Too Fast
Improving also meant learning to not under-engineer. Under-engineering is far more common than over-engineering. We under-engineer when we become exclusively focused on quickly adding more and more behavior to a system without regard for improving its design along the way. Many programmers work this way—I know I sure have. You get code working, move on to other tasks and never make time to improve the code you wrote. Of course, you'd love to have time to improve your code, but you either don't get around to it, or you listen to managers or customers who say we'll all be more competitive and successful if we simply don't fix what ain't broke.

That advice, unfortunately, doesn't work so well with respect to software. It leads to the "fast, slow, slower" rhythm of software development, which goes something like this:
  • You quickly deliver release 1.0 of a system, but with junky code.
  • You attempt to deliver release 2.0 of the system, but the junky code slows you down.
  • As you attempt to deliver future releases, you go slower and slower as the junky code multiplies, until people lose faith in the system, the programmers and even the process that got everyone into this position.
That kind of experience is far too common in our industry. It makes organizations less competitive than they could be. But there is a better way.

Socratic Development
Test-first programming and merciless refactoring, two of the many excellent Extreme Programming practices, dramatically improved the way I build software. I found that these two practices have helped me and the organizations I've worked for spend less time over-engineering and under-engineering, and more time designing just what we need: well-built systems, produced on time.
 
Test-first programming enables the efficient evolution of working code by turning programming into what Kent Beck once likened to a Socratic dialogue: Write test code to ask your system a question, write system code to respond to the question and keep the dialogue going until you've programmed what you need. This rhythm of programming put my head in a different place. Instead of thinking about a design that would work for every nuance of a system, test-first programming enabled me to make a primitive piece of behavior work correctly before evolving it to the next necessary level of sophistication.
 
Merciless refactoring is an integral part of this evolutionary design process. A refactoring is a "behavior-preserving transformation," or, as Martin Fowler defined it, "a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior" (Refactoring: Improving the Design of Existing Code, Addison -Wesley, 1999).

Merciless refactoring resembles the way Socrates continually helped dialogue participants improve their answers to his questions by weeding out inessentials, clarifying ambiguities and consolidating ideas. When you mercilessly refactor, you relentlessly poke and prod your code to remove duplication, clarify and simplify.
 
The trick to merciless refactoring is to not schedule time to make small design improvements, but to make them whenever your code needs them. The resulting quality of your code will enable you to sustain a healthy pace of development. Martin Fowler documents a rich catalog of refactorings, each of which identifies a common need for an improvement and the steps for making that improvement.
 
Why Refactor to Patterns?
On various projects, I've observed what and how my colleagues and I refactor. While we use many of the refactorings described in Fowler's book, we also find places where patterns can help us improve our designs. At such times, we refactor to patterns, being careful not to produce overly flexible or unnecessarily sophisticated solutions.

When I explored the motivation for refactoring to patterns, I found that it was identical to the motivation for implementing nonpatterns-based refactorings: to reduce or remove duplication, simplify the unsimple and make our code better at communicating its intention.
 
However, the motivation for refactoring to patterns is not the primary motivation for using patterns that is documented in the patterns literature. For example, let's look at the documented Intent and Applicability of the Decorator pattern (see Design Patterns: Elements of Reusable Object -Oriented Software by Erich Gamma, et al. Addison -Wesley, 1994) and then examine Erich Gamma and Kent Beck's motivation for refactoring to Decorator in their excellent, patterns-dense testing framework, JUnit.

Decorator's Intent: Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Decorator's Applicability
:
  • To add responsibilities to individual objects dynamically and transparently; that is, without affecting other objects.
  • For responsibilities that can be withdrawn.
  • When extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and could produce an explosion of subclasses to support every combination, or a class definition may be hidden or otherwise unavailable for subclassing.
Motivation for Refactoring to Decorator in JUnit: Gamma remembered the following reason for refactoring to Decorator: "Someone added TestSetup support as a subclass of TestSuite, and once we added RepeatedTestCase and ActiveTest Case, we saw that we could reduce code duplication by introducing the TestSetup Decorator." (Note: This was from a private e-mail.)
 
Can you see how the motivation for refactoring to Decorator (reducing code duplication) had very little connection with Decorator's Intent or Applicability (a dynamic alternative to subclassing)? I noticed similar disconnects when I looked at motivations for refactorings to other patterns. Consider the examples in the table below.

Based on these observations, I began to document a catalog of refactorings to patterns to illustrate when it makes sense to make design improvements with patterns. (To see the work-in -progress, visit http://industriallogic.com/xp/refactoring/ ). For this work, it's essential to show refactorings from real-world projects in order to accurately describe the kinds of forces that lead to justifiable transformations to a pattern.

My work on refactoring to patterns is a direct continuation of work that Martin Fowler began in his excellent catalog of
refactorings, in which he included the following refactorings to patterns:
  • Form Template Method
  • Introduce Null Object
  • Replace Constructor with Factory Method
  • Replace Type Code with State/Strategy
  • Duplicate Observed Data
Fowler also noted the natural relation between patterns and refactorings. Patterns are where you want to be; refactorings are ways to get there from somewhere else.

This idea agrees with the observation made in Design Patterns: "Our design patterns capture many of the structures that result from refactoring. … Design patterns thus provide targets for your refactorings."

Evolutionary Design
Today, after having become quite familiar with patterns, the "structures that result from refactoring," I know that understanding good reasons to refactor to a pattern are more valuable than understanding the result of a pattern or the nuances of implementing that result.

If you'd like to become a better software designer, studying the evolution of great software designs will be more valuable than studying the great designs themselves. For it is in the evolution that the real wisdom lies. The structures that result from the evolution can help you, but without knowing why they were evolved into a design, you're more likely to misapply them or over-engineer with them on your next project.

To date, our software design literature has focused more on teaching great solutions than teaching evolutions to great solutions. We need to change that. As the great poet Goethe said, "That which thy fathers have bequeathed to thee, earn it anew if thou wouldst possess it." The refactoring literature is helping us reacquire a better understanding of good design solutions by revealing sensible evolutions to those solutions.

If we want to get the most out of patterns, we must do the same thing: See patterns in the context of refactorings, not just as reusable elements existing apart from the refactoring literature. This is perhaps my primary motivation for producing a catalog of refactorings to patterns.

By learning to evolve your designs, you can become a better software designer and reduce the amount of work you over- or under-engineer. Test-first programming and merciless refactoring are the key practices of evolutionary design. Instill refactoring to patterns in your knowledge of refactorings and you'll find yourself even better equipped to evolve great designs.

Intention and Motivation in Refactoring Patterns
 Pattern Intent  Refactoring Motivations
 Builder Separate the construction of a complex object from its representation so that the same construction process can create different representations.
 Simplify code
 Remove duplication
 Reduce creation errors 
 Factory Method Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory Method lets a class defer instantiation to subclasses.  Remove duplication
 Communicate intent 
 Template Method Define the skeleton of an algorithm in an operation, deferring some steps to client subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.  Remove duplication
 

'Archive' 카테고리의 다른 글

테스트하기 쉬운 코드  (0) 2011.10.05
/etc/passwd 파일의 포맷  (0) 2011.10.04
디자인 패턴 공부 순서  (0) 2011.10.04
프로그래머를 위한 공부론 - 김창준  (0) 2011.10.04
리팩토링  (0) 2011.10.04
  

디자인 패턴 공부 순서

Posted by epicdev Archive : 2011. 10. 4. 19:18
출처: http://www.industriallogic.com/papers/learning.html

Design Patterns Navigation

l Factory Method Session 1
Begin with Factory Method. This pattern is used by a number of patterns in the book and throughout the patterns literature.
 
u Strategy Session 2
Strategy is used frequently throughout the book, and an early knowledge of it helps in understanding other patterns.
 
n Decorator Session 3
For an early dose of elegance, nothing is better than the Decorator. The discussion of "skin" vs. "guts" is a great way to differentiate Decorator from the previous pattern, Strategy.
 
n Composite Session 4
The Composite pattern appears everywhere and is often used with Iterator, Chain of Responsibility, Interpreter, and Visitor patterns.
 
u Iterator Session 5
Reenforce the reader's understanding of Composite by studying Iterator.
 
u Template Method Session 6
The author's footnote to Iterator explains that a method called "Traverse" in the Iterator example code is an example of a Template Method. This pattern also reenforces Strategy and Factory Method.
 
l Abstract Factory Session 7
The reader now returns to the second-easiest creational pattern, the Abstract Factory. This pattern also helps reenforce Factory Method.
 
l Builder Session 8
The reader now may compare another creational pattern, the Builder, with the Abstract Factory.
 
l Singleton Session 9
Singleton is often used to model Abstract Factories, as the "Related Patterns" section of Singleton describes.
 
n Proxy Session 10
The reader now has a chance to learn how Proxy is used to control access to an object. This pattern leads directly into the next pattern, Adapter.
 
n Adapter Session 11
The Adapter pattern may be compared with what the reader understands about Decorator, Proxy, and later, Bridge.
 
n Bridge Session 12
Finally, the reader learns how the Bridge pattern differs from both the Adapter and Proxy patterns.
 
u Mediator Session 13
Now the reader learns the Mediator pattern, in preparation for understanding Observer and the Model-View-Controller design.
 
u Observer Session 14
Discover how the Mediator is used by the Observer to implement the classic Model-View-Controller design.
 
u Chain of Responsibility Session 15
After exploring how messages are passed using the Observer and Mediator patterns, the reader now may contrast how messages are handled by the Chain of Responsibility pattern.
 
u Memento Session 16
The reader now moves on to Memento. This pattern leads directly into a discussion of undo and redo, which is related to the next pattern, Command.
 
u Command Session 17
The Command pattern is used in a number of ways, one of which relates to the previous pattern, Mediator.
 
l Prototype Session 18
Perhaps the most complex creational pattern, Prototype is often used with the Command pattern.
 
u State Session 19
The reader may now study State to understand another way an object's behavior changes.
 
u Visitor Session 20
Visitor is often combined with the Composite and/or Iterator patterns.
 
n Flyweight Session 21
The Flyweight pattern is one of the more complex patterns. An examples use of this pattern is described in the next pattern, Interpreter.
 
u Interpreter Session 22
The Interpreter pattern is complex. It makes reference to and helps reenforce one's understanding of Flyweight and Visitor.
 
n Facade Session 23
The final pattern to read is Facade. Facade is relatively straightforward and follows nicely after Interpreter since the example code is similar in theme to example code in the Interpreter.

 
Opening Questions For A Study Group

l Factory Method Session 1
How does Factory Method promote loosely coupled code?
 
u Strategy Session 2
Part 1: What happens when a system has an explosion of Strategy objects? Is there some way to better manage these strategies?

Part 2: In the implementation section of this pattern, the authors describe two ways in which a strategy can get the information it needs to do its job. One way describes how a strategy object could get passed a reference to the context object, thereby giving it access to context data. But is it possible that the data required by the strategy will not be available from the context's interface? How could you remedy this potential problem?

 
n Decorator Session 3
In the Implementation section of the Decorator Pattern, the authors write: A decorator object's interface must conform to the interface of the component it decorates.

Now consider an object A, that is decorated with an object B. Since object B "decorates" object A, object B shares an interface with object A. If some client is then passed an instance of this decorated object, and that method attempts to call a method in B that is not part of A's interface, does this mean that the object is no longer a Decorator, in the strict sense of the pattern? Furthermore, why is it important that a decorator object's interface conforms to the interface of the component. it decorates?

 
n Composite Session 4
Part 1: How does the Composite pattern help to consolidate system-wide conditional logic?

Part 2: Would you use the composite pattern if you did not have a part-whole hierarchy? In other words, if only a few objects have children and almost everything else in your collection is a leaf (a leaf can have no children), would you still use the composite pattern to model these objects?

 
u Iterator Session 5
Consider a composite that contains loan objects. The loan object interface contains a method called "AmountOfLoan()", which returns the current market value of a loan. Given a requirement to extract all loans above, below or in between a certain amount, would you write or use an Iterator to do this?
 
u Template Method Session 6
The Template Method relies on inheritance. Would it be possible to get the same functionality of a Template Method, using object composition? What would some of the tradeoffs be?
 
l Abstract Factory Session 7
In the Implementation section of this pattern, the authors discuss the idea of defining extensible factories. Since an Abstract Factory is composed of Factory Methods, and each Factory Method has only one signature, does this mean that the Factory Method can only create an object in one way?

Consider the MazeFactory example. The MazeFactory contains a method called MakeRoom, which takes as a parameter one integer, representing a room number. What happens if you would also like to specify the room's color & size? Would this mean that you would need to create a new Factory Method for your MazeFactory, allowing you to pass in room number, color and size to a second MakeRoom method?

Ofcourse, nothing would prevent you from setting the color and size of the Room object after is has been instantiated, but this could also clutter your code, especially if you are creating and configuring many objects. How could you retain the MazeFactory and keep only one MakeRoom method but also accomodate different numbers of parameters used by MakeRoom to both create and configure Room objects?

 
l Builder Session 8
Like the Abstract Factory pattern, the Builder pattern requires that you define an interface, which will be used by clients to create complex objects in pieces. In the MazeBuilder example, there are BuildMaze(), BuildRoom() and BuildDoor() methods, along with a GetMaze() method. How does the Builder pattern allow one to add new methods to the Builder's interface, without having to change each and every sub-class of the Builder?
 
l Singleton Session 9
The Singleton pattern is often paired with the Abstract Factory pattern. What other creational or non-creational patterns would you use with the Singleton pattern?
 
n Proxy Session 10
If a Proxy is used to instantiate an object only when it is absolutely needed, does the Proxy simplify code?
 
n Adapter Session 11
Would you ever create an Adapter that has the same interface as the object which it adapts? Would your Adapter then be a Proxy?
 
n Bridge Session 12
How does a Bridge differ from a Strategy and a Strategy's Context?
 
u Mediator Session 13
Since a Mediator becomes a repository for logic, can the code that implements this logic begin to get overly complex, possible resembling speggheti code? How could this potential problem be solved?
 
u Observer Session 14
Part 1: The classic Model-View-Controller design is explained in Implementation note #8: Encapsulating complex update semantics. Would it ever make sense for an Observer (or View) to talk directly to the Subject (or Model)?

Part 2: What are the properties of a system that uses the Objserver pattern extensively? How would you approach the task of debugging code in such a system?

Part 3: Is it clear to you how you would handle concurrency problems with is pattern? Consider an Unregister() message being sent to a subject, just before the subject sends a Notify() message to the ChangeManager (or Controller).

 
u Chain of Responsibility Session 15
Part 1: How does the Chain of Responsibility pattern differ from the Decorator pattern or from a linked list?.

Part 2: Is it helpful to look at patterns from a structural perspective? In other words, if you see how a set of patterns are the same in terms of how they are programmed, does that help you to understand when to apply them to a design?

 
u Memento Session 16
The authors write that the "Caretaker" participant never operates on or examines the contents of a memento. Can you consider a case where a Caretaker would infact need to know the identity of a memento and thus need the ability to examine or query the contents of that memento? Would this break something in the pattern?
 
u Command Session 17
In the Motivation section of the Command pattern, an application's menu system is described. An application has a Menu, which in turn has MenuItems, which in turn execute commands when they are clicked. What happens if the command needs some information about the application in order to do its job? How would the command have access to such information such that new comamnds could easily be written that would also have access to the information they need?
 
l Prototype Session 18
Part 1: When should this creational pattern be used over the other creational patterns?

Part 2: Explain the difference between deep vs. shallow copy.

 
u State Session 19
If something has only two to three states, is it overkill to use the State pattern?
 
u Visitor Session 20
One issue with the Visitor pattern involves cyclicality. When you add a new Visitor, you must make changes to existing code. How would you work around this possible problem?
 
n Flyweight Session 21
Part 1: What is a non-GUI example of a flyweight?

Part 2: What is the minimum configuration for using flyweight? Do you need to be working with thousands of objects, hundreds, tens?

 
u Interpreter Session 22
As the note says in Known Uses, Interpreter is most often used "in compilers implemented in object-oriented languages...". What are other uses of Interpreter and how do they differ from simply reading in a stream of data and creating some structure to represent that data?
 
n Facade Session 23
Part 1: How complex must a sub-system be in order to justify using a facade?

Part 2: What are the additional uses of a facade with respect to an organization of designers and developers with varying abilities? What are the political ramifications?

 

'Archive' 카테고리의 다른 글

/etc/passwd 파일의 포맷  (0) 2011.10.04
Stop Over-Engineering  (0) 2011.10.04
프로그래머를 위한 공부론 - 김창준  (0) 2011.10.04
리팩토링  (0) 2011.10.04
동시성을 고려한 설계를 하면 좋은 이유  (0) 2011.10.04
  

프로그래머를 위한 공부론 - 김창준

Posted by epicdev Archive : 2011. 10. 4. 18:55
정말 강력 추천 하고 싶은 텍스트 입니다.

http://xper.org/ns/upload/studyforprogrammer.pdf 
  

리팩토링

Posted by epicdev Archive : 2011. 10. 4. 16:53
리팩토링이 필요한 코드를 일종의 '종양'이라고 생각하자. 종양을 제거하려면 수술이 필요하다. 지금 바로 수술해서 아직 종양이 작을 때 제거 할 수도 있다. 하지만 종양이 자라고 다른 곳으로 전이 할 때까지 놓아 둘 수도 있다. 하지만 그 때가 되면 제거하는 데 드는 비용도 더 커질 뿐더러 위험도 훨씬 커진다. 시간을 더 끌면, 환자는 생명을 잃을지도 모른다.

<실용주의 프로그래머 팁>
일찍 리팩토링하고, 자주 리팩토링하라

리팩토링해야 할 것들의 명단을 만들고 유지하라. 어떤 것을 지금 당장 리팩토링하기 힘들다면, 일정에 그것을 리팩토링 할 시간을 확실히 포함시켜 두도록 한다. 그 코드를 사용하는 사람들이 코드가 조만간 리팩토링 될 것이라는 사실과 그 사실이 그들의 코드에 어떤 영향을 주게 될지 인지하도록 만들어야 한다.

리팩토링은 천천히, 신중하게, 조심스럽게 진행해야 하는 작업이다. 마틴 파울러는 손해보다 이득이 큰 방향으로 리팩토링을 하기 위한 다음 몇가지 간단한 조언을 제공한다.

1. 리팩토링과 새로운 기능 추가를 동시에 하지 말라.
2. 리팩토링을 시작하기 전 든든한 테스트 집합이 있는지 먼저 확인한다. 할 수 있는 한 자주 테스트들을 돌려본다. 이렇게 하면 여러분의 변경 때문에 무엇이 망가졌을 경우 재빨리 그 사실을 알 수 있다.
3. 단계를 작게 나누어서 신중하게 작업한다. 필드를 한 클래스에서 다른 클래스로 옮기기, 비슷한 메소드를 합쳐서 수퍼클래스로 옮기기. 리팩토링에서는 국지적인 변경들이 많이 모여서 커다란 규모의 변화를 낳는 일이 자주 발생한다. 단계를 작게 나누고, 한 단계가 끝날 때마다 테스트를 돌린다면, 기나긴 시간의 디버깅 작업을 피할 수 있다.

모듈에 큰 변화가 있다면, 즉 모듈의 인터페이스나 기능을 이전과 호환성을 유지 할 수 없을 정도로 변경하는 변화가 있다면, 일부러 빌드를 실패하도록 변화를 주는 기법도 유용하다. 리팩토링 대상 코드에 의존하는 옛날 코드들이 컴파일이 안 되게 만들어 버리는 것이다. 그러면 리팩토링 대상 코드에 어떤 코드들이 의존하는지 쉽게 찾아내서 지금 상황에 맞도록 고칠 수 있다.

그러므로 다음 번에 여러분이 마땅하다고 생각하는 수준에 못 미치는 코드를 보게 되면, 그 코드와 더불어 그 코드에 의존하는 모든 것도 함께 고치도록 한다. 고통을 관리하자. 지금 고통스럽더라도, 앞으로 더욱 고통스러워질 것 같으면 지금 고치는 편이 낫다.

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

동시성을 고려한 설계를 하면 좋은 이유

Posted by epicdev Archive : 2011. 10. 4. 11:03
동시성 요소가 포함 된 아키텍처를 설계 한 다음에는, 수많은 동시적 서비스들을 다루는 것에 대해 생각하기도 더 쉬워진다. 동시성 모델은 도처에 스며든다.

이제 애플리케이션을 어떻게 배치할지, 곧 독립 애플리케이션으로 할지, 클라이언트-서버로 할지, n-티어로 할지 결정하는 문제에 대해서도 유연하게 대응 할 수 있다. 시스템을 독립적인 서비스들로 구성 된 아키텍처로 만듦으로써, 설정 역시 동적으로 만들 수 있다. 동시성을 고려해서 계획하고 작업들의 시간적 결합을 끊음으로써, 동시성을 이용하지 않기로 선택한, 독립 애플리케이션을 포함해서 모든 옵션을 다 이용 할 수 있게 된다.

다른 길을 가는 것(비동시적 애플리케이션에 동시성을 추가하려고 하는 것)은 훨씬 힘들다. 동시성을 허용하도록 설계한다면, 확장가능성이나 성능에 대한 요구사항이 들어올 때 더 쉽게 그것에 맞추어 줄 수 있으며, 그런 일이 들어오지 않더라도 여전히 깔끔한 설계의 이점을 누리게 된다.

 
실용주의프로그래머
카테고리 컴퓨터/IT > 프로그래밍/언어
지은이 앤드류 헌트 (인사이트, 2007년)
상세보기
  
쓰레드를 사용하는 프로그래밍은 몇 가지 설계상의 제약을 받게 되는데, 이것은 좋은 일이다. 이 제약들은 워낙 도움이 많이 되어서 다른 어떤 프로그래밍을 하더라도 꼭 지키고 싶어지는 것이다. 이 제약들은 코드의 결합을 끊고 '우연에 맡기는 프로그래밍'과 싸우는 데 도움이 된다.

직선형 코드에서는 엄밀하지 않은 프로그래밍으로 이끌리는 전제들을 남발하기 쉽다. 하지만 동시성을 염두에 둔다면 여러 가지 일들을 더 주의 깊게 생각하게 될 수 밖에 없다. 더 이상 혼자 마음대로 놀 수 없는 것이다. 이제는 여러 일이 '동시에' 일어 날 수 있기 때문에, 갑자기 전에 못 보던 시간에 관련된 의존성들이 보이기 시작한다.

일단 제일 먼저, 모든 전역 변수나 정적 변수들을 동시 접근으로부터 보호해야 한다. 지금이 왜 애초에 전역 변수가 필요했는지 스스로에게 물을 수 있는 좋은 기회다. 게다가, 호출 순서와 관계없이 일관성 있는 상태 정보를 보일 수 있는지도 확인 해 봐야 한다. 예를 들어 언제 객체의 상태에 대해 물을 수 있는가? 만약 어떤 호출들 사이에서 객체가 유효하지 않은 상태에 있다면, 여러분은 아무도 그 시점에서는 그 객체를 호출하지 않을 것이라는 우연에 기대고 있는 셈이다.

위젯이 먼저 만들어지고 그 다음에 화면에 표시되는 두 단계 구조의 윈도우 하위시스템이 있다고 해보자. 위젯이 화면에 나오기 전에는 위젯의 상태를 설정 할 수 없다. 코드가 어떻게 되어있는지에 따라, 생성된 위젯이 화면에 보이기 전까지는 다른 객체가 그 위젯을 사용 할 수 없다는 사실에 의존하고 있는지도 모른다.

하지만 동시성 있는 시스템에서는 이것이 사실이 아닐지도 모른다. 객체는 호출 될 때 언제나 유효한 상태에 있어야 하는데, 객체들은 가장 불편한 시각에도 호출 될 수 있는 것이다. 호출 될 가능성이 있는 모든 시간에 언제나 객체가 유효한 상태에 있도록 만들어야 한다. 이 문제는 생성자와 초기화 루틴을 별개로 정의하는 클래스에서 종종 나타난다.

<실용주의 프로그래머 팁>
언제나 동시성을 고려해 설계하라

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

'Archive' 카테고리의 다른 글

리팩토링  (0) 2011.10.04
동시성을 고려한 설계를 하면 좋은 이유  (0) 2011.10.04
세부사항을 코드에서 몰아내라  (0) 2011.10.03
Camera의 setDisplayOrientation 메소드  (0) 2011.10.03
Java 필드 초기화  (0) 2011.10.03
  

세부사항을 코드에서 몰아내라

Posted by epicdev Archive : 2011. 10. 3. 22:57
세부사항은 우리의 깔끔한 코드를 어질러 놓는다. 특히 변화가 잦을 때는 더더욱 그러하다. 그러므로 우리는 "세부사항에서 벗어나라!"고 말한다. 세부사항을 코드에서 몰아내라. 이렇게 함으로써 우리의 코드는 매우 설정 가능(configurable)하게 되고 '소프트' 해진다. 즉 변화에 쉽게 적응 할 수 있게 되는 것이다.

우선 시스템을 되도록 설정가능하게 만들기 바란다. 배경 색, 프롬프트 텍스트 뿐 아니라 알고리즘의 선택, 사용 할 데이터베이스 제품, 미들웨어 기술, 사용자 인터페이스 스타일 등 시스템의 심층까지 말이다. 이런 아이템들은 통합하거나 엔지니어링하지 말고 설정 옵션으로 구현해야 한다.

<실용주의 프로그래머 팁>
 통합하지 말고 설정하라

<실용주의 프로그래머 팁>
코드에는 추상화를, 메타데이터에는 세부 내용을

실용주의프로그래머
카테고리 컴퓨터/IT > 프로그래밍/언어
지은이 앤드류 헌트 (인사이트, 2007년)
상세보기
  
 «이전 1 ··· 8 9 10 11 12 13 14 ··· 17  다음»