You are on page 1of 97

The Crafsman 1.

Opening Diaster.
Robert C. Martin
13 Thng 2, 2002

Bi vit ny l"#c trch t& ch"$ng Principles, Patterns and Practices trong cu(n Agile
Software Development c*a Robert C. Martin, nh xu-t b/n Prentice Hall, 2002.

Nh0t k thn mn,
13 thng 2, 2002.

Hm nay 2ng l m3t ngy xui x4o - Ti lm h5ng c/ chuy6n. Ti r-t mu(n gy -n t"#ng
v7i cc ngi "c9u h:c vi6c" ; 2y nh"ng rt cu3c ch< lm r(i tung c/ ln.

l ngy 2>u tin ti 2"#c m3t chn h:c vi6c v7i ng C. Ti qu/ l may m?n c 2"#c chn
h:c vi6c ny. ng C l m3t tay trm l7p lang trong v-n 2@ pht triAn ph>n m@m. -u 2A
ginh 2"#c chn vi6c ny 2ng l nBy lCa. Cc tay h:c vi6c c*a ng C th"Dng tr; nn cc
tay "c9u h:c vi6c" sng gi. i@u ny c nghEa 2"#c lm vi6c v7i ng C c gi trF r rng.

Ti cH ngI l hm nay ti sK 2"#c gLp ng ta nh"ng thay v 2 ti bF m3t g "c9u h:c vi6c"
nu ti qua m3t bn. G b/o ng C lun lun dNn cc tay h:c vi6c 2i xuyn qua ph>n 2Fnh
h"7ng trong nhOng ngy 2>u. G ni ng C nh-t quyt cho rPng ph>n th9c t0p 2Fnh h"7ng
l thit th9c v7i cc tay h:c vi6c v n dNn 2n mHc ch-t l"#ng m nguQn m ng ta ta d9
t";ng.

Ti no nHc kinh kh*ng. y l m3t c$ h3i cho h: th-y ti l m3t tay l0p trnh "ngon" cI
no. Th l ti b/o Jerry ti khng chD 2"#c nOa. G 2p lRi s9 no nHc c*a ti bPng cch
b/o ti thC vit m3t ch"$ng trnh 2$n gi/n cho g. G mu(n ti dng "Sieve of
Eratosthenes" 2A tnh cc s( nguyn. G cn b/o ti ph/i chuBn bF xong ch"$ng trnh bao
gQm tr:n b3 cc "unit tests" sSn sng 2A "ch-m" sau buTi Un tr"a.

Th0t l khoi! Ti c g>n 4 ting 2Qng hQ 2A "xo n-u" m3t ch"$ng trnh gi(ng nh" Sieve.
Ti quyt tm th9c hi6n cng tc ny m3t cch ht sHc c -n t"#ng. M dNn 1 2"a ra nhOng
g ti 2 vit. Ti n?m ch?c l ch"$ng trnh c*a ti 2"#c ch thch cBn th0n v trnh by g:n
gng.

M dn 1
/**
* This class generates prime numbers up to a user-specified maximum.
* The algorithm used is the Sieve of Eratosthenes.
* <p>
* Eratosthenes of Cyrene, b.c. 276 BC, Cyrene, Libya; d.c.194 BC,Alexandria.
* He was the first man to calculate the circumference of the Earth,
* and was also known for working on calendars with leap years and
* running the library at Alexandria.</p>
*
* The algorithm is quite simple:
* Given an array of integers starting at 2, cross out all multiples of 2.
* Find the next uncrossed integer, and cross out all of its multiples.
* Repeat until you have passed the square root of the maximum value.
*
* @authorAlphonse, @version 13 Feb 2002 atp
*/
import java.util.*;

public class GeneratePrimes {
/**
* @param maxValue is the generation limit.
*/
public static int[] generatePrimes(int maxValue) {
if (maxValue >= 2) { // the only valid case
// declarations
int s = maxValue + 1; // size of array
boolean[] f = new boolean[s];
int i;
// initialize array to true.
for (i = 0; i < s; i++)
f[i] = true;

// get rid of known non-primes.
f[0] = f[1] = false;

// sieve
int j;
for (i = 2; i < Math.sqrt(s) + 1; i++) {
if (f[i]) { // if i is uncrossed, cross its multiples.
for (j = 2 * i; j < s; j += i)
f[j] = false; // multiple is not prime
}
}

// how many primes are there?
int count = 0;
for (i = 0; i < s; i++) {
if (f[i])
count++; // bump count.
}
int[] primes = new int[count];
// move the primes into the result.
for (i = 0, j = 0; i < s; i++) {
if (f[i]) // if prime
primes[j++] = i;
}
return primes; // return the primes.
} else // maxValue < 2
return new int[0]; // return null array if bad input.
}
}

Sau 2 ti vit m3t ci "unit test" cho GeneratePrimes. Xem ; m dNn 2. oRn m ny dng
JUnit framework nh" Jerry 2 ch< dNn. N dng tnh ch-t h"7ng th(ng k; kiAm tra xem ci
"generator" c thA tRo ra cc s( nguyn t7i 0, 2, 3 v 100. Trong tr"Dng h#p thH nh-t hVn
khng c s( nguyn no c/. Trong tr"Dng h#p thH nh hVn ph/i c m3t s( nguyn v n
ph/i l s( 2. Tr"Dng h#p thH ba ph/i c hai s( nguyn v chng ph/i l s( 2 v 3. Tr"Dng
h#p cu(i ph/i l 25 s( nguyn v s( cu(i ph/i l 97. Nu cc b"7c kiAm tra 2@u 2ng, ti
gi/ 2Fnh l ci "generator" lm vi6c 2ng. Ti e rPng kh c thA tin c0y tuy6t 2(i cch ;
trn, nh"ng ti khng nghE ra 2"#c m3t tr"Dng h#p no m3t "function" c thA bF h5ng m
cc b"7c kiAm tra 2@u 2ng.










M dn 2
import junit.framework.*;
import java.util.*;
public class TestGeneratePrimes extends TestCase {
public static void main(String args[]) {
Junit.swingui.TestRunner.main( new String[] {"TestGeneratePrimes"});
}
public TestGeneratePrimes(String name) {
super(name);
}
public void testPrimes() {
int[] nullArray = GeneratePrimes.generatePrimes(0);
assertEquals(nullArray.length, 0);

int[] minArray = GeneratePrimes.generatePrimes(2);
assertEquals(minArray.length, 1);
assertEquals(minArray[0], 2);

int[] threeArray = GeneratePrimes.generatePrimes(3);
assertEquals(threeArray.length, 2);
assertEquals(threeArray[0], 2);
assertEquals(threeArray[1], 3);

int[] centArray = GeneratePrimes.generatePrimes(100);
assertEquals(centArray.length, 25);
assertEquals(centArray[24], 97);
}
}

Ti m-t kho/ng m3t giD 2Qng hQ 2A lm nhOng b"7c trn chRy 2"#c. Jerry khng mu(n gLp
ti cho 2n sau buTi Un tr"a, b;i th, ti dnh tr:n b3 thDi gian cn lRi 2:c cu(n Design
Patterns m Jerry 2"a cho ti.

Sau buTi Un tr"a, ti gh vUn phng c*a Jerry v cho g bit ti 2 th9c hi6n xong ch"$ng
trnh. G nhn ti v v7i m3t nW c"Di kh t/, h?n ni: ""#c l?m, hy xem thC n th no."

G dNn ti v phng th nghi6m v cho ti ngQi tr"7c m3t my. G ngQi bn cRnh ti v yu
c>u ti 2"a ch"$ng trnh c*a ti vo my ny. Th l ti chuyAn m nguQn t& my laptop
c*a ti ln.

Jerry xem xt hai m nguQn ch&ng nUm pht rQi g l?c 2>u v b/o: "My khng thA 2"a
nhOng ci ny cho ng C xem 2"#c! Nu tao 2A Tng xem m-y ci ny, Tng sK 2uTi cT c/ tao
lNn my. ng -y khng ph/i l ng"Di kin nhNn 2u."

Ti 2nh tht m3t pht nh"ng c( giO bnh tEnh v h5i g: "Ch7 n sai chX no?"

Jerry th; di v ni: "TWi mnh nn 2i xuyn qua m nguQn ny v7i nhau. Tao sK ch< cho
my t&ng 2iAm m3t cch ng C mu(n th9c hi6n n nh" th no."

"Qu r rng", g tip tWc, "ci main function mu(n lm ra ba ci functions ring bi6t. Ci
thH nh-t kh;i tRo t-t c/ cc bin hm v thit l0p ci "sieve". Ci thH nh th9c s9 thi hnh
ci "sieve" v ci thH ba t/i kt qu/ c*a "sieve" vo m3t dy s( nguyn."

Ti nh0n ra 2"#c g mu(n ni g. C ba khi ni6m chn trong ci function 2. Tuy v0y, ti
khng bit g mu(n ti ph/i lm g v7i n.
G nhn ti m3t lc, r rng 2ang 2#i ti ph/n Hng sao 2. Nh"ng r(t cu3c g th; di, l?c
2>u v....
<2n 2:c bi k tip>
The Crafsman 2.
Crash Diet.
Robert C. Martin

Trong phn tr"#c * Jerry, m&t tay c*u h+c vi,c yu cu Alphonse, m&t tay h+c vi,c, vi.t
m&t ch"$ng trnh t/o cc s0 nguyn dng "sieve of Etastosthenes". Jerry, nh1n th2y
Alphonse 3ng d4ng tr+n b& thu1t ton vo m&t function "kh6ng t"7ng" nn 8 yu cu
Alphonse tch n ra theo ba khi ni,m: kh9i 8&ng, 3ng t/o v chu;n xu2t;... nh"ng
Alphonse khng bi.t ph<i b=t 8u t> 8u...

G nhn ti m3t lc, r rng 2ang 2#i ti lm g 2. Nh"ng r(t cu3c g th; di, l?c 2>u v
tip tWc. "A m; r3ng ba khi ni6m r rng h$n, tao mu(n my tch chng ra thnh ba
methods ring bi6t. Qng thDi vHt ht nhOng ci phW ch khng c>n thit v 2Lt m3t ci tn
kh h$n cho ci class. My lm xong nhOng thH 2 rQi ph/i b/o 2/m l m-y ci test vNn cn
chRy 2"#c."

Cc bRn c thA th-y nhOng 2iAm ti 2 lm trong M dNn 3. Ti 2 2nh d-u nhOng thay 2Ti
bPng chO 20m, y h6t nh" Martin Fowler trnh by trong cu(n Refactoring c*a ng ta. Ti 2Ti
tn c*a ci class thnh dRng danh t&, vHt ht nhOng phW ch v@ chuy6n Eratosthenes v tRo
ra ba methods t& ba khi ni6m trong generatePrimes function.

Tch ra ba functions bu3c ti ph/i 2"a ra m3t s( bin hm c*a function thnh static fields
c*a ci class. Jerry ni cch ny lm r nhOng bin hm no l local v nhOng bin hm no
c /nh h";ng r3ng l7n h$n.

M dn 3
PrimeGenerator.java, version 2

/**
* This class generates prime numbers up to a user-specified
* maximum. The algorithm used is the Sieve of Eratosthenes.
* Given an array of integers starting at 2: Find the first
* uncrossed integer, and cross out all its multiples. Repeat
* until the first uncrossed integer exceeds the square root of
* the maximum value.
*/
import java.util.*;

public class PrimeGenerator {
private static int s;
private static boolean[] f;
private static int[] primes;

public static int[] generatePrimes(int maxValue) {
if (maxValue < 2)
return new int[0];
else {
initializeSieve(maxValue);
sieve();
loadPrimes();
return primes; // return the primes
}
}
private static void loadPrimes() {
int i,j;

// how many primes are there?
int count = 0;
for (i = 0; i < s; i++) {
if (f[i])
count++; // bump count.
}

primes = new int[count];

// move the primes into the result
for (i = 0, j = 0; i < s; i++) {
if (f[i]) // if prime
primes[j++] = i;
}
}
private static void sieve() {
int i,j;
for (i = 2; i < Math.sqrt(s) + 1; i++) {
// if i is uncrossed, cross out its multiples.
if (f[i]) {
for (j = 2 * i; j < s; j += i)
f[j] = false; // multiple is not prime
}
}
}
private static void initializeSieve(int maxValue) {
// declarations
s = maxValue + 1; // size of array
f = new boolean[s];

// initialize array to true.
for (int i = 0; i < s; i++)
f[i] = true;

// get rid of known non-primes
f[0] = f[1] = false;
}
}

Jerry b/o ti m ny h$i l3n x3n, nn g ginh l-y bn 2nh v ch< ti cch d:n dYp. M
dn 4 minh hoR nhOng g g 2 lm. ThoRt tin g vHt 2i ci bin hm s trong
initializeSieve v thay th n bPng f.length. Sau 2 g 2Ti tn c*a ba functions (theo
kiAu) g cho l c -n t"#ng h$n. Cu(i cng g s?p xp lRi ci "b3 lng"
initializeArrayOfIntegers (t& initializeSieve) 2A cho dZ 2:c h$n m3t cht. Cc ci test
vNn chRy nh"ng th"Dng.

M dn 4
PrimeGenerator.java, version 3 (partial)

public class PrimeGenerator {
private static boolean[] f;
private static int[] result;

public static int[] generatePrimes(int maxValue) {
if (maxValue < 2)
return new int[0];
else {
initializeArrayOfIntegers(maxValue);
crossOutMultiples();
putUncrossedIntegersIntoResult();
return result;
}
}
private static void initializeArrayOfIntegers(int maxValue) {
f = new boolean[maxValue + 1];
f[0] = f[1] = false; //neither primes nor multiples.
for (int i = 2; i < f.length; i++)
f[i] = true;
}

Ti ph/i cng nh0n m ny r h$n m3t cht. Tr"7c giD ti nghE tRo functions c tn sinh
23ng l ph thDi giD , nh"ng nhOng ch<nh 2Ti c*a g qu/ th0t lm cho m nguQn dZ 2:c h$n.

Tip theo Jerry tr5 vo crossOutMultiples, ni l g nghE cWm if(f[i] == true) c thA lm
cho dZ 2:c h$n nOa. Ti nghE 2n 2iAm ny ch&ng m3t pht. 2Fnh c*a cc cWm ny dng
2A kiAm tra xem i khng bF loRi tr&; th l ti 2Ti tn c*a f thnh unCrossed.

Jerry ni m ny 2"#c h$n nh"ng ti vNn ch"a hi lng v7i n v n dNn 2n kh/ nUng ph*
2Fnh 2i (double negative) nh" unCrossed[i] = false. B;i th g 2Ti tn c*a dy s( thnh
dy isCrossed v7i ch< s( nh5 h$n 2. Cc ci test vNn chRy 2"#c.

Jerry tch ph>n lLp bn trong (inner loop) c*a crossOutMultiples function v g:i n l
crossOutMultipleOf. G b/o rPng cc cWm t"$ng t9 nh" if (isCrossed[i] == false) dZ
nh>m lNn nn g tRo ra function c tn notCrossed v thay cWm if thnh if
(notCrossed(i)). Kt tip g chRy thC m-y ci test lRi.

Sau 2 Jerry h5i ti nghEa c*a ph>n s( cUn 2 l g. Ti t(n t thDi giD vit phW ch gi/i
thch tRi sao c>n ph/i lLp lRi cho 2n ph>n s( cUn c*a chi@u di dy s(. Ti c( tranh 2ua v7i
Jerry bPng cch tch ph>n tnh ton thnh m3t function, n$i ti c thA 2"a vo ph>n phW
gi/i. Trong khi vit phW ch ti nh0n ra rPng cUn s( l phn t( c9c 2Ri c*a s( nguyn trong
m3t dy s(. B;i th 2A Hng ph, ti ch:n cch g:i 2 (maxValue) cho cc bin hm. Cu(i
cng ti b/o 2/m cc tests vNn chRy 2"#c. Kt qu/ c*a cc thay 2Ti trong M dn 5.

M dn 5
PrimeGenerator.java version 4 (partial)
public class PrimeGenerator {
private static boolean[] isCrossed;
private static int[] result;

public static int[] generatePrimes(int maxValue) {
if (maxValue < 2)
return new int[0];
else {
initializeArrayOfIntegers(maxValue);
crossOutMultiples();
putUncrossedIntegersIntoResult();
return result;
}
}
private static void
initializeArrayOfIntegers(int maxValue) {
isCrossed = new boolean[maxValue + 1];
for (int i = 2; i < isCrossed.length; i++)
isCrossed[i] = false;
}
private static void crossOutMultiples() {
int maxPrimeFactor = calcMaxPrimeFactor();
for (int i = 2; i <= maxPrimeFactor; i++)
if (notCrossed(i))
crossOutMultiplesOf(i);
}
private static int calcMaxPrimeFactor() {
// We cross out all multiples of primes. Thus, all crossed
// out multiples have p and q for factors. If p > sqrt of the
// size of the array, then q will never be greater than 1.
// Thus p is the largest prime factor in the array, and is
// also the iteration limit.
double maxPrimeFactor = Math.sqrt(isCrossed.length) + 1;
return (int) maxPrimeFactor;
}
private static void crossOutMultiplesOf(int i) {
for (int multiple = 2*i; multiple < isCrossed.length; multiple += i)
isCrossed[multiple] = true;
}
private static boolean notCrossed(int i) {
return isCrossed[i] == false;
}

Ti b?t 2>u n?m b?t 2"#c v-n 2@ nn li@n xt lRi method
putUncrossedIntegersIntoResult. Ti th-y rPng method ny c hai ph>n. Ph>n thH nh-t
2m cc s( nguyn khng bF loRi trong dy s(, v tRo nn dy kt qu/ (bPng chi@u di c*a
dy s(). Ph>n thH nh dDi cc s( nguyn khng bF loRi vo dy kt qu/ ny. B;i th, nh"
bRn th-y trong M dn 6, ti tch ph>n thH nh-t ra 2A hnh thnh function cho chnh n v
d:p dYp lLt vLt 2i cht. Cc tests vNn chRy 2"#c. Jerry ch< thong g0t 2>u. G c th0t s9
khoi nhOng 2i@u ti 2 th9c hi6n khng?

M dn 6
PrimeGenerator.java, version 5 (partial).
private static void putUncrossedIntegersIntoResult() {
result = new int[numberOfUncrossedIntegers()];
for (int j = 0, i = 2; i < isCrossed.length; i++)
if (notCrossed(i))
result[j++] = i;
}
private static int numberOfUncrossedIntegers() {
int count = 0;
for (int i = 2; i < isCrossed.length; i++)
if (notCrossed(i))
count++;
return count;
}


<2n xem ph>n k tip>

* Trong nguyn b/n l "In the last month's column..." nh"ng ; 2y tRm dFch thong ra l
"trong ph>n tr"7c" cho ph h#p v7i tinh th>n cc bi craftsman 2"#c post ln diZn 2n
(khng theo thng m theo... ty hHng c*a ng"Di dFch ;))
The Crafsman 3.
Clarity and Collaboration
Rober C. Martin

Ln tr"#c, Jerry, m&t c*u h+c vi,c yu cu tay h+c vi,c Alphonse vi.t m&t ch"$ng trnh t/o
s0 nguyn t0 dng ph"$ng php l"7t Eratosthenes (sieve of Eratosthenes). Jerry duy,t v
gip Alphonse tch l"7c (refactor) m ngu@n 8. Anh ta khng 8"7c hi lng v#i k.t qu< cAa
Alphonse. Ln tr"#c Alphonse th*c hi,n xong phn refactoring v nghB ch=c Jerry sC ch2p
thu1n...

Jerry ch< thong g0t 2>u. Li6u g c th0t s9 khoi nhOng 2i@u ti 2 lm khng?

Sau 2 Jerry 2i xuyn qua tr:n b3 ch"$ng trnh, 2:c lRi t& 2>u 2n cu(i nh" thA g 2ang
2:c bi chHng minh hnh h:c. G b/o ti 2y l m3t b"7c ht sHc quan tr:ng. "n b"7c
ny, tWi mnh 2 th9c hi6n refactoring cc m/nh m. By giD tWi mnh xem thC tr:n b3
ch"$ng trnh c thA n(i li@n nhau nh" m3t dRng tTng thA".

Ti h5i: "Jerry, b3 ng c[ng lm nh" th v7i chnh m nguQn c*a ng sao?"

Jerry qu?c m?t ln v ni: "\ 2y tWi tao lm vi6c v7i nhau theo nhm nn khng c ci m
no l c*a ring tao ht. B3 my cho l ci m ny c*a ring my h;?"

Ti tr/ lDi ht sHc nh5 nh4: "ht nghE nh" v0y rQi, ng /nh h";ng r-t l7n 2n m nguQn
ny."

G tr/ lDi: "C/ hai thPng mnh 2@u /nh h";ng 2n n, v 2y l cch ng C "a chu3ng. ng
-y khng khoi b-t cH m3t ai lm ch* m nguQn ht 2u. Tr/ lDi ring cho cu h5i c*a my:
ng v0y, ; 2y tWi tao th9c nghi6m ci "r$" refactoring v d:n rc v 2y l ph"$ng php
c*a ng C."

Trong khi 2:c qua m nguQn, Jerry th-y g khng khoi ci tn initializeArrayOfIntegers.

G ni: "Ci 2"#c kh;i tRo ; 2y th9c ra khng ph/i l m3t dy s( nguyn, m l m3t dy
booleans. Nh"ng initializeArrayOfBooleans khng hVn l cch c/i tin. i@u chng ta
th9c s9 mu(n lm ; method ny l li6t k ra m3t danh sch cc s( nguyn ph h#p v 2A
chng ln m3t ci sng, rQi sau 2 l:c v loRi ra cc s( khng ph/i s( nguyn t( (ie loRi ra
nhOng b3i s()". (Do 2, danh sch lc 2>u sK khng bF gRch cho, nhOng s( bF loRi sK sK bF
gRch cho (crossed out )).

Ti tr/ lDi: "T-t nhin!" Th l ti v7 l-y bn 2nh v sCa tn c*a method 2 thnh
uncrossIntegersUpTo. Ti c[ng th-y khng khoi ci tn isCrossed lRi dng cho m3t dy
booleans, nn ti 2Ti n thnh crossedOut. Cc ci test vNn chRy. Ti b?t 2>u th-y thch
m-y ci tr ny nh"ng Jerry vNn khng h@ t5 v4 2Qng tnh.

Sau 2 Jerry quay lRi, h5i ti c ph/i ti 2 m$ mng theo khi thu(c khi vit ci m7
maxPrimeFactor. (Xem M dn 6). ThoRt 2>u ti ht sHc ngI ngng nh"ng khi xem lRi
2oRn m v cc phW ch ti nh0n th-y g c l. Eo i, ti th-y mnh th0t l ngu! CUn b0c 2
(Square root )* c*a chi@u di m3t dy s( khng hVn l nguyn s(. Method 2 khng tnh
th&a s( nguyn t( c9c 2Ri (max prime factor) **. Ph>n ch gi/i sai bt nn, ht sHc ng"#ng
ngng ti vit lRi ph>n phW ch 2A gi/i thch r h$n ci cUn b0c 2 ny dng 2A lm g v 2Ti
tn nhOng bin , hm cho thch h#p. Cc test vNn chRy.





M dn 6

TestGeneratePrimes.java (Partial)
private static int calcMaxPrimeFactor() {

// We cross out all multiples of p, where p is prime.
// Thus, all crossed out multiples have p and q for factors.
// If p > sqrt of the size of the array, then q will never
// be greater than 1. Thus p is the largest prime factor
// in the array, and is also the iteration limit.

double maxPrimeFactor = Math.sqrt(isCrossed.length) + 1;
return (int) maxPrimeFactor;
}

"dng +1 ; 2y lm qui g v0y?" Jerry tru tro ln.

Ti nu(t ci 9c, xem lRi 2oRn m v cu(i cng ti pht biAu: "Ti ngRi l khi ch< l-y ph>n
nguyn c*a cUn b0c 2, th ph>n th0p phn c*a cUn b0c 2 2 bF m-t 2i, do 2 vng lLp c thA
bF thiu."

G bn h5i: "Cho nn my x/ rc trong 2oRn m v7i ph>n gia tUng "+1" b;i v my bF
ho/ng? Nh" th th ng(c qu, dYp ngay ci tr gia tUng "+1" 2 2i v thC test lRi."

Ti lm nh" th v tr:n b3 cc test 2@u chRy. Ti suy nghE lRi ph>n ny m3t lc v n lm ti
run qu. Th nh"ng ti quyt 2Fnh c thA gi7i hRn lLp lRi th9c s9 chnh l s( "th&a s(
nguyn t( c9c 2Ri" v "th&a s( nguyn t(" 2 <= cUn b0c 2 chi@u di c*a dy s(.

"Ph>n thay 2Ti v&a rQi lm ti kh b(i r(i". Ti ni v7i Jerry. "Ti hiAu nguQn g(c 2Png sau
ci cUn b0c 2, nh"ng ti c/m th-y khng yn, bit 2u c tr"Dng h#p "bin" no 2 mnh
ch"a th-y ht."

G l>m b>m "OK, v0y th vit m3t ci test khc 2A kiAm tra chuy6n 2 2i."

"Ti nghE ti c thA kiAm tra xem trong cc danh sch s( nguyn t& 2 2n 500 khng c
tr"Dng h#p ; trn".

"OK, nu n lm cho my c/m th-y dZ chFu h$n, th thC 2i." G ni. R rng l g b?t 2>u
tr; nn m-t kin nhNn.

Th l ti vit ci testExhaustive function nh" trong M dn 8. Ph>n test m7i ny chRy
2ng v nXi lo s# c*a ti l?ng xu(ng.

Jerry dFu xu(ng m3t cht. G ni: "Bit 2"#c l do tRi sao m3t ci g 2 chRy 2"#c lun lun
l m3t 2i@u t(t; v lRi cng t(t h$n khi m kiAm chHng 2"#c my 2ng bPng ci test."

Sau 2 Jerry d qua tr:n b3 m nguQn v cc ci tests m3t l>n nOa (xem M dn 7 v 8).
G ng ng"Di ra v suy nghE ch&ng m3t pht rQi ni: "OK, tao nghE l tWi mnh lm xong. M
nguQn ny xem ra 2* r rng (clean) rQi 2. Tao sK 2"a cho ng C xem."

Th rQi g nhn ti, lRnh lng ni: "Ph/i nh7, t& nay v@ sau khi my vit m3t ph>n no 2,
nn tm s9 gip 2I v nh7 giO cho m nguQn r rng (clean). Nu my nhng tay vo
nhOng thH d"7i tiu chuBn ny, my khng "th:" ; 2y 2u."

G r/o b"7c.




M dn 7
PrimeGenerator.java (final)
/**
* This class generates prime numbers up to a user specified maximum.
* The algorithm used is the Sieve of Eratosthenes. Given an array of
* integers starting at 2: Find the first uncrossed integer, and cross out
* all its multiples. Repeat until there are no more multiples in the array.
*/
public class PrimeGenerator {
private static boolean[] crossedOut;
private static int[] result;

public static int[] generatePrimes(int maxValue) {
if (maxValue < 2)
return new int[0];
else {
uncrossIntegersUpTo(maxValue);
crossOutMultiples();
putUncrossedIntegersIntoResult();
return result;
}
}
private static void uncrossIntegersUpTo(int maxValue) {
crossedOut = new boolean[maxValue + 1];
for (int i = 2; i < crossedOut.length; i++)
crossedOut[i] = false;
}
private static void crossOutMultiples() {
int limit = determineIterationLimit();
for (int i = 2; i <= limit; i++)
if (notCrossed(i))
crossOutMultiplesOf(i);
}
private static int determineIterationLimit() {
// Every multiple in the array has a prime factor that is
// less than or equal to the sqrt of the array size, so we
// don't have to cross out multiples of numbers larger than that root.
double iterationLimit = Math.sqrt(crossedOut.length);
return (int) iterationLimit;
}
private static void crossOutMultiplesOf(int i) {
for (int multiple = 2*i; multiple < crossedOut.length; multiple += i)
crossedOut[multiple] = true;
}
private static boolean notCrossed(int i) {
return crossedOut[i] == false;
}
private static void putUncrossedIntegersIntoResult() {
result = new int[numberOfUncrossedIntegers()];
for (int j = 0, i = 2; i < crossedOut.length; i++)
if (notCrossed(i))
result[j++] = i;
}
private static int numberOfUncrossedIntegers() {
int count = 0;
for (int i = 2; i < crossedOut.length; i++)
if (notCrossed(i))
count++;

return count;
}
}

M dn 8
TestGeneratePrimes.java (final)
import junit.framework.*;

public class TestGeneratePrimes extends TestCase {
public static void main(String args[]) {
junit.swingui.TestRunner.main(new String[] {"TestGeneratePrimes"});
}
public TestGeneratePrimes(String name) {
super(name);
}
public void testPrimes() {
int[] nullArray = PrimeGenerator.generatePrimes(0);
assertEquals(nullArray.length, 0);

int[] minArray = PrimeGenerator.generatePrimes(2);
assertEquals(minArray.length, 1);
assertEquals(minArray[0], 2);

int[] threeArray = PrimeGenerator.generatePrimes(3);
assertEquals(threeArray.length, 2);
assertEquals(threeArray[0], 2);
assertEquals(threeArray[1], 3);
int[] centArray = PrimeGenerator.generatePrimes(100);
assertEquals(centArray.length, 25);
assertEquals(centArray[24], 97);
}
public void testExhaustive() {
for (int i = 2; i<500; i++)
verifyPrimeList(PrimeGenerator.generatePrimes(i));
}
private void verifyPrimeList(int[] list) {
for (int i=0; i<list.length; i++)
verifyPrime(list[i]);
}
private void verifyPrime(int n) {
for (int factor=2; factor<n; factor++)
assert(n%factor != 0);
}
}

Qu/ l tai hoR! Ti cH ngI l gi/i php nguyn th*y c*a ti l th"#ng thLng. Cht g 2 ti
vNn cn c/m th-y nh" v0y. Ti c( ph tr"$ng ti nUng c*a ti nh"ng ti 2on l ng C 2nh
gi cao s9 c3ng tc v tnh minh bRch h$n ti nUng c nhn.

Ti ph/i th nh0n rPng ch"$ng trnh ny dZ xem h$n lc kh;i 2>u. N lRi lm vi6c ngon h$n
m3t t nOa. Ti kh hi lng v7i kt qu/ v, mLc d Jerry c thi 23 c3c cPn, lm vi6c v7i g
ti c[ng th-y vui. Ti h:c h5i 2"#c r-t nhi@u.

DNu v0y, ti th-y h$i chn b"7c v7i chnh hi6u su-t c*a ti. Ti khng dm nghE l m-y tay
; 2y sK khoi ti cho l?m. Ti c[ng khng dm ch?c 2n bao bao giD h: 2nh gi ti 2*
"ngon". S9 thA sK kh khUn h$n ti nghE nhi@u l?m.

* Square root hay c"n s$ l cch g:i tr"7c 2y cho cUn b0c 2, m3t cch g:i 2"#c dng sau ny ; VN (ch thch
ny dnh cho nhOng ai th?c m?c v7i 1 s( thu0t ngO ton h:c x"a v nay ;))
** max prime factor hay th&a s$ nguyn t$ c)c +,i (hoLc phn t( c9c 2Ri nguyn s() c[ng l nhOng thu0t ngO
ton (quen dng) tr"7c 2y. c9c 2Ri c thA dFch l t(i 2a nu mu(n (ch thch ny m3t l>n nOa dnh cho nhOng ai
th?c m?c v7i 1 s( thu0t ngO ton h:c x"a v nay ;))

<2n 2:c ph>n k tip>
The Crafsman 4.
ATest Of Patient
Robert C. Martin
12 thng 7, 2002

Nh0t k thn yu,

T(i qua ti ngQi t9a cCa sT hng giD, nhn cc v sao mD d>n trong b>u trDi 2m. Ti th-y
vi6c lm c*a ti v Jerry hm qua c nhi@u xung 23t. Ti h:c h5i r-t nhi@u trong khi lm
vi6c v7i Jerry v7i v-n 2@ tRo s( nguyn t(, nh"ng ti khng tin ti gy -n t"#ng g v7i g.
V, th0t tnh m ni, ti c[ng khng nA g cho l?m. Th0t ra, g t(n kh nhi@u thDi gian mi
d[a cc m/nh m cho d nhOng m/nh m ny lm vi6c ngon lnh.

Hm nay v7i m3t bi t0p m7i, Jerry 2n gLp ti. G yu c>u ti vit m3t ch"$ng trnh tnh
th&a s( nguyn t( c*a s( nguyn. G cho bit g lm vi6c v7i ti ngay t& 2>u nn hai chng
ti ngQi xu(ng v b?t 2>u l0p trnh.

Ti tin ch?c ti bit cch lm. Hm qua chng ti 2 vit ch"$ng trnh tRo s( nguyn t(. D
tm cc th&a s( nguyn t( ch< l v-n 2@ 2i xuyn qua danh sch cc s( nguyn t( v xt thC
c th&a s( no t& cc s( nguyn 2 2Fnh. Th nn ti v7 l-y bn 2nh v b?t 2>u vit m.
Kho/ng nOa giD sau khi vit v kiAm tra, ti lm 2"#c nh" sau:

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class PrimeFactorizer {

public static void main(String[] args) {
int[] factors = findFactors(Integer.parseInt(args[0]));
for (int i = 0; i < factors.length; i++) System.out.println(factors[i]);
}

public static int[] findFactors(int multiple) {
List factors = new LinkedList();
int[] primes = PrimeGenerator.generatePrimes((int) Math.sqrt(multiple));
for (int i = 0; i < primes.length; i++)
for (; multiple % primes[i] == 0; multiple /= primes[i])
factors.add(new Integer(primes[i]));
return createFactorArray(factors);
}

private static int[] createFactorArray(List factors) {
int factorArray[] = new int[factors.size()];
int j = 0;
for (Iterator fi = factors.iterator(); fi.hasNext();) {
Integer factor = (Integer) fi.next();
factorArray[j++] = factor.intValue();
}
return factorArray;
}
}

Ti kiAm tra ch"$ng trnh bPng cch chRy n v7i nhi@u thng s( khc nhau. M:i thH d"Dng
nh" Tn tho/. ChRy ch"$ng trnh v7i gi trF thng s( 100 cho ti kt qu/ 2, 2, 5 v 5. ChRy
n v7i 32767 cho ti 7, 31 v 151. ChRy v7i 32768 cho ti m"Di lUm s( hai.

Jerry ngQi nhn ti. G chVng ni nCa lDi. i@u ny lm ti h$i ho/ng nh"ng ti tip tWc n?n
bp v thC nghi6m m nguQn cho 2n lc ti hi lng. Sau 2, ti b?t 2>u vit ph>n "unit
tests".

Jerry h5i: "My lm g v0y?"

"Ch"$ng trnh chRy nn ti 2ang vit cc unit tests." Ti 2p lRi.

"Nu ch"$ng trnh 2 chRy vi6c g my c>n unit tests?" G h5i tip.

Ti khng nghE 2n 2iAm ny. Ti ch< bit theo thng l6 c>n ph/i vit unit tests. Ti li@u lEnh
2on m: "A m cc l0p trnh vin khc bit 2"#c l ch"$ng trnh 2 chRy?"

Jerry nhn ti kho/ng 30 giy rQi g l?c 2>u v ni: "ThDi buTi ny h: dRy dX tWi my ci g
; tr"Dng v0y?"

Ti 27 l"Ii khng tr/ lDi 2"#c nh"ng g ngUn ti lRi bPng m3t ci nhn.

"OK", g ni, "xo ht nhOng thH my 2 lm 2i. Tao ch< cho my cch tWi tao lm ; 2y."

Ti qu/ khng chuBn bF cho tnh th nh" v0y. G mu(n ti xo nhOng g ti 2 tRo ra trong
ba m"$i pht qua. Ti ch< ngQi yn, khng t";ng t"#ng nTi.

Cu(i cng Jerry ni: "Xo 2i."

Ti tr/ lDi: "Nh"ng ch"$ng trnh 2 chRy m."

"Th sao?" Jerry 2p lRi.

Ti b?t 2>u nTi cu. Ti ni cHng: "Ch"$ng trnh ny chVng c g sai ht!"

"Th9c v0y h;?" g l>m b>m v v7 l-y bn 2nh, xo ht m nguQn c*a ti.

Ti 2ing ng"Di. Khng ph/i, ti 2in tit ln. G m7i v&a chQm qua v xo ht 2Q c*a ti.
Trong pht ch(c -y ti chVng cn thit g 2n "u th 2"#c lm m3t tay h:c vi6c cho ng C
nOa. H:c vi6c m ph/i 2Wng 2n nhOng k4 tn bRo nh" Jerry th cn hay ho g nOa? V7i
nghE nh" th v nhOng nghE cn km ph>n t";ng th";ng khc diZn nhanh qua trong 2>u
trong khi ti nhn g chPm chLp.

", tao th-y my nTi 2o rQi 2." Jerry ni m3t cch 2i@m tEnh.

Ti l?p b?p nh"ng chVng th(t 2"#c g cho minh bRch.

"Ny." Jerry ni, r rng 2ang c( lm dFu ti xu(ng. "&ng c 2eo cHng vo m nguQn c*a
m qu nh" v0y. Ch< c ba m"$i pht lm vi6c m thi chVng ph/i l ci g gh g7m 2u.
My ph/i chuBn bF tinh th>n vHt b5 thm c/ 2(ng m nguQn nOa nu my mu(n tr; thnh
m3t thH l0p trnh vin g 2. VHt b5 2"#c hng 2(ng m nguQn th"Dng l 2i@u t(t nh-t m
my nn lm.

Ti bu3c mi6ng: "Nh"ng lm nh" th th qu/ l ph!"

G h5i lRi: "B3 my nghE gi trF c*a ch"$ng trnh nPm trong m nguQn sao? Khng ph/i v0y.
Gi trF c*a m3t ch"$ng trnh nPm trong ci 2>u c*a my 2."

G nhn ti ch&ng m3t giy rQi tip tWc. "C bao giD my lI tay xo ci g 2 my 2ang lm
ch"a? ci g 2 m-t c*a my vi ngy lm vi6c 2?"

"C m3t l>n, ; tr"Dng". Ti ni "Ci disk bF h5ng v hQ s$ l"u trO c[ 2n hai ngy."

G cau my g0t 2>u biAu l3 s9 thng hiAu rQi h5i: "My m-t bao lu 2A ti tRo lRi nhOng ci
2 bF m-t?"

"Ti n?m kh r nhOng ci bF m-t nn ch< m-t c nCa ngy 2A ti tRo."

"Ra th my chVng th0t s9 m-t kh(i l"#ng hai ngy lm vi6c."

Ti chVng mng g 2n ci logic c*a g. Ti khng b?t b4 2"#c nh"ng ti khng khoi ci
logic 2. Ch< 2$n gi/n l ti c/m th-y bF m-t m3t kh(i l"#ng hai ngy lm vi6c!

G h5i tip: "My c nh0n th-y ph>n m lm lRi t(t h$n hay t6 h$n ph>n m my bF m-t
khng?"

"^, t(t h$n nhi@u." Ti ni, ngay l0p tHc h(i tic l 2 pht biAu nh" th. "L>n thH nh ti c
thA dng m3t c-u trc t(t h$n nhi@u."

G c"Di. "Th th c( thm 25 ph>n trUm, my 2"a ra 2"#c m3t gi/i php t(t h$n."

Logic c*a g lm ti b9c mnh. Ti l?c 2>u v g>n nh" tht ln: "C ph/i ng gi/ 2Fnh l
chng ta lun lun vHt b5 m nguQn sau khi lm xong?"

Tr/ lDi cho s9 ngRc nhin c*a ti, g g0t 2>u v ni: "G>n nh" l nh" v0y. Tao gi/ 2Fnh
chuy6n vHt b5 m nguQn l m3t vi6c gi trF v hOu dWng. Tao gi/ 2Fnh my khng nn xem
2 l chuy6n hoang ph. Tao gi/ 2Fnh my khng nn m kh" kh" ci m nguQn c*a my."

<2n xem ph>n k tip>
The Crafsman 5.
Baby Step
Robert C. Martin
24 thng B/y 2002

Jerry yu c>u ti vit m3t ch"$ng trnh tRo ra cc th&a s( nguyn t(. Ti vit xong, ch"$ng
trnh chRy ngon lnh v sau 2 g xo m-t ch"$ng trnh 2. Ti kh b9c nh"ng Jerry b/o:
"&ng c qu 2eo cHng vo m nguQn c*a mnh nh" th."

Ti chVng khoi ci tr ny nh"ng ti khng c m3t cht lu0n cH no 2A ch(ng ch:i v7i g.
Ti ch< ngQi yn, b-t 2Qng.

"OK", g ni, "Mnh lm lRi t& 2>u. Cch tWi tao lm ; 2y l vit 'unit tests' tr"7c".

Ci ny 2ng l kiAu nghiZn chuy6n qui 2/n. Ti nhanh tr ph/n Hng ngay: "H;?"

"A tao ch< cho my th-y." G ni. "Cng tc c*a tWi mnh l tRo ra m3t dy cc th&a s(
nguyn t( t& m3t s( nguyn. My nghE 2"#c tr"Dng h#p test no 2$n gi/n nh-t?"

"Tr"Dng h#p gi trF 2>u tin l 2. V trong 2 n 2"a v@ m3t dy v7i ch< m3t s( 2."

"ng rQi." G ni. V g vit m3t ci unit test nh" sau:

public void testTwo() throws Exception {
int factors[] = PrimeFactorizer.factor(2);
assertEquals(1, factors.length);
assertEquals(2, factors[0]);
}

K tip g vit m3t 2oRn m r-t 2$n gi/n cho php ci "test case" bin dFch.

public class PrimeFactorizer {
public static int[] factor(int multiple) {
return new int[0];
}
}

G chRy thC ci test v n bo lXi: "testTwo(TestPrimeFactors): expected: <1> but
was: <0>".

n 2y g nhn ti v ni: "Lm cch g 2$n gi/n nh-t 2A v"#t qua ci test case 2."

y 2ng l v l chQng ch-t. " ng l sao?" Ti h5i. "i@u 2$n gi/n nh-t hVn tr/ v@ m3t
dy v7i s( 2 trong 2."

G tr/ lDi v7i v4 mLt nghim nghF: " OK, lm v0y 2i."

"Nh"ng ng7 ngBn qu." Ti ni, "Ci m ny sai. Gi/i php th9c s9 khng ch< tr/ v@ c s(
2."

"`a, 2ng v0y." G 2p lDi. "Nh"ng khu-y nh3n ln m3t t dm tao 2i."

Ti th; di b9c d:c, ph0p ph m3t cht rQi vit:



public static int[] factor(int multiple) {
return new int[] {2};
}

Ti chRy ci test v - t-t nhin n Tn c/.

Ti h5i "Ci ny chHng minh 2"#c 2i@u g v0y?"

"N chHng minh l my c thA vit m3t ci hm tm ra th&a s( nguyn t( c*a 2." G ni.
"N c[ng chHng minh l test 2 Tn khi ci hm tr/ lDi 2ng v7i s( 2."

Ti 2/o m?t l>n nOa. M-y thH ny nPm d"7i "c$" c*a ti. Ti ngI l lm m3t tay h:c vi6c ;
2y sK 2"#c dRy m3t ci g 2 c$ chH.

"By giD, ci test case no 2$n gi/n nh-t mnh c thA 2"a thm vo?" g h5i ti.

Ti khng km 2"#c, ti ch chit m3t cch diZu c#t: "i, Jerry hay l mnh nn thC v7i s(
3?"

V dNu ti h#m tr"7c, khng ngD g vit m3t ci "test case" cho s( 3 th0t:

public void testThree() throws Exception {
int factors[] = PrimeFactorizer.factor(3);
assertEquals(1, factors.length);
assertEquals(3, factors[0]);
}

ChRy ci test ny n bo lXi nh" 2 2on tr"7c: "testThree(TestPrimeFactors):
expected: <3> but was: <2>".

"OK Alphonse, "Lm cch g 2$n gi/n nh-t 2A ci test case ny Tn."

M-t kin nhNn ti v7 l-y bn 2nh v 2nh vo nh" sau:

public static int[] factor(int multiple) {
if (multiple == 2) return new int[] {2};
else return new int[] {3};
}

Ti chRy thC m-y ci test v chng 2@u Tn c/.

Jerry nhn ti v7i m3t nW c"Di b-t th"Dng. G ni: "OK, m-y ci test 2 2Rt. Tuy nhin, nhn
ra khng "chin" l?m ph/i khng?"

G l ng"Di by ci tr ng7 ngBn ny v by giD g 2i h5i ti c chin hay khng? "Ti cho
rPng tr:n b3 bi t0p ny kh n/n 2." Ti ni.

G lD 2i v tip tWc. "CH mXi l>n my thm vo m3t "test case" m7i, my ph/i cho n v"#t
qua 2"#c bPng cch lm cho m nguQn cng tTng qut h$n. By giD thC 2"a ra thay 2Ti 2$n
gi/n nh-t, tTng qut h$n gi/i php 2>u tin c*a my xem sao."

Ti nghE v@ v-n 2@ ny ch&ng m3t pht. R(t cu3c Jerry 2 h5i ti vi 2i@u c>n tr no. ng
v0y, c gi/i php tTng qut h$n nOa. Ti v7 l-y bn 2nh v g nh" sau :

public static int[] factor(int multiple) {
return new int[] {multiple};
}

Cc ci tests 2@u Tn c/ v Jerry m<m c"Di nh"ng ti vNn khng thA hnh dung lm sao m-y
ci tr ny 2"a 2n v-n 2@ tRo ra th&a s( nguyn t(. n mHc ny 2i@u duy nh-t ti c thA
pht biAu l nhOng ci tr qui 2/n ny ch< ph thDi gian. Tuy nhin ti vNn khng ngRc
nhin m-y khi Jerry h5i ti: By giD, ci test case no 2$n gi/n nh-t mnh c thA 2"a thm
vo?"

"R rng l cho tr"Dng h#p s( 4." Ti ni m3t ch thiu kin nhNn v v7 l-y bn 2nh, ti
vit:

public void testFour() throws Exception {
int factors[] = PrimeFactorizer.factor(4);
assertEquals(2, factors.length);
assertEquals(2, factors[0]);
assertEquals(2, factors[1]);
}

Ti ni "Ti d9 ph5ng ci 'assert' thH nh-t sK h5ng v chi@u di c*a dy ch< cho 1."

Qu/ v0y, khi chRy thC ci test n t"Dng trnh: "testFour(TestPrimeFactors) :expected
<2> but was <1>".

Ti h5i: "Ti 2on ng mu(n ti 2"a ra thay 2Ti 2$n gi/n nh-t c thA lm cho cc ci test
2@u Tn v tRo ra ph"$ng thHc th&a s( tTng qut h$n?"

Jerry g0t 2>u.

Ti c( g?ng ph(i h#p gi/i quyt cho ci test case tr"7c m?t, lD cc test case ti bit sK 2Wng
2n sau. Ci tr ny th0t l ai on nh"ng Jerry mu(n v0y. Kt qu/ nh" sau:

public class PrimeFactorizer {
public static int[] factor(int multiple) {
int currentFactor = 0;
int factorRegister[] = new int[2];
for (; (multiple % 2) == 0; multiple /= 2)
factorRegister[currentFactor++] = 2;
if (multiple != 1)
factorRegister[currentFactor++] = multiple;
int factors[] = new int[currentFactor];
for (int i = 0; i < currentFactor; i++)
factors[i] = factorRegister[i];
return factors;
}
}

oRn m ny qua ht cc ci test nh"ng nhn kh l3n x3n. Jerry nhUn mLt nh" thA g 2nh
2"#c mi hi th(i 2u 2y. G ni: "Mnh ph/i 'refactor' ci ny tr"7c khi 2i tip."

"H"#m 2." Ti ph/n 2(i. "Ti 2Qng n l3n x3n nh"ng sao mnh khng lm cho n chRy
tr"7c rQi 'refector' lRi nu c 2* thDi gian?"

"TrDi! Khng 2"#c!" Jerry ni. "Mnh c>n ph/i 'refector' ngay lc ny 2A c thA th-y c-u trc
th9c s9 tin ho, khng th chng ta ch< chQng ch-t ci b&a b3n trn ci b&a b3n v chng
ta sK khng cn bit mnh 2ang lm g nOa."

"OK." Ti th; di. "Th d:n dYp."

Th rQi hai 2Ha ti tch l"#t ph>n m ny m3t cht. Kt qu/ nh" sau:


public class PrimeFactorizer {

private static int factorIndex;
private static int[] factorRegister;

public static int[] factor(int multiple) {
initialize();
findPrimeFactors(multiple);
return copyToResult();
}

private static void initialize() {
factorIndex = 0;
factorRegister = new int[2];
}

private static void findPrimeFactors(int multiple) {
for (; (multiple % 2) == 0; multiple /= 2)
factorRegister[factorIndex++] = 2;
if (multiple != 1)
factorRegister[factorIndex++] = multiple;
}

private static int[] copyToResult() {
int factors[] = new int[factorIndex];
for (int i = 0; i < factorIndex; i++)
factors[i] = factorRegister[i];
return factors;
}
}

Jerry tuyn b(: "n lc cho ci test case k tip." v g chuyAn bn 2nh 2n ti.

Ti vNn ch"a thA nh0n ra tr ny 2i 2n 2u nh"ng ch< bit khng cch g thot ra 2"#c.
M3t cch nhn nh"#ng ti g ci test case nh" sau:

public void testFive() throws Exception {
int factors[] = PrimeFactorizer.factor(5);
assertEquals(1, factors.length);
assertEquals(5, factors[0]);
}

"Th0t l l th." Ti ni trong khi nhn chPm chLp vo ci 'bar' mu xanh, "n chRy m
chVng c>n thay 2Ti g ht."

"ng l l th". Jerry n(i tip. "Hy thC ci test case k tip."

Lc ny ti bF thu ht r. Ti khng d9 t";ng ci test case ch< chRy nh" v0y. NgNm nghE v@
v-n 2@ ny, ti c[ng ch"a h";ng Hng th9c s9 nh"ng r rng n chRy. Ti kh ch?c ci test
kt tip sK h5ng nn g 2oRn test nh" sau sau v chRy thC:










public void testSix() throws Exception {
int factors[] = PrimeFactorizer.factor(6);
assertEquals(2, factors.length);
assertContains(factors, 2);
assertContains(factors, 3);
}

private void assertContains(int factors[], int n) {
String error = "assertContains:" + n;
for (int i = 0; i < factors.length; i++) {
if (factors[i] == n)
return;
}
fail(error);
}

"Ui! Ci test ny c[ng Tn lun!" ti r ln.

"L th." Jerry g0t g. "V0y 7 sK chRy lun ph/i khng?"

"Vng, ti nghE v0y."

"v0y th b5 n 2i v 2i thVng t7i 8, n khng qua 2"#c ci test 2u!"

G 2ng. 8 ph/i h5ng v dy factorRegister qu nh5.

public void testEight() throws Exception {
int factors[] = PrimeFactorizer.factor(8);
assertEquals(3, factors.length);
assertContainsMany(factors, 3, 2);
}

private void assertContainsMany(int factors[], int n, int f) {
String error = "assertContains(" + n + "," + f +")";
Int int count = 0;
for (int i = 0; i < factors.length; i++) {
if (factors[i] == f)
count++;
}
if (count != n)
fail(error);
}

"ng l nhY nhm!, n h5ng rQi!"

"`a." Jerry 2p "v bF qu gi7i hRn chi@u di c*a dy. My c thA lm n v"#t qua 2"#c bPng
cch gia tUng chi@u di c*a factorRegister nh"ng cch ny khng tTng qut h$n 2"#c."

"Th cH thC xem sao rQi mnh gi/i quyt v-n 2@ chi@u di c*a dy sau."

Th l ti 2Ti 2 thnh 3 trong hm initialize v c ci 'bar' mu xanh.

"OK," ti ni, "s( c9c 2Ri c*a cc th&a s( mnh c thA c l g?"

"Tao nghE hnh nh" l lga 2 c*a m3t s( hay sao 2." Jerry ni.

"HSng 2!" Ti ni, "C thA mnh 2ang 2i vng vng 2y. S( l7n nh-t mnh c thA xC l l
m-y? khng ph/i l 2 m[ 64 sao?"

Jerry 2p "Tao ch?c l khng thA h$n con s( 2."

"OK, v0y th thC tRo ra chi@u di c*a factorRegister l 100 2i. N l7n 2* 2A xC l b-t cH s(
no mnh nm t7i n."

""#c thi." Jerry ni "M3t trUm s( nguyn th chVng c g ph/i lo."

Chng ti thC v cc ci test vNn chRy.

Ti nhn Jerry v ni: "test case k tip c*a ti 2 nha. Ch?c ch?n n sK h5ng."

G 2p "Th thC 2i."

Nn ti g nh" sau:

public void testNine() throws Exception {
int factors[] = PrimeFactorizer.factor(9);
assertEquals(2, factors.length);
assertContainsMany(factors, 2, 3);
}

"TrDi, n h5ng th0t." Ti ni. "Cho ci test qua 2"#c c[ng 2$n gi/n thi. Ti ch< c>n b5 2i 2
nh" m3t s( 2Lc bi6t trong findPrimeFactors v dng c/ 2 v 3 cho thu0t ton tTng qut."
Th l ti 2i@u ch<nh findPrimeFactors nh" sau:

private static void findPrimeFactors(int multiple) {
for (int factor = 2; multiple != 1; factor++)
for (; (multiple % factor) == 0; multiple /= factor)
factorRegister[factorIndex++] = factor;
}

"OK, 2Rt". Jerry ni. "By giD xem thC ci test case tip theo no h5ng?"

"`m, thu0t ton 2$n gi/n ti dng 2A chia 2"#c t& s( phi nguyn t( lNn s( nguyn t(. KiAu
ny sK khng th9c hi6n cho 2ng 2"#c nn phin b/n 2>u c*a ch"$ng trnh ch< chia 2"#c t&
s( nguyn t(. Thu0t ton 2>u dnh cho s( phi nguyn t( sK chia cho 4 nn ti m"Dng t"#ng
4X4 sK h5ng.

public void testSixteen() throws Exception {
int factors[] = PrimeFactorizer.factor(16);
assertEquals(4, factors.length);
assertContainsMany(factors, 4, 2);
}

"Ui! Ci test ny qua kh5i." Ti ni "Lm sao n qua kh5i 2"#c c?"

"N qua 2"#c v t-t c/ cc s( 2 2 2"#c loRi b5 tr"7c khi my thC chia cho 4, nn 4 khng
bao giD nh0n ra nh" m3t th&a s(. Nn nh7, n c[ng khng th-y nh" m3t th&a s( hoLc l 8,
hoLc l 4!"

"T-t nhin!" ti tr/ lDi. "T-t c/ cc s( nguyn t( bF dDi b5 tr"7c cc 2a h#p. Th0t ra thu0t
ton dng 2A kiAm tra cc 2a h#p khng dnh d9 g ht, nh"ng 2i@u 2 c nghEa l ti khng
h@ c>n dy c*a cc s( nguyn t( trong phin b/n 2>u c*a ti."

"ng th." Jerry ni. " l l do tRi sao tao xo n."

"V0y th xong? Mnh hon thnh rQi ph/i khng?"

Jerry h5i: " My c thA nghE ra 2"#c ci test case no bF h5ng khng?"

"Ti khng bit nOa, hy thC 1000 2i." Ti tr/ lDi.

", kiAu ch$i m 2Qm. OK, thC 2i."

public void testThousand() throws Exception {
int factors[] = PrimeFactorizer.factor(1000);
assertEquals(6, factors.length);
assertContainsMany(factors, 3, 2);
assertContainsMany(factors, 3, 5);
}

"N chRy lun! OK, hay l..."

Chng ti thC nhi@u test case khc nh"ng ci no c[ng Tn c/. Phin b/n ny c*a ch"$ng
trnh 2$n gi/n h$n phin b/n 2>u tin c*a ti nhi@u v chRy nhanh h$n nOa. Hn chi Jerry
2 xo 2i phin b/n 2>u.

i@u lm ti kinh ngRc v vNn cn lm ti kinh ngRc l sau mXi ci test case chng ti lRi
tuQn ra m3t gi/i php t(t h$n. Nu khng r-n ln mXi l>n m3t test case th ti khng nghE
sK bao giD dnh vo l(i khai triAn 2$n gi/n ny. Ti khng bit chuy6n g sK x/y ra v7i nhOng
projects l7n h$n nOa?

Hm nay ti 2 h:c 2"#c 2i 2i@u.

<2n xem ph>n k tip>
The Crafsman 6.
Socket Service
Robert C. Martin
16 thng Chn 2002

S9 ki6n ngy hm qua lm ti l/ ng"Di. Jerry v ti gi/i quyt xong v-n 2@ tRo th&a s(
nguyn t( bPng cch tuQn qua mXi l>n m3t test case t hon. y l m3t cch gi/i quyt v-n
2@ kb lR nh-t m ti t&ng th-y nh"ng n lRi lm vi6c ngon lnh h$n gi/i php nguyn th*y
c*a ti.

Ti lBn quBn v 2Fnh h"7ng trong cc hnh lang, ngNm nghE 2n chuy6n ny mi. Ti chVng
cn nh7 2n bOa t(i hay ; 2u nOa. Ti ng* thip 2i s7m h$n ngy th"Dng v chim bao v@
nhOng phn 2oRn c*a m-y ci test b nh5 kia.

Sng nay khi ti trnh di6n Jerry, g ni:

"Cho Alphonse. My 2 sSn sng cho m3t ch"$ng trnh th0t ch"a?"

"ng th&a bit nh" th! Thch qu, vng, ti sSn sng! Ti qu m6t m-y ci tr thC nghi6m
ny l?m rQi."

"T(t l?m! TWi mnh c m3t ch"$ng trnh g:i l SMC dng 2A bin dFch trRng thi ngO php
hOu hRn c*a my vo mi tr"Dng Java. ng C mu(n tWi mnh bin ch"$ng trnh -y thnh
m3t dFch vW trn mRng."

" ng l sao?", ti h5i.

Jerry xoay qua b/n phc th/o rQi b?t 2>u cng m3t lc gi/ng gi/i v minh hoR.





"Mnh sK vit hai ch"$ng trnh. M3t ci g:i l SMCR Client v ci kia g:i l SMCR Server.
Ng"Di dng mu(n bin dFch trRng thi ngO php hOu hRn c*a my sK dng tn c*a hQ s$ 2A
g:i SMCR Client. SMCR Client sK g;i hQ s$ 2 2n m3t my 2Lc bi6t n$i SMCR Server 2ang
hoRt 23ng. SMCR Server sK chRy ph>n bin dFch SMC v g;i kt qu/ bin dFch v@ SMCR
Client. SMCR Client sK vit cc dO ki6n ny vo th" mWc c*a ng"Di dng. (i v7i ng"Di
dng, c$ ch ny khng khc g h: 2ang dng SMC tr9c tip."

"OK, ti nghE l ti hiAu v-n 2@." Ti ni. "Nghe kh 2$n gi/n."

"N kh 2$n gi/n th0t." Jerry 2p. "Nh"ng 2Wng 2n sockets lc no c[ng th vF h$n m3t
cht."

Chng ti ngQi xu(ng my v, nh" th"Dng l6, chuBn bF t" th vit ci unit test 2>u tin.
Jerry suy nghE m3t lc rQi tr; lRi b/n phc th/o v phc hoR ra m3t biAu 2Q nh" sau:





"y l nghE c*a tao v@ SMCR Server." G ni. "Chng ta sK 2Lt m qu/n l socket vo
class SocketService. Class ny sK 2n v qu/n trF cc truy c0p t& bn ngoi vo. Khi
serve(port) 2"#c g:i, n sK tRo m3t dFch vW socket v7i port 2 -n 2Fnh v b?t 2>u tip
nh0n truy c0p. B-t cH khi no c m3t truy c0p x/y ra n sK tRo m3t thread m7i v chuyAn
giao nhi6m vW 2i@u tc sang method serve(socket) thu3c interface SocketServer. V7i
cch 2, mnh tch rDi m qu/n trF socket ra kh5i ph>n m mnh mu(n dng 2A thao tc cc
dFch vW khc."

Khng n?m 2"#c l(i khai triAn ny hi6u qu/ hay khng, ti ch< g0t 2>u. R rng g c l do
2A nghE nh" th. Ti ch< theo 2ui m thi.

K tip g vit ci test nh" sau:

public void testOneConnection() throws Exception {
SocketService ss = new SocketService();
ss.serve(999);
connect(999);
ss.close();
assertEquals(1, ss.connections());
}

"Chuy6n tao lm ; 2y c ci tn I ntentional Programming (l0p trnh c ch* 2Fnh). Jerry
ni. "Tao g:i ci 2oRn m trong lc n ch"a tQn tRi. Lm nh" th 2A diZn 2Rt ch* c*a
mnh v@ ph"$ng di6n m nguQn sK ra sao, lm vi6c nh" th no."

"OK." Ti 2p. "ng tRo ci SocketService rQi ng ch< 2Fnh n tip nh0n cc truy c0p trn
port 999. K tip c v4 nh" ng truy c0p vo dFch vW m7i v&a 2"#c tRo ra trn port 999.
Cu(i cng ng 2ng SocketService v 'assert' rPng n c m3t truy c0p."

"ng nh" th." Jerry xc nh0n.

"Nh"ng lm sao ng bit SocketService sK c>n cc connections method?"

", c lK n khng c>n. Tao ch< 2Lt n ; 2 2A c thA test n."

"Nh" v0y khng ph sao?" Ti dRm h5i.

Jerry nghim kh?c nhn ti v tr/ lDi: "Khng c g lm cho m3t ci test 2"#c dZ dng lRi l
phung ph c/ Alphonse. TWi tao th"Dng thm cc methods v cc classes 2$n gi/n 2A tRo
2i@u ki6n test cc classes dZ dng h$n."

Ti khng khoi ci connnections() method nh"ng cH lm thinh.

Chng ti ch< vit v&a 2* ph>n contructor SocketService v cc methods serve, close v
connect 2A c thA bin dFch tr:n b3. Cc functions ny 2@u tr(ng nn khi chng ti chRy
thC, ci test bF h5ng nh" d9 2on.

K tip Jerry vit method connect nh" m3t ph>n c*a ci class cho test case

private void connect(int port) {
try {
Socket s = new Socket("localhost", port);
s.close();
}
catch (IOException e) {
fail("could not connect");
}
}

ChRy test ny bo lXi nh" sau: "testOneConnection: could not connect"

Ti ni: "N h5ng v khng thA tm ra port 999 ; 2u ht, 2ng khng?"

"ng v0y!" Jerry tr/ lDi. "Nh"ng chuy6n 2 dZ thi. y, sao my khng sCa n 2i?"

Tr"7c giD ti ch"a bao giD vit m cho socket nn khng bit ph/i lm tip nhOng g. Jerry
ch< ti 2n ph>n ServerSocket trong Javadocs. Cc v dW ; 2y xem ra r-t 2$n gi/n nn ti
ngoy thm trong cc methods c*a SocketService nh" sau:

public class SocketService {
private ServerSocket serverSocket = null;

public void serve(int port) throws Exception {
serverSocket = new ServerSocket(port);
}

public void close() throws Exception {
serverSocket.close();
}

public int connections() {
return 0;
}
}

ChRy ph>n m ny n bo: "testOneConnection: expected: <1> but was: <0>"

" ha!" Ti ni: "N tm ra port 999. Qu 2! nh"ng mnh c>n 2m s( l>n truy c0p!"

Nn ti 2Ti SocketService class nh" sau:





import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketService {
private ServerSocket serverSocket = null;
private int connections = 0;

public void serve(int port) throws Exception {
serverSocket = new ServerSocket(port);
try {
Socket s = serverSocket.accept();
s.close();
connections++;
}
catch (IOException e) {
}
}

public void close() throws Exception {
serverSocket.close();
}

public int connections() {
return connections;
}
}

Nh"ng 2oRn m ny khng chRy, n c[ng chVng bo lXi. Khi ti chRy ph>n test, n bF treo.

"Chuy6n g 2y c?" Ti th?c m?c.

Jerry m<m c"Di. "ThC xem my c thA m ra khng Alphonse. D thC 2i."

"OK, xem thC. Ci ch"$ng trnh test g:i serve 2A tRo ra socket v tip tWc g:i accept. ^!
accept khng tr/ v@ cho 2n khi n c 2"#c m3t truy c0p, v v serve khng h@ tr/ lRi nn
mnh khng h@ c c$ h3i g:i connect."

Jerry g0t 2>u. "V0y th my 2Fnh sCa n th no Alphonse?"

Ti nghE ng#i m3t cht. Ti c>n g:i function connect sau khi g:i accept nh"ng khi mnh g:i
accept n khng tr/ v@ cho 2n khi mnh g:i connect. Nhn qua th c v4 khng thA 2"#c.

"Khng ph/i l khng 2"#c 2u Alphonse." Jerry c-t ting. "My ch< c>n tRo ra m3t ci
thread."

Ti lRi ngNm nghE thm m3t cht nOa. ng rQi, ti c thA 2Lt ph>n g:i cho vi6c tip nh0n
truy c0p trong m3t thread khc rQi m7i b?t l-y thread 2 v g:i b"7c truy c0p.

Ti ni: "Ti bit l do tRi sao ng ni tRo m nguQn cho socket th vF h$n m3t cht rQi 2."
v ti thay 2Ti 2oRn m nh" sau:









private Thread serverThread = null;

public void serve(int port) throws Exception {
serverSocket = new ServerSocket(port);
serverThread = new Thread(
new Runnable() {
public void run() {
try {
Socket s = serverSocket.accept();
s.close();
connections++;
}
catch (IOException e) {
}
}
}
);
serverThread.start();
}

"SC dWng ci anonymous inner class hay l?m 2 Alphonse." Jerry ni.

"Cm $n." Ti c/m th-y s"$ng s"7ng khi 2"#c g khen. "Nh"ng e n tRo m3t chm 2ui kh<
; cu(i ci function."

"Mnh refactor n sau, 2>u tin cH chRy ci test ci 2."

Ci test chRy Tn nh"ng Jerry c v4 2Um chiu, nh" thA g v&a bF ai ni d(i.

"ChRy ci test l>n nOa xem Alphonse."

Ti vui v4 nh-n nt run v ci test lRi chRy ngon lnh.

"L>n nOa." G ni.

Ti nhn g m3t giy xem thC g c 2a khng. R rng g khng 2a. M?t g dn chLt trn
mn hnh nh" thA g 2ang sUn lng "dribin". Th nn ti nh-n nt m3t l>n nOa v th-y:
"testOneConnection: expected:<1> but was:<0>"

"HSng 2!" ti r ln. "Khng thA no!"

"^, c thA ch7." Jerry ni. "Tao 2ang 2#i n x/y ra."

Ti nh-n nt lin tWc. Trong m"Di l>n c 2n ba l>n h5ng. Khng bit ti c loRn tr khng?
lm sao ch"$ng trnh lRi gi; tr nh" v0y?

"Lm sao ng bit 2"#c v0y Jerry? ng c lin h6 g 2n s-m truy@n Aldebran h;?"

"Khng, tao c vit loRi m ny tr"7c 2y nn bit 2i 2i@u c>n d9 ph5ng. My c thA minh
gi/i chuy6n g x/y ra khng? Suy nghE cho th-u 2o v kd cng 2."

ng l 2au 2>u nh"ng ti b?t 2>u rp t&ng ph>n lRi v7i nhau. Ti 2n b/n phc th/o v vK
ra:





Khi 2 minh gi/i xong, ti t"Dng trnh s9 vW cho Jerry. "TestSocketServer g;i thng 2i6p
serve(999) 2n SocketService. SocketService tRo ServerSocket v serverThread rQi
tr/ v@. Sau 2 TestSocketServer g:i connect phn 2oRn 2 tRo nn client socket. Hai
sockets ny hVn 2 tm th-y nhau b;i v chng ta khng nh0n 2"#c lXi 'could not connect'.
ServerSocket hVn 2 tip nh0n truy c0p nh"ng c lK serverThread ch"a c c$ h3i 2A
chRy. V trong khi serverThread bF c/n, function connect 2ng client socket lRi. K tip
TestSocketServer g;i thng 2i6p 2ng cCa 2n SocketService v phn 2oRn ny 2ng
serverSocket. Khi serverThread c c$ h3i g:i function accept th server socket 2 2ng
m-t."

"Tao nghE my 2ng 2." Jerry ni. "Hai bin c( - tip nh0n v 2ng - thiu 2Qng b3 v h6
th(ng ny dZ h5ng v7i cc trnh t9 x/y ra. Ci ny mnh g:i l tr"Dng h#p dQn 2uTi (race
condition). Chng ta ph/i b/o 2/m th?ng cu3c 2uTi chRy ny."

Chng ti quyt 2Fnh thC nghi6m gi/ thuyt c*a ti bPng cch 2"a vo cc print statement
trong kh(i 'catch' sau khi accept 2"#c g:i. HVn v0y, trong m"Di l>n test, chng ti th-y
thng 2i6p ny ba l>n.

Jerry h5i ti: "Th th lm sao mnh cho unit test chRy 2y?"

"Theo ti nghE, d"Dng nh" ci test khng thA ch< m; client socket rQi 2ng lRi ngay l0p tHc."
Ti 2p "N c>n ph/i 2#i b"7c tip nh0n."

G ni: "Mnh c thA 2#i 100ms tr"7c khi 2ng client socket."

"`a, ch?c l 2"#c nh"ng h$i Y." Ti tr/ lDi.

"Hy xem thC mnh lm cho n chRy 2"#c hay khng ci 2 rQi tnh chuy6n refector sau."

Nn ti thay 2Ti method connect nh" sau:







private void connect(int port) {
try {
Socket s = new Socket("localhost", port);
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
}
s.close();
}
catch (IOException e) {
fail("could not connect");
}
}

Ph>n thay 2Ti cho kt qu/ test 10 trn 10.

"G7m th0t." Ti ni. "Khi mnh 2(i ph v7i nhi@u threads th ph/i d ch&ng tr"Dng h#p dQn
2uTi (race condition). Nh-n nt test nhi@u l>n l m3t thi quen t(t nn t0p."

"Hn l mnh khm ph ra n trong m-y ci test case." Ti ni. "Khng th kh m kim ra
n sau khi h6 th(ng 2 chRy."

Jerry ch< g0t 2>u.

<2n xem ph>n k tip>
The Crafsman 7.
Socket Service 2
Robert C. Martin
Ngy 15 thng 10 2002

L>n tr"7c Alphonse v Jerry kh;i 2>u trn m3t framework java 2$n gi/n hX tr# dFch vW
socket. Test case thH nh-t c*a h: vRch ra tr"Dng h#p dQn 2uTi (race condition) m h: 2
gi/i quyt Tn tho/. ChuXi unit test hi6n tRi 2"#c dNn ; M dn 1 v m nguQn chnh ; M
dn 2.

M dn 1

import junit.framework.TestCase;
import junit.swingui.TestRunner;
import java.io.IOException;
import java.net.Socket;

public class TestSocketServer extends TestCase {
public static void main(String[] args) {
TestRunner.main(new String[]{"TestSocketServer"});
}

public TestSocketServer(String name) {
super(name);
}

public void testOneConnection() throws Exception {
SocketService ss = new SocketService();
ss.serve(999);
connect(999);
ss.close();
assertEquals(1, ss.connections());
}

private void connect(int port) {
try {
Socket s = new Socket("localhost", port);
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
}
s.close();
}
catch (IOException e) {
fail("could not connect");
}
}
}










M dn 2

import java.io.IOException;
import java.net.*;

public class SocketService {
private ServerSocket serverSocket = null;
private int connections = 0;
private Thread serverThread = null;

public void serve(int port) throws Exception {
serverSocket = new ServerSocket(port);
serverThread = new Thread(
new Runnable() {
public void run() {
try {
Socket s = serverSocket.accept();
s.close();
connections++;
}
catch (IOException e) {
}
}
}
);
serverThread.start();
}

public void close() throws Exception {
serverSocket.close();
}

public int connections() {
return connections;
}
}

Sau giD gi/i lao, chng ti tr; lRi v sSn sng tip tc v7i SocketService.

"Chng ta 2 chHng minh 2"#c mnh c thA truy c0p m3t l>n. V0y hy thC truy c0p nhi@u
l>n xem sao." Jerry ni.

"Nghe 2"#c l?m." Ti tr/ lDi. Sau 2 ti vit ci test case nh" sau:

public void testManyConnections() throws Exception {
SocketService ss = new SocketService();
ss.serve(999);
for (int i = 0; i < 10; i++)
connect(999);
ss.close();
assertEquals(10, ss.connections());
}

"OK, ci test ny h5ng." Ti ni.

"Y nh" "7c 2on". Jerry 2p. "Ci SocketService ch< g:i method accept m3t l>n. Chng ta
c>n 2Lt b"7c g:i 2 vo m3t vng lLp."

"Khi no vng lLp 2 ch-m dHt?" Ti h5i.

Jerry nghE ng#i 1 t v ni: "Khi chng ta g:i method close c*a SocketService."

"Nh" th ny chUng?" V ti hi6u 2nh nh" sau:

public class SocketService {
private ServerSocket serverSocket = null;
private int connections = 0;
private Thread serverThread = null;
private boolean running = false;

public void serve(int port) throws Exception {
serverSocket = new ServerSocket(port);
serverThread = new Thread(
new Runnable() {
public void run() {
running = true;
while (running) {
try {
Socket s = serverSocket.accept();
s.close();
connections++;
}
catch (IOException e) {
}
}
}
}
);
serverThread.start();
}

public void close() throws Exception {
running = false;
serverSocket.close();
}
}

Ti chRy ci test v c/ hai 2@u 2Rt.

"T(t." Ti ni. "By giD chng ta c thA truy c0p bao nhiu ty thch. Khng may ci
SocketService chVng lm g nhi@u khi mnh truy c0p 2n n. N ch< 2ng lRi m thi."

"`a, 2Ti n 2i." Jerry ni. "Mnh hy bu3c SocketService g;i thng 2i6p "Hello" mXi khi
chng ta truy c0p 2n n."

Ti khng c>n chuy6n ny cho l?m. Ti ni: "TRi sao mnh lm bBn ci SocketService bPng
thng 2i6p "Hello" ch< 2A tho/ mn ci test c*a mnh? SocketService c thA g;i thng 2i6p
th t(t nh"ng mnh khng mu(n thng 2i6p ny l m3t ph>n c*a m nguQn
SocketService!"

"ng th!" Jerry 2Qng . "Mnh mu(n thng 2i6p 2"#c ch< 2Fnh v xc th9c do ci test."

"Mnh lm sao 2y?" Ti h5i.

Jerry m<m c"Di 2p: "Chng ta dng ci Mock Object pattern. Ni m3t cch ng?n g:n,
mnh tRo ra m3t ci interface t& 2 SocketService sK thao tc sau khi nh0n m3t truy c0p.
Chng ta sK c ci test Hng dWng ci interface 2 dng 2A g;i thng 2i6p "Hello". Sau 2,
mnh sK c ci test dng 2A 2:c thng 2i6p t& socket c*a client v xc th9c thng tin 2"#c
g;i 2i m3t cch 2ng 2?n."

Ti chVng bit Mock Object pattern l g c/ v thnh ph>n interface c*a g lm ti b(i r(i.
"ng ch< cho ti 2"#c khng?" Ti h5i.

Th rQi Jerry v7 l-y bn 2nh v b?t 2>u g.

">u tin chng ta vit ci test."

public void testSendMessage() throws Exception {
SocketService ss = new SocketService();
ss.serve(999, new HelloServer());
Socket s = new Socket("localhost", 999);
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String answer = br.readLine();
s.close();
assertEquals("Hello", answer);
}

Ti kiAm tra 2oRn m ny cBn th0n. "OK, ng tRo ra ci g:i l HelloServer v 2"a n vo
trong method serve. Ci ny sK lm h5ng ht cc ci test khc!"

"Hay l?m!" Jerry th(t ln. "i@u 2 c nghEa l chng ta c>n refactor nhOng test khc tr"7c
khi tip tWc."

"Nh"ng cc dFch vW trong hai ci test kia chVng lm g ht." Ti kin.

"T-t nhin l chng lm vi6c - chng 2m s( truy c0p! My c nh7 l my ght m-y ci bin
s( truy c0p 2n th no khng, v n ch< l ph>n phW m thi? By giD mnh sK dYp chng
2i."

"Mnh s?p sCa lm th ?"

"Xem 2y." Jerry c"Di r3. ">u tin chng ta 2Ti hai ci test v thm bin s( connections
vo test case."

public void testOneConnection() throws Exception {
ss.serve(999, connectionCounter);
connect(999);
assertEquals(1, connections);
}

public void testManyConnections() throws Exception {
ss.serve(999, connectionCounter);
for (int i=0; i<10; i++)
connect(999);
assertEquals(10, connections);
}

"K tip mnh tRo ci interface."

import java.net.Socket;
public interface SocketServer {
public void serve(Socket s);
}

"Sau 2 chng ta tRo bin s( connectionCounter v kh;i 23ng n trong constructor c*a
TestSocketServer bPng m3t anonymous inner class 2A n tUng c-p bin s( connections.


public class TestSocketServer extends TestCase {
private int connections = 0;
private SocketServer connectionCounter;

public static void main(String[] args) {
TestRunner.main(new String[]{"TestSocketServer"});
}

public TestSocketServer(String name) {
super(name);
connectionCounter = new SocketServer() {
public void serve(Socket s) {
connections++;
}
};
}
...

"Cu(i cng, chng ta cho n bin dFch tr:n b3 bPng cch thm 2(i s( phW vo method
serve c*a SocketService v bin ci test m7i thnh ph>n ch gi/i (2A n kh5i chRy)."

public void serve(int port, SocketServer server) throws Exception {
...
}

"OK, ti bit ng rQi." Ti ni. "Hai ci test c[ lc ny hVn ph/i h5ng b;i lK SocketService
khng bao giD gy ra method serve t& 2(i s( SocketServer c*a n."

T-t nhin cc ci test 2 h5ng v chnh l do -y.

Ti bit ph/i lm g k tip. Ti v7 l-y bn 2nh v thay 2Ti nh" sau:

public class SocketService {
private ServerSocket serverSocket = null;
private int connections = 0;
private Thread serverThread = null;
private boolean running = false;
private SocketServer itsServer;

public void serve(int port, SocketServer server) throws Exception {
itsServer = server;
serverSocket = new ServerSocket(port);
serverThread = new Thread(
new Runnable() {
public void run() {
running = true;
while (running) {
try {
Socket s = serverSocket.accept();
itsServer.serve(s);
s.close();
connections++;
} catch (IOException e) {
}
}
}
}
);
serverThread.start();
}
...

oRn m ny lm cc test chRy 2"#c.

"Hay l?m!" Jerry ni. "By giD chng ta ph/i lm cho ci test m7i chRy."

Th nn ti tho b5 ph>n ch gi/i cho 2oRn test v bin dFch n. N "la lng" trong ph>n
HelloServer.

", 2ng rQi. Mnh ph/i th9c thi ci HelloServer. N sK phun ra chO "hello" t& socket, ph/i
khng?"

"ng th." Jerry xc nh0n.

Th rQi ti vit ci class m7i trong hQ s$ TestSocketServer.java nh" sau

class HelloServer implements SocketServer {
public void serve(Socket s) {
try {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("Hello");
}
catch (IOException e) {
}
}
}

Cc test 2@u Tn.

"C[ng dZ thi." Jerry ni.

"`a. Ph>n pattern Mock Oject kh hOu dWng. N cho php ta duy tr cc m dng 2A test
trong k hoRch test. SocketService khng bit g c/."

"Cn hOu dWng h$n th." Jerry tr/ lDi. "Cc servers th0t c[ng sK Hng dWng interface
SocketServer."

"Ti bit." Ti tr/ lDi. "Th0t l th khi th-y t& nhu c>u tRo ra m3t unit test 2"a mnh 2n chX
tRo ra m3t 2Q hnh hOu dWng m3t cch tTng qut."

"i@u ny th"Dng x/y ra m." Jerry ni. "Tests l ng"Di dng 2. Nhu c>u dng tests
th"Dng trng h#p v7i nhu c>u c*a ng"Di dng th0t s9."

"Nh"ng tRi sao lRi g:i n l Mock Object?"

"Hy nghE trn ph"$ng di6n th ny. HelloServer dng 2A thay th cho, hoLc l m3t b/n
nhp, c*a m3t server th0t. Ci pattern ny cho php chng ta thay th b/n nhp c*a
chuy6n test vo m nguQn Hng dWng th0t s9."

" ra v0y." Ti 2p. "Thi th by giD mnh nn d:n dYp ph>n m ny v xo b5 ci bin s(
truy c0p v dWng kia v0y."

"Qng ."

Th rQi chng ti d:n dYp thm m3t cht nOa v ngh< gi/i lao. Kt qu/ c*a SocketService
nh" sau:





import java.io.IOException;
import java.net.*;

public class SocketService {
private ServerSocket serverSocket = null;
private Thread serverThread = null;
private boolean running = false;
private SocketServer itsServer;

public void serve(int port, SocketServer server) throws Exception {
itsServer = server;
serverSocket = new ServerSocket(port);
serverThread = makeServerThread();
serverThread.start();
}

private Thread makeServerThread() {
return new Thread (
new Runnable() {
public void run() {
running = true;
while (running) {
acceptAndServeConnection();
}
}
}
);
}

private void acceptAndServeConnection() {
try {
Socket s = serverSocket.accept();
itsServer.serve(s);
s.close();
}
catch (IOException e) {
}
}

public void close() throws Exception {
running = false;
serverSocket.close();
}
}

<2n xem ph>n k tip>
The Crafsman 8.
Testing in Sync

"Testing in Synch", tay h-c vi.c c1a chng ta h-c +'4c m6t +i7u: cc tests c m8c
+ch ph8c v8 l9n h5n l ch; +5n thu=n ch>ng minh l m ngu?n ch,y +'4c: "tests"
l m6t d,ng ti li.u th)c hnh v gio d8c.

Robert C. Martin

Thang my t>ng 17 lRi h5ng nn ti ph/i dng trW tu3t. Trong lc tWt xu(ng, ti b?t 2>u
ngNm nghE 2n chuy6n 2ng ghi nh0n l dng tests nh" m3t thH 2Q ngh@ thit k. Chm
2?m trong suy nghE, ti h$i v nn va ci ch5 vo trW thang v7i sHc d3i Coriolis [*]. Khi ti
gLp Jerry trong phng th nghi6m n vNn cn 2au nhi.

"My sSn sng thC ci test dng 2A g;i thng 2i6p 'hello' xuyn qua sockets ch"a?" g h5i.

"HiAn nhin rQi", ti 2p.

Chng ti b5 ph>n phW ch (comment) c*a method TestSendMessage.

public void testSendMessage() throws Exception {
SocketService ss = new SocketService();
ss.serve(999, new HelloServer());
Socket s = new Socket("localhost", 999);
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String answer = br.readLine();
s.close();
assertEquals("Hello", answer);
}

"Nh" d9 2on, 2oRn ny khng bin dFch 2"#c" Jerry pht biAu. "Mnh c>n ph/i vit ci
HelloServer."

"Ti nghE ti bit ph/i lm g," ti tr/ lDi. "HelloServer l ci class th&a h";ng t&
SocketServer v Hng dWng method server() 2A g;i thng 2i6p 'hello' qua socket."

Ti v7 l-y bn 2nh v 2i@u ch<nh nhm TestSocketServer.java nh" sau:

class HelloServer implements SocketServer {
public void serve(Socket s) {
try {
OutputStream os = s.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println("Hello");
}
catch (IOException e) {
}
}
}

oRn ny bin dFch 2"#c v cc tests 2@u 2Rt ngay l>n 2>u.

"Ngon lnh," Jerry ni. "By giD chng ta c thA g;i m3t thng 2i6p qua socket."

Ti bit Jerry b?t 2>u nghE 2n chuy6n refactoring v ti mu(n qua mLt g. Xem xt 2oRn
m kd l"Ing, ti nh7 g c 2@ c0p 2n v-n 2@ trng lLp.

"C m3t s( m trng lLp trong cc ph>n unit tests," ti ni. "Trong mXi ci test mnh tRo v
2ng ci SocketService. Chng ta nn b5 n 2i."

"Tinh m?t l?m!" Jerry phn. "Hy dDi n vo cc function Setup v Teardown." G tm l-y
bn 2nh v thay 2Ti nh" sau:

private SocketService ss;

public void setUp() throws Exception {
ss = new SocketService();
}

public void tearDown() throws Exception {
ss.close();
}

Sau 2 g b5 tr:n b3 cc dng ss = newSocketService(); and ss.close(); trong ba ci tests.

"Xem 2"#c h$n 2," ti ni. "Hy thC xem mnh c thA g;i m3t thng 2i6p ng"#c lRi khng."

"Tao c[ng nghE y nh" v0y," Jerry tr/ lDi. "V tao c m3t cch lm chuy6n 2."
G b?t 2>u 2nh m3t test case m7i:

public void testReceiveMessage() throws Exception {
ss.serve(999, new EchoService());
Socket s = new Socket("localhost", 999);
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
OutputStream os = s.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println("MyMessage");
String answer = br.readLine();
s.close();
assertEquals("MyMessage", answer);
}

"Eo i! T;m th," ti cPn nhPn.

"`a, 2ng th0t," Jerry th nh0n. "Hy lm cho n chRy ci 2 rQi mnh d:n dYp n sau.
Chng ta khng mu(n m7 l3n x3n 2 ; 2y lu! My bit tao 2Fnh lm g ph/i khng?"

"Vng," Ti tr/ lDi. "EchoService sK nh0n m3t thng 2i6p t& socket v g;i ng"#c lRi ngay.
B;i th, 2oRn test c*a ng ch< g;i MyMessage; rQi 2:c n lRi."

"ng rQi. mu(n thC ngoy ph>n EchoService khng?" "T-t nhin," ti ni m3t cch hUm
h;.









class EchoService implements SocketServer {
public void serve(Socket s) {
try {
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
OutputStream os = s.getOutputStream();
PrintStream ps = new PrintStream(os);
String token = br.readLine();
ps.println(token);
}
catch (IOException e) {
}
}
}

"Oi," ti ni. "LRi thm m3t m7 m x-u x. Mnh cH tRo cc objects PrintStream v
BufferedReader t& socket. Chng ta c>n ph/i d:n dYp m7i 2"#c."

"Mnh sK lm chuy6n 2 ngay sau khi m-y ci test chRy ngon lnh," Jerry 2p, trong khi
nhn ti c v4 kb v:ng.

"Oh!" ti r ln. "Ti qun chRy ci test." X-u hT, ti nh-n nt test v theo di n chRy.
"C[ng khng kh l?m," ti ni. "By giD hy vHt ph>n m x-u x -y 2i." Ti rt nhi@u
functions ra kh5i EchoService.

class EchoService implements SocketServer {
public void serve(Socket s) {
try {
BufferedReader br = getBufferedReader(s);
PrintStream ps = getPrintStream(s);
String token = br.readLine();
ps.println(token);
}
catch (IOException e) {
}
}
private PrintStream getPrintStream(Socket s) throws IOException {
OutputStream os = s.getOutputStream();
PrintStream ps = new PrintStream(os);
return ps;
}
private BufferedReader getBufferedReader(Socket s) throws IOException {
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
return br;
}
}

"oRn ny c/i tin method EchoService," Jerry ni, "nh"ng n kh r(i ci class. H$n nOa, n
khng gip g cho function testRecieveMessage, 2 c[ng l m3t 2iAm khng 2Yp. ThC nghE
getBufferedReader v getPrintStream c nPm 2ng chX khng?"

"y sK l v-n 2@ lLp lRi," ti ni. "Ai mu(n dng SocketService ph/i sK chuyAn socket
thnh BufferedReader v PrintStream."

"Chnh l cu tr/ lDi!" Jerry 2p lRi. "Cc methods getBufferedReader v getPrintStream qu/
th9c thu3c v@ SocketService."

Ti dDi hai functions vo class SocketService v thay 2Ti EchoService theo 2.

public class SocketService {
[...]
public static PrintStream getPrintStream(Socket s) throws IOException {
OutputStream os = s.getOutputStream();
PrintStream ps = new PrintStream(os);
return ps;
}
public static BufferedReader getBufferedReader(Socket s)throws IOException{
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
return br;
}
}

class EchoService implements SocketServer {
public void serve(Socket s) {
try {
BufferedReader br = SocketService.getBufferedReader(s);
PrintStream ps = SocketService.getPrintStream(s);
String token = br.readLine();
ps.println(token);
}
catch (IOException e) {
}
}
}

Cc tests 2@u chRy. GiO vOng tnh hnh, ti ni: "by giD ti hVn c thA sCa 2Ti method
testReceiveMessage lun." Trong lc Jerry quan st, ti thay 2Ti ph>n ny nh" sau:

public void testReceiveMessage() throws Exception {
ss.serve(999, new EchoService());
Socket s = new Socket("localhost", 999);
BufferedReader br = SocketService.getBufferedReader(s);
PrintStream ps = SocketService.getPrintStream(s);
ps.println("MyMessage");
String answer = br.readLine();
s.close();
assertEquals("MyMessage", answer);
}

"`a, coi 2"#c h$n 2," Jerry ni.

"Khng ch< nh" v0y m cc tests 2@u 2Rt," ti gy ln. Th rQi ti nh0n th-y thm m3t 2i@u.
"Ui, c thm m3t ci nOa trong testSendMessage." Ti sCa ci 2 lun.

public void testSendMessage() throws Exception {
ss.serve(999, new HelloServer());
Socket s = new Socket("localhost", 999);
BufferedReader br = SocketService.getBufferedReader(s);
String answer = br.readLine();
assertEquals("Hello", answer);
}

Cc tests vNn chRy. Ti ngQi tBn mBn xt lRi class TestSocketServer, tm xem c g loRi b5
2"#c khng.

"My xong ch"a?" Jerry h5i.

Ti g0t 2>u.

"T(t," g 2p lRi. "My s?p xFt khi lX tai 2."

"Ti c m3t cu h5i. Chng ta chVng thay 2Ti t no ci SocketService. Mnh thm
testSendMessage v testRecieveMessage v c/ hai 2@u chRy. Mnh lRi t(n r-t nhi@u thDi gian
2A vit m-y ci test v lo chuy6n refactoring. Lm nh" th c l#i g cho mnh nh<? Chng ta
chVng thay 2Ti m nguQn chnh c*a s/n phBm g ht!"

Jerry nh"7n my. "B3 my nghE l getBufferedReader v getPrintStream 2ng 2"#c 2"a vo
s/n phBm?" M-y ci ny kh t>m th"Dng; chng ch< hX tr# cho m-y ci test m thi.

Jerry th; di. "Nu my dnh vo project ny, tao ch< cho my m-y ci test, chng dRy my
2"#c nhOng g?"

Ti h:c 2"#c g t& m-y ci test 2? Ti h:c 2"#c cch tRo SocketService v g?n
SocketServer t& 2. Ti c[ng h:c 2"#c cch g;i v nh0n thng 2i6p. Ti h:c 2"#c tn v vF
tr c*a cc classes trong framework v cch xC dWng chng. " ng mnh vit m-y ci tests
ny 2A lm v dW cho nhOng ng"Di khc?"

" l m3t ph>n l do, Alphonse. NhOng ng"Di khc sK c thA 2:c m-y ci test ny v xem
cch lm vi6c c*a m nguQn. H: c[ng c thA lm vi6c xuyn qua l gi/i. H$n th, h: sK c
thA bin dFch v thao tc cc ci tests ny v chHng minh v7i chnh h: rPng cch l gi/i c*a
chng ta 2ng thuyt phWc. Cn nhi@u 2i@u h$n th nOa," g ni tip, " nh"ng chng ta 2A
dnh v-n 2@ ny cho m3t dFp khc."

Ci ch5 ti vNn cn 2au nhHc nn ti m&ng l thang my 2 chOa. Trong khi 2i thang my,
ti khng ng&ng nghE ng#i: "Tests l m3t dRng ti li6u-c thA bin dFch 2"#c, c thA thao tc
v lun lun 2Qng b3."



[*] Cn c tn g:i l Coriolis effect g:i theo tn c*a kd s" - nh ton h:c Php Gustave-Gaspard Coriolis. \ 2y
d"Dng nh" tc gi/ m t/ hnh 23ng tay h:c vi6c m c3t tWt xu(ng v trong khi tWt xu(ng, anh ta ; trRng thi xoay
vng trn c3t nn bF "Coriolis force". Xem thm chi tit ;: http://zebu.uoregon.edu/~js/glossary...fect.html. v
http://satftp.soest.hawaii.edu/ocn620/coriolis/ - ch thch c*a ng"Di dFch.

The Crafsman 9.
Dangerous Threads

Cu chuy,n tay h+c vi,c trE tu6i cAa chng ta h+c 8"7c bi nFm lng: Khng 8G cc threads
8eo lAng lHng - ph<i n=m ch=c b/n kiGm sot b"#c k.t thc cIng nh" 8iGm kh9i t/o cAa
chng. Phn 9.

Robert C. Martin

Sng nay chic PDA khe khK 2nh thHc ti d0y. C( trt c$n ngi ng* t& no b3, ti t?t my
bo thHc v m vo phng t?m. Trong khi vi phun kb c: v xoa bp thn thA, tm tr ti
vBn v$ 2i vo nhOng bin c( ngy hm tr"7c.

Ti tr; phng lm vi6c lRi sau buTi gi/i lao, trong 2>u vNn nghE ng#i v@ gi trF th9c s9 t& cc
c thC nghi6m. Jerry 2ang 2#i ti, g ni: "Tao m&ng l my tr; lRi. Tao 2ang hon t-t ci
"test case" k tip 2y. Xem qua ci 2i v thC 2on mWc 2ch c*a n l g."

public void testMultiThreaded() throws Exception {
ss.serve(999, new EchoServer());
Socket s1 = new Socket("localhost", 999);
BufferedReader br = SocketService.getBufferedReader(s1);
PrintStream ps = SocketService.getPrintStream(s1);

Socket s2 = new Socket("localhost", 999);
BufferedReader br2 = SocketService.getBufferedReader(s2);
PrintStream ps2 = SocketService.getPrintStream(s2);

ps2.println("MyMessage");
String answer2 = br2.readLine();
s2.close();

ps.println("MyMessage");
String answer = br.readLine();
s1.close();

assertEquals("MyMessage", answer2);
assertEquals("MyMessage", answer);
}

"N h$i phHc tRp m3t cht nh"ng hnh nh" ng mu(n chHng minh l SocketService c thA
2(i ph v7i hai mRch n(i cng m3t lc."

"ng v0y," Jerry tr/ lDi. "My c nh0n ra l mRch n(i thH nh-t lRi 2ng sau cng khng?"

"Khng, nh"ng ng ni ti m7i th-y 2. ng lm th 2A lm chi v0y?"

"Tao mu(n hai phin truy c0p cng m; lin tWc," Jerry 2p.

"TRi sao?" Ti b(i r(i h5i lRi. "B;i v khi -y method serve trong class SocketService sK ph/i
2i vo hai l>n trong hai threads khc nhau, tr"7c khi c/ hai c c$ h3i kt thc," Jerry tip
tWc. "Khi m3t hm 2"#c g:i vo h$n m3t l>n tr"7c khi n kt thc, ci ny g:i l reentrant."

"Nh"ng sao ng lRi mu(n test n lm g?" ti cH khUng khUng h5i tip.

"B;i v cc hm reentrant th"Dng 2em lRi cho mnh nhOng s9 c( r-t l th," Jerry m<m c"Di.
Ti khng hiAu nTi 2i@u ny nh"ng ti bit ch?c r(t cu3c Jerry sK gi/i thch v-n 2@. "OK" g
ni. "Hy chRy thC ci test 2i."

Ti bin dFch v chRy ci test. Thanh ch< 2Fnh mu xanh l chuyAn 23ng lY lng xuyn qua
khung test cho chng ti bit rPng tr:n b3 nhOng test tr"7c 2y vNn lm vi6c ngon lnh.
Th rQi, tr"7c khi kt thc, ch"$ng trnh bF kh9ng lRi. Ti 2#i vi giy xem thC n c thHc
d0y v hon t-t hay khng nh"ng n hon ton treo lun.

Sau khi nghin cHu m nguQn ; 2oRn SocketService.serve ch&ng m3t pht, ti ni, "Hy
xem 2oRn lLp ny."

while (running) {
try {
Socket s = serverSocket.accept();
itsServer.serve(s);
s.close();
}
catch (IOException e) {
}
}

"itsServer.serve khng tr; lRi 2A b?t l-y mRch n(i thH nh," ti tip tWc. "MRch n(i thH nh-t
bF treo trong 2oRn EchoServer 2#i mnh g;i 2n m3t thng 2i6p. B;i th chng ta khng bao
giD 2i ht vng lLp 2A g:i accept cho mRch n(i socket thH nh."

Jerry c"Di rRng rI. "Kh l?m! by giD mnh lm sao v7i n 2y?" "Chng ta c>n 2"a
itsServer.serve trong thread ring c*a n 2A ci vng lLp 2 c c$ h3i tr; lRi m khng ph/i
2#i n."

"LRi 2ng l>n nOa!" g m<m c"Di. "Dm ch:c n m3t pht khng?"

Ti v7 l-y bn phm v 2Ti method SocketService.serve nh" sau:

while (running) {
try {
Socket s = serverSocket.accept();
new Thread(new ServiceRunnable(s)).start();
}
catch (IOException e) {
}
}

K tip ti thm m3t inner class m7i bn trong SocketService g:i l ServiceRunnable:

class ServiceRunnable implements Runnable {
private Socket itsSocket;
ServiceRunnable(Socket s) {
itsSocket = s;
}
public void run() {
try {
itsServer.serve(itsSocket);
itsSocket.close();
}
catch (IOException e) {
}
}
}

"V0y l 2* rQi," ti ni. Ti nh-n nt test v 2"#c 2@n b bPng kt qu/ md mn. "Nh-n nt
thm vi l>n xem sao," Jerry 2@ nghF. "i thi, 2&ng ch$i m-y tr ny," ti c9 n9, nh7 2n
ci chHng kh0p khiZng l>n 2>u tin chng ti kh;i s9. Ti miZn c"Ing chRy ph>n test thm
vi l>n. HiAn nhin ti th-y ngay chX h5ng:

1) testMultiThreaded(TestSocketServer)
java.lang.NullPointerException
at SocketService.close(SocketService.java:32)
at TestSocketServer.
(TestSocketServer.java:30)

"Que tha ma b?t g 2y?" ti nhUn nh nhn dng 32 c*a SocketService.java

30 public void close() throws Exception {
31 running = false;
32 serverSocket.close();
33 }

"HSng m3t pht," ti ch(ng ch. "Lm sao c thA bF null pointer exception chX 2 2"#c c$
chH?" Ti ko ln ph>n TestSocketServer ; dng 30:

29 public void tearDown() throws Exception {
30 ss.close();
31 }

"V l. TearDown 2ng SockerService nh" gi/ 2Fnh nh"ng ci serverSocket lRi null l th
no? Nu serverSocket l null th mnh 2 dnh ngay lXi t& 2oRn testMultiThreaded ch7
khng ph/i trong 2oRn tearDown."

Jerry hVn c/m th-y hOu l b;i g ni, "`a."

"Jerry, ci que g 2y? chVng nghEa l g c/," ti cPn nhPn. "Ci bin serverSocket khng thA
l null 2"#c."

"Alphonse," Jerry ni nh5 nhY. "Hy suy nghE pht ch(c. TrRng thi cc threads th no?"
"H;?" ti khng b?t kFp g. "Cc ci threads," g lLp lRi m3t cch kin nhNn. "Cc threads
ny lm g khi tearDown 2"#c g:i?"

Ti suy nghE v-n 2@ ny ch&ng m3t pht. R rng ph>n test case 2Rt; khng th tearDown
2 khng 2"#c g:i. i@u ny c nghEa l c/ hai mRch n(i socket 2"#c tip nh0n v
serverThread 2 2i xuyn vng lLp hai l>n. serverThread c thA chLn c g:i tip nh0n l>n
thH ba hoLc gi/ n ch"a tr; lRi hm kh;i 23ng dng 2A kch thread ServiceRunnable thH nh.

Thread 2>u c*a ServiceRunnable 2 vo EchoServer ci ny 2 2"#c 2:c v vit thng 2i6p
nh"ng n c thA ch"a bF kt liZu. N c thA 2#i ph>n println g;i thng 2i6p ng"#c lRi t&
ph>n test case, nh"ng thread thH nh c*a ServiceRunnable hVn c 2 thDi gian 2A kt thc:
n 2 nh0n v g;i thng 2i6p c*a n 2 lu.

Ti gi/ng gi/i t-t c/ m:i 2i@u v7i Jerry v g lLng lK g0t 2>u. "Vng," g ni. "Tao c[ng
phn tch nh" th." "V0y th sao lRi c null pointer exception?" ti h5i, vNn cn cht cUng
thVng. "Tao ch/ bit," g rWt vai. "Nh"ng s9 th0t l n bF 2T vI khi mnh 2ng ci
serverSocket lm tao nghE l mnh 2A cho m3t vi thread no 2 chRy lm /nh h";ng 2n
th" vi6n socket." " ng l c bug trong b3 th" vi6n socket?" ti r ln. Jerry ch< dn m?t
vo mn hnh v ni, "tao khng ch?c; c lK mnh dng khng 2ng. Hy 2i qua m3t vi thC
nghi6m. i@u g x/y ra nu ci serverThread t& ph>n test tr"7c ch"a 2ng ngay khi chng
ta th9c thi testMultiThreaded? V rQi, khi ci close() c*a serverThread tr"7c cu(i cng c[ng
th9c thi, ci ny /nh h";ng th no 2 2n phn 2oRn close c*a testMultiThreaded. Mnh
thC nghi6m gi/ thuyt ny sao 2y?"

Ti ph/i p 2Lt nhOng khi ni6m ny t&ng ci m3t trong no - nh" th"Dng l6, Jerry 2i tr"7c
ti nhi@u b"7c. Nh"ng m3t lc sau, ti g0t 2>u v 2@ nghF, "chng ta c thA 2#i ; ph>n cu(i
c*a tearDown 2A n?m ch?c l serviceThread 2ng hon ton." Jerry nghE ng#i m3t giy. V7i
v4 mLt rRng rI g ni, " kin hay 2! nu gi/ thuyt c*a mnh 2ng, ph>n thay 2Ti ny
hVn ph/i lm cho cc ci test 2Rt m:i l>n."

Ti thay 2Ti nh" sau v chRy ci test vi chWc l>n. Hon ton khng bF h5ng nOa.

public void tearDown() throws Exception {
ss.close();
Thread.sleep(200);
}

Jerry m<m c"Di v ni, "OK, 2 l m3t ci test 2A tho/ mn gi/ thuyt c*a chng ta. Tr;
ngRi ny d"Dng nh" l m3t thH /nh h";ng no 2 giOa m-y ci test v khng bF lXi m3t
cch cW thA v7i testMultiThreaded, dNu n khng gi/i thch l do tRi sao chng ta khng th-y
lXi ny tr"7c 2y. Nh-t 2Fnh c v-n 2@ g 2 v7i testMultiThreaded lm l3 ra trRng thi ny."

Ti h$i o/i v7i ci thay 2Ti cu(i: "Mnh khng thA 2A ci sleep trong 2, 2ng khng?
khng ph/i l gi/i php ph/i khng?" ti h5i. "Khng, nh-t 2Fnh khng - n ch< l m3t thH
thC nghi6m m thi. em n ra 2i," Jerry tr/ lDi.

Ti b5 n ra v kiAm nghi6m khng c lXi. Th rQi 2i@u g 2 n/y ra trong 2>u ti. "Jerry, gi/
thuyt c*a mnh khng thA 2ng 2"#c. Server sockets ph/i c kh/ nUng 2Qng thDi m; v
2ng trong h6 2i@u hnh, ph/i khng? m-y ci test c*a mnh khng lm g b-t th"Dng. ti
l, th" vi6n socket ch?c ph/i bF vI nLng n@ nu n gin 2oRn quy trnh 2ng m; th<nh
tho/ng bF chQng ln nhau."

"Th" vi6n ny 2"#c dng 2 lu. Tao khng nghE l n bF vI 2u," Jerry ng-m ngoVng.
"Nh-t 2Fnh ph/i c g 2Lc bi6t trong cch chng ta vit m-y ci test lm cho th" vi6n ph/n
Hng nh" th ny." "C thA no do chng ta dng cng m3t cTng s(?" ti h5i.

Ti 2Ti tr:n b3 cc test dng cTng s( khc nhau. Sau khi qua hng chWc test, ti ni, "n sK
khng h5ng. V-n 2@ nPm ; chX nhi@u tests cng dng m3t cTng s(." "y l 2i@u r-t l
th," Jerry tr/ lDi. "i@u 2 gi/i thch l do tRi sao mnh khng th-y lXi ny trn nhOng h6
th(ng khc. Cc h6 th(ng khng dng cng m3t cTng s(."

Ti lRi th-y o/i nOa. "Jerry, 2y c[ng ch"a ph/i l gi/i php t(t cho mnh. Chng ta ph/i tm
cch lm sao cho SocketService 2A ngUn ng&a tr; ngRi ny, ph/i khng?" "Tuy6t 2(i l nh"
v0y rQi Alphonse. V0y th tin hnh 2i v 2A cTng s( y nh" c[ v tnh thC mnh ph/i lm g."

Ngay khi test c lXi tr; lRi, ti nhn Jerry, 2#i chD. "OK, mnh xC ci que ny sao 2y?"
"Chng ta khng cho php SocketService.close tr; v@ cho 2n khi serverThread kt thc,"
g ni, v7 l-y bn phm v thay 2Ti nh" sau:

public void close() throws Exception {
if (running) {
running = false;
serverSocket.close();
serverThread.join();
}
else {
serverSocket.close();
}
}

Sau hng t test, g ni, "`a, 2u vo 2-y." "Ti 2on bi h:c ; 2y l: 2&ng 2A threads
treo l*ng lVng. Ph/i n?m ch?c mnh kiAm sot 2"#c b"7c kt thc c[ng nh" 2iAm kh;i tRo
c*a chng," Ti ni. " l m3t bi h:c nPm lng r-t t(t," g tr/ lDi. "M3t thread l*ng lVng
c thA gy tai hoR khi my t ngD 2n nh-t."
The Crafsman 10.
Intergation Unbound

Nh@ng vng xoay v gi9i h,n

N.u c m&t vng xoay 8&ng, b/n khng mu0n 86i t1p h+p hi,n c, nh2t l t> m&t thread
khc. Ph<i chJng "design patterns" l gi<i php cho b/n?

Robert C. Martin

MXi thng ti lRi dng 2iAm tm m3t l>n ; 2i quan st. y l 2i@u ngoRi hRng cho tay h:c
vi6c nh" ti, ti khoi Un d"7i vm trDi m; r3ng. Trong lc Un, ti ngNm nghE v@ chuy6n
thread treo l*ng lVng 2"#c chng ti gi/i quyt ngy hm qua. Chng ti sCa ci
serverThread nh"ng lRi 2A tr:n b3 cc thread thu3c serviceRunnable treo tng teng. Ti bit
th no Jerry c[ng mu(n sCa m-y ci -y cho s7m.

ng y nh" v0y, ngay khi ti b"7c vo phng lm vi6c, Jerry 2 mang m-y ci test case
trn mn hnh nh" sau:

public void testAllServersClosed() throws Exception {
ss.serve(999, new WaitThenClose());
Socket s1 = new Socket("localhost", 999);
Thread.sleep(20);
assertEquals(1,WaitThenClose.threadsActive);
ss.close();
assertEquals(0, WaitThenClose.threadsActive);
}

"ng ph/i ch?c Un tr:n b3 nhOng ci SocketServers 2ng ht ngay khi tr; lRi t& b"7c 2ng
SockeService," ti ni.

"Tao mu(n ch?c Un l mnh khng 2A cho m-y ci servers 2 treo l*ng lSng nh" th," Jerry
tr/ lDi.

"Nh"ng ng ch< test n v7i m3t server thi m," ti 2p lRi. "B3 mnh khng c>n test v7i
nhi@u server hay sao?"

"ng th!" Jerry m<m c"Di. "Nh"ng hy lm xong ci test ny ngon lnh ci 2."

"OK," ti tr/ lDi. "Ti bit cch vit WaitThenClose ra sao rQi."

class WaitThenClose implements SocketServer {
public static int threadsActive = 0;

public void serve(Socket s) {
threadsActive++;
delay();
threadsActive--;
}
private void delay() {
try {
Thread.sleep(100);
}
catch (Interrupted Exception e) {
}
}
}

Jerry g0t g trong lc m nguQn c*a ti hi6n ra trn mn hnh; ci WaitThenClose c*a ti
2ng y nh" g d9 t";ng. Ti bin dFch m nguQn ny v chRy m-y ph>n test, chng h5ng
nh" d9 2on:

1) testAllServersClosed AssertionFailedError:
expected:<0> but was:<1>

Jerry xoa tay v ni, "by giD hy lm cho n 2Rt 2i." G v7i l-y bn phm nh"ng ti c/n g
lRi. "Ti nghE l ti c m3t kin". Th nn, trong khi Jerry quan st, ti thay 2Ti 2oRn m
nh" sau:

private LinkedList serverThreads = new LinkedList();

public void serve(int port, SocketServer server) throws Exception {
itsServer = server;
serverSocket = new ServerSocket(port);
serverThread = new Thread(
new Runnable() {
public void run() {
running = true;
while (running) {
try {
Socket s = serverSocket.accept();
Thread serverThread = new Thread(new ServiceRunnable(s));
serverThreads.add(serverThread);
serverThread.start();
}
catch (IOException e) {
}
}
}
}
);
serverThread.start();
}

public void close() throws Exception {
if (running) {
running = false;
serverSocket.close();
serverThread.join();
for (Iterator i = serverThreads.iterator(); i.hasNext();) {
Thread thread = (Thread) i.next();
serverThreads.remove(thread);
thread.join();
}
}
else {
serverSocket.close();
}
}

Khi m nguQn 2"#c bin dFch, Jerry nhUn nh. "V0y 2"#c khng?" ti h5i.

"Hy xem no," g tr/ lDi. "ChRy thC ci test xem sao."

Khi chRy ci test, bF m3t lXi khc th"Dng:

1) testOneConnection java.util.ConcurrentModificationException

"Ci g v0y?" ti h5i.

"My lm vI lu0t 2, Alphonse," Jerry ni. "Khng bao giD thm hoLc b7t t& m3t ci list
trong khi my c m3t vng xoay 23ng."

"T-t nhin rQi!" ti ni m3t cch ng"#ng ngng. "Ok, nh"ng chuy6n ny dZ sCa thi, b;i v
ti khng c>n ph/i tho b5 ci ci thread t& list." Ti b5 dng remove v chRy 2oRn test lRi.
"! by giD th n chRy."

Jerry g0t 2>u nh"ng nhn ti chPm chLp m3t cch chD 2#i. "G h;?" ti go ln sau nCa pht
chFu 29ng kiAu nhn c*a g. "My vNn 2ang thay 2Ti ci list trong khi vng xoay Hng 23ng,"
g phn.

"V0y sao?" ti qu/ th0t b(i r(i. "Ch< c m3t n$i duy nh-t ci list 2"#c thay 2Ti, v 2 l n$i
thread 2"#c thm vo trong running loop. Lm sao n 2"#c g:i trong khi vng xoay 23ng?"

"C thA 2"#c," Jerry ni. "C g:i 2A tip nh0n c thA ; tnh trRng ch9c tr; lRi ngay khi my
2i vo vng xoay. Khi vng xoay chLn m3t c n(i (join), ph>n tip nh0n sK tr; lRi v thm
m3t thread nOa vo list."

"OK, nh"ng mnh test chuy6n 2 2"#c khng?" ti h5i.

"Mnh c thA lm 2"#c chuy6n 2 nh"ng chVng ch g," Jerry tr/ lDi. "Ho ra ; m3t n$i khc
n$i my sK thay 2Ti ci list trong khi vng xoay m; ra."

"C ?"

"`a, my s?p sCa thm n vo 2," Jerry m<m c"Di. G ni tip, "C bao nhiu thread trong
list 2 v0y?"

"C/ l[... eo i!" ti vX trn. "Ti nn b5 ci thread ra kh5i list khi n 2 hon thnh cng
tc! khng th, cc thread 2 hon t-t sK 2eo tng teng trong list." Ti v7 l-y bn phm v
thay 2Ti nh" sau:

class ServiceRunnable implements Runnable {
private Socket itsSocket;

ServiceRunnable(Socket s) {
itsSocket = s;
}

public void run() {
try {
itsServer.serve(itsSocket);
serverThreads.remove(Thread.currentThread());
itsSocket.close();
}
catch (IOException e) {
}
}
}

" h, by giD n lRi h5ng tip," ti ni. "ng ni 2ng l?m - vi ci thread hon t-t tr"7c
khi vng xoay ch-m dHt. Cha ch/, vng xoay " kin" v7i cc c0p nh0t lin 27i qu/ l 2i@u
th0t hay!"

"ng th," Jerry g0t 2>u. "By giD 2A tao ch< m cch tao trF n nh" th no."


public void close() throws Exception {
if (running) {
running = false;
serverSocket.close();
serverThread.join();
while (serverThreads.size() > 0) {
Thread t = (Thread)serverThreads.get(0);
serverThreads.remove(t);
t.join();
}
}
else {
serverSocket.close();
}
}

"RQi!" Jerry ni. "By giD th m-y ci test hVn ph/i 2Rt."

"Ti bit rQi," ti th(t ra. "Thay v dng vng xoay, ng ch< ko ph>n tC thH nh-t ra kh5i list
v tip tWc lLp lRi cho 2n khi list tr(ng rXng."

"ng 2," Jerry tr/ lDi. "BPng cch 2, khng vng xoay no m; ra qu lu. Cc c n(i
(joins) c thA m-t thDi gian, cho nn 2A vng xoay m; qu lu khi cc thread khc thay 2Ti
list l 2i@u khng hay."

"Th, mnh xong vi6c rQi sao?" Jerry l?c 2>u. "Khng, vNn cn hiAm nguy," g c/nh bo.

" ng th no v0y?" ti r ln, th-t v:ng. "Ch7 c s9 c( g nOa 2y?"

"Alphonse, mXi khi my c m3t container bF nhi@u thread thay 2Ti, r-t c c$ h3i hai thread
va nhau bn trong container. M3t thread c thA thm m3t ph>n tC trong khi m3t thread
khc lRi xo ph>n tC khc. Khi tr"Dng h#p ny x/y ra, container c thA bF h5ng v nhOng
chuy6n kb qui c thA x/y ra."

"V0y ng l mnh nn 2Qng b3 ho truy c0p 2n container?" ti h5i.

"Chnh xc," Jerry tr/ lDi. "Chng ta c>n n?m ch?c khng c thread no khc c thA truy c0p
container trong khi n bF thay 2Ti."

"$n gi/n thi," ti ni trong khi gom lRi 2oRn thm v hai 2oRn b7t v7i bi6n thHc 2Qng b3
(serverThreads) {...}. Ti chRy m-y ci tests v chng 2Rt ht.

" l m3t cch," Jerry ni v7i nW c"Di trn mLt, "nh"ng n h$i bF dZ dnh lXi. Nu c ai
ch<nh sCa m nguQn v 2Lt vo m3t ci add hay remove, h: ph/i nh7 2Lt ph>n 2Qng b3 ho
vo. Nu h: qun, nhOng chuy6n tQi t6 c thA x/y ra."

Ti ngNm nghE v-n 2@ -y vi pht v xc 2Fnh g ni 2ng - nu chng ta khng c>n ph/i
gom cc dng thao tng list bPng bi6n thHc 2Qng b3 th c lK t(t h$n. "Th cch no t(t h$n
v0y?"

"Tao ch< cho my xem." G l-y bn phm v tho b5 cc dng synchronized c*a ti. Sau 2
g thay 2Ti thm m3t dng m nOa - dng tRo LinkedList ngay lc 2>u:

private List serverThreads = Collections.synchronizedList(new LinkedList());

Jerry bin dFch m nguQn v chRy tr:n b3 cc ci test. M:i s9 Tn c/. Sau rQi g h5i, "My
bit g v@ design patterns h/ Alphonse? C bao giD my nghe 2n Decorator pattern ch"a?"

"T-t nhin l ti nghe v@ chng rQi, v ti c[ng th-y sch ni v@ chuy6n ny trn gi sch
c*a thin hR, nh"ng ti khng bit nhi@u l?m v@ chng."

Jerry nhn ti nghim kh?c ni, "v0y th 2n lc m nn b?t 2>u h:c v@ chng m3t cch
nghim ch<nh 2i. My c thA m"#n sch c*a tao v nghin cHu n nu thch. >u tin tao
mu(n my 2:c ch"$ng ni v@ Decorator pattern. Hm synchronizedList mnh v&a g:i 2A gi
ci LinkedList trong m3t Decorator. M:i c g:i 2n LinkedList 2@u 2"#c n 2Qng b3 ho c/."

"Nghe 2ng l m3t gi/i php hay," ti 2p. "`a, m my c[ng ph/i nh7 2Qng b3 ho cW thA
nhOng n$i dng vng xoay." Jerry cau my.

"V0y sao?" Ti h5i. " ng vng xoay khng 2"#c 2Qng b3 ho trong danh sch 2Qng b3
sao?"

"TANSTAAFL," g tr/ lDi.

"H;?" ti h5i, th3n ng"Di ra. Khng bit c ph/i g ni ting Clangrish hay g 2y.

"TANSTAAFL," g lLp lRi theo kiAu kh(ng ch; rQi g m<m c"Di. "There Ain't No Such Thing
As A Free Lunch" (Khng h@ c ci g:i l buTi Un tr"a miZn ph).

"Ti bit," ti m<m c"Di trong khi r/o b"7c v@ buQng c*a ti.

(Cn nOa.....)
The Crafsman 11.
Forget The main()
Qun +i hm main()

Chng ti 8 d*ng xong ch"$ng trnh 8G g+i phn bin dLch SMC t> xa, g9i m ngu@n 8.n
server v g9i ng"7c l/i h@ s$ 8 bin dLch. Th. nh"ng t/i sao Jerry l/i khJng khJng test m
ngu@n lE tE?

Robert C. Martin

Trong 2>u ti cH cn nh?c mi m7 threads treo tng teng trong khi Un mn m (ng
spaghetty m3t cch l$ 2ng. Sau bOa tr"a, ti tr; v@ phng lm vi6c tm Jerry.

"ng C nghE l SocketServer sSn sng 2A dng rQi 2, v by giD ng ta mu(n chng mnh
lm vi6c v7i Hng dWng SMSRemote."

"^, 2ng nh<!" Ti ni. "Th 2 l l do c SocketServer m - mnh 2 d9ng xong ch"$ng
trnh dng 2A g:i ph>n bin dFch SMC t& xa, g;i m nguQn 2n server v g;i ng"#c lRi hQ s$
2 bin dFch."

Jerry nhn ti chD 2#i v h5i, "my nghE mnh kh;i cng sao 2y?"

"Ti nghE l ti c>n bit ng"Di dng sK sC dWng chng ra sao ci 2," ti tr/ lDi.

"Xu-t s?c!" g m<m c"Di. "Kh;i 2>u t& ci nhn c*a ng"Di dng lun lun l m3t 2i@u hay.
Th th cch no l cch 2$n gi/n nh-t ng"Di dng c thA m 2n ti6n ch ny?"

"Anh ta c thA yu c>u m3t hQ s$ no 2 2"#c bin dFch," ti tr/ lDi. "L6nh -y c thA nh"
th ny." ti vit ln t"Dng nh" sau: java SMCRemoteClient myFile.sm

"Coi 2"#c 2," Jerry ni. "Mnh b?t 2>u sao 2y?"

Ti c/m th-y kh vOng tin sau khi lm SocketServer chRy 2"#c, th nn ti v7 l-y bn phm
v b?t 2>u g:

public class SMCRemoteClient {
public static void main(String args[]) {
String fileName = args[0]; }
}
}

"My c ci test cho n khng?" Jerry ng?t ngang.

" ng l sao?" ti h5i m3t cch thiu kin nhNn. "M nguQn ny thu3c dRng l4 t4 - sao
mnh ph/i vit ci test cho n lm chi?"

"Nu my khng vit m3t ci test cho n th lm sao my bit l c c>n hay khng?" g h5i.

Cu h5i -y lm ti kh9ng lRi. "Ti nghE 2i@u -y qu hiAn nhin," sau r(t ti ni.

"V0y sao?" Jerry tr/ lDi. "Tao khng 2"#c thuyt phWc cho l?m. Hy thC m3t l(i khc xem
sao." G v7 l-y bn phm v xo ht m nguQn c*a ti. T9 i trong lng bng ln nh"ng ti
c( dPn n xu(ng. D g c[ng ch< c v5n vYn b(n dng code m thi.

"OK, mnh c>n nhOng hm no 2y?" g h5i. Ti nghE ng#i vi giy v ni, "mnh c>n l-y tn
hQ s$ t& dng l6nh nh"ng ti khng bit ng sK lm sao nu khng c ph>n m nguQn ng
v&a xo m-t."

Jerry nhn ti v7i v4 ch giZu, h?n ni, "tao bit," v b?t 2>u g phm. >u tin g vit m3t
2oRn test framework quen thu3c:

import junit.framework.*;
public class TestSMCRemoteClient extends TestCase {
public TestSMCRemoteClient(String name) {
super(name);
}
}

G bin dFch v chRy thC, n?m ch?c ph>n test ph/i h5ng v thiu tests, v rQi g thm 2oRn
test sau:

public void testParseCommandLine() throws Exception {
SMCRemoteClient c = new SMCRemoteClient();
c.parseCommandLine(new String[]{filename});
assertEquals(filename, c.filename());
}

"OK," ti ni. "C v4 nh" ng l-y 2(i s( c*a dng l6nh bPng function parseCommandLine
thay v dng main, nh"ng phi@n nh" th lm g?"

"Th 2A tao c thA thC nghi6m," Jerry c( nn c"Di, tr/ lDi.

"Nh"ng chVng c g 2A m thC c/," ti cPn nhPn.

"i@u 2 c nghEa qu hDi 2A vit ph>n test," g c"Di toe tot.

Ti bit ti sK khng th?ng nTi tr0n 2-u ny nn 2nh th; di, v7 l-y bn phm v vit 2oRn
m sau 2A ph>n test c thA 2Rt:

public class SMCRemoteClient {
private String itsFilename;

public void parseCommandLine(String[] args) {
itsFilename = args[0];
}

public String filename() {
return itsFilename;
}
}

Jerry g0t 2>u v lLng lK vit ph>n test case k tip.

public void testParseInvalidCommandLine() {
SMCRemoteClient c = new SMCRemoteClient();
boolean result = c.parseCommandLine(new String[0]);
assertTrue(result should be false, !result);
}

LK ra ti ph/i bit g ch< cho ti l do tRi sao ti nghE, vit m3t ci test khng c>n thit lRi l
m3t khi ni6m hay. "OK", ti th nh0n. "Ti 2on vi6c l-y 2(i s( c*a dng l6nh t vWn vLt
h$n l ti nghE. C lK n 2ng 2A c m3t ci test cho ring n." Th rQi ti v7 l-y bn phm
v lm cho ph>n test 2Rt.

public boolean parseCommandLine(String[] args) {
try {
itsFilename = args[0];
}
catch (ArrayIndexOutOfBoundsException e) {
return false;
}
return true;
}

Cn nh?c kd l"Ing, ti refactor bin s( c v kh;i 23ng n trong function setUp. Cc tests
2@u 2Rt. Tr"7c khi Jerry c thA 2@ nghF ph>n test case tip theo, ti ni, "R-t c kh/ nUng
hQ s$ khng tQn tRi. Chng ta nn vit m3t ci test chHng minh mnh c thA lo cho tr"Dng
h#p -y 2"#c."

"Qu/ v0y," Jerry ni trong khi tm l-y bn phm trong tay ti. "Nh"ng 2A tao ch< cho m
cch tao khoi lm th no."

public void testFileDoesNotExist() throws Exception {
c.setFilename(thisFileDoesNotExist);
boolean prepared = c.prepareFile();
assertEquals(false, prepared);
}

"My th-y khng?" g gi/ng gi/i. "tao mu(n "7c 2Fnh mXi 2(i s( c*a dng l6nh trong
function c*a chnh n thay v nh0p chung c/ m7 m phn tch v "7c 2Fnh chung v7i nhau."
Trong khi 2, ti kn 2o 2/o m?t rng ghi nh7 nhOng 2im -y 2A tham kh/o sau ny, ti
l-y bn phm v thay 2Ti nhOng 2iAm sau 2A lm cho ph>n test 2Rt:

public void setFilename(String itsFilename) {
this.itsFilename = itsFilename;
}

public boolean prepareFile() {
File f = new File(itsFilename);
if (f.exists())
return true;
else
return false;
}

Tr:n b3 cc test 2@u 2Rt. Jerry nhn ti rQi ngha sang bn phm. HiAn nhin g mu(n "li"
bn phm. Hm nay d"Dng nh" g trn 2>y sng kin, b;i th ti chuyAn bn phm v@ pha
g.

"OK, by giD xem 2y!" g ni, cX my trong g r rng 2ang g>m r.

public void testCountBytesInFile() throws Exception {
File f = new File(testFile);
FileOutputStream stream = new FileOutputStream(f);
stream.write(some text.getBytes());
stream.close();

c.setFilename(testFile);
boolean prepared = c.prepareFile();
f.delete();
assertTrue(prepared);
assertEquals(9, c.getFileLength());
}

Sau khi nghin cHu m nguQn c*a g vi giy, ti tr/ lDi, "ng mu(n preparFile() 2A l-y 23
di c*a hQ s$? tRi sao?"

"Tao nghE lt nOa mnh sK c>n chng," g gi/i thch. "v 2 l m3t cch hay 2A chHng minh
mnh c thA 2(i ph v7i m3t hQ s$ hi6n c."

"Mnh c>n n 2A lm g kia ch7?" ti nPn nLc.

"Chng ta sK ph/i g;i n3i dung c*a hQ s$ xuyn qua socket 2n server, ph/i khng?" Jerry
h5i.

"Vng."

"V chng ta c>n bit sK g;i bao nhiu chO," g kin nhNn gi/i thch.

"H"Dm... c lK," ti miZn c"Ing tr/ lDi.

"Tin tao 2i," g m<m c"Di. "t0n cng th tao lm ng"Di h"7ng 2Ro c$ m."

"OK, kh5i ni 2n chuy6n -y," ti tr/ lDi m3t cch thiu kin nhNn. "TRo sao ng lRi tRo hQ
s$ trong ph>n test kia ch7? sao ng khng giO hQ s$ ny sSn thay v l>n no c[ng ph/i tRo
n ra?"

Jerry c"Di khBy rQi tr; nn nghim tc. "Tao ght giO lRi cc nguQn bn ngoi cho m-y ci
test. B-t cH khi no c thA 2"#c, tao 2A cho m-y ci test tRo ra nguQn chng c>n. V7i cch
-y, khng cch no tao bF m-t nguQn c/, hoLc ngay c/ tr"Dng h#p nguQn bF h5ng nOa."

"^, 2i@u ny th qu/ c l," ti th&a nh0n, "nh"ng ti vNn khng 2in khng v7i m-y thH 23
di c*a hQ s$ kia."

"Nh7 2. My sK th-y!"

Ti l-y bn phm v b?t 2>u lm vi6c v7i ph>n cho php 2oRn test 2Rt. Trong khi ti g
phm, ti th-y h$i lR v ti 2ang vit m chnh trong khi thit k l c*a Jerry - nh"ng nhOng
g Jerry lm ch< l vit nhOng 2oRn test case nh5. BRn c thA th9c s9 xp loRi m3t thit k
bPng cch vit nhOng test case hay khng?

public long getFileLength() {
return itsFileLength;
}

public boolean prepareFile() {
File f = new File(itsFilename);
if (f.exists()) {
itsFileLength = f.length();
return true;
}
else
return false;
}

Test case k tip tRo ra m3t ci server gi/ v dng 2A thC kh/ nUng c*a SMCRemoteClient
truy c0p vo 2.





public void testConnectToSMCRemoteServer() throws Exception {
SocketServer server = new SocketServer(){
public void serve(Socket socket) {
try {
socket.close();
}
catch (IOException e) {
}
}
};
SocketService smc = new SocketService(SMCPORT, server);
boolean connection = c.connect();
assertTrue(connection);
}

V7i r-t t tr; ngRi, ti lm cho ph>n test case 2Rt:

public boolean connect() {
try {
Socket s = new Socket(localhost, 9000);
return true;
}
catch (IOException e) {
}
return false;
}

"Tuy6t!" Jerry ni. "Mnh nghE gi/i lao m3t t."

"OK," ti tr/ lDi, "nh"ng hy vit ph>n main() tr"7c 2."

"main() g, dnh d9 g ; 2y?" g h5i.

"H;? 2 l main c*a ch"$ng trnh ch7 g!"

"Th th sao ch7?" Jerry rWt vai. "N ch< g:i parseCommandLine(), parseFile() v connect().
Cn lu l?m mnh m7i test m-y thH 2!"

Ti rDi phng lm vi6c v 2i v@ pha phng gi/i lao. Tr"7c giD ti cH nghE main() l function
2>u tin c>n 2"#c vit, nh"ng Jerry r-t 2ng. R(t cu3c, main() ch< l m3t function kh thiu
th vF.


Cn tip.....
The Crafsman 12.
Three Ugly Lines

Ba dng xBu x

Robert C. Martin

Ti ngh< gi/i lao trn 2i quan st. Khi l7p ch?n bPng n"7c 2 2i xuyn qua vng phn tC
dy c3m lm cho l7p n"7c 2 nh0p nho trong nhOng ln ch7p xanh v nhOng m hnh
chuyAn bin kh?p b@ mLt c*a l7p ch?n - lm ti nh7 2n B?c c9c quang c*a tri 2-t.

Nh" th"Dng l6, Jerry 2ang 2#i ti sau buTi gi/i lao. G nhn ti v ni, "OK, hy g;i m3t hQ
s$ qua socket."

"ng xem cu3c tr"ng by Cherenkov -1- ch"a?

"Tuy6t 2Yp!" g c"Di m<m. Ti 2on lu lu g c[ng ngh< gi/i lao - nh"ng th"Dng th"Dng g
2i 2u?

"OK," ti ni. "Ti sK vit ph>n test case." Ph>n 2>u tin ti g l 2oRn m dng 2A tRo hQ
s$ 2"#c g;i qua socket.

public void testSendFile() throws Exception {
File f = new File("testSendFile");
FileOutputStream stream = new FileOutputStream(f);
stream.write("I am sending this file.".getBytes());
stream.close();
}

"Ti bit ng mu(n tRo hQ s$ dO li6u trong m test h$n l phW thu3c vo tnh trRng chng
c hi6n di6n hay khng," ti ni.

"ng th," Jerry tr/ lDi. "Nh"ng my c th-y my bF m-y thH lLp lRi khng?"

Ti xem lRi ph>n test v th-y ngay chng ti vit 2oRn m g>n nh" trng lLp v7i method
testCountBytesInFile() m chng ti 2 hon thnh tr"7c giD gi/i lao. "Ch< c b(n dng code
m thi," ti ni.

"ng th," Jerry 2p. "Nh"ng s9 trng lLp nn 2"#c vHt b5 ngay khi c thA 2"#c. Khng
th my sK m m3t m7 code khTng lQ 2>y m0p mD v 2>y lXi."

""#c rQi," ti tr/ lDi, "sCa ci ny dZ thi." Ti t<a tt m3t hm m7i g:i l createTestFile()
v thay 2Ti c/ testCountBytesInFile() lNn testSendFile() 2A g:i hm ny.

private File createTestFile(String name, String content) throws IOException {
File f = new File(name);
FileOutputStream stream = new FileOutputStream(f);
stream.write(content.getBytes());
stream.close();
return f;
}

Ti chRy thC ci test 2A ch?c Un l khng lm h5ng g c/, rQi tip tWc vit ph>n test. Ti bit
n c>n gi/ l0p main(), cho nn ti g:i nhOng hm main() c>n g:i. Th rQi ti thm vo ph>n
g:i cu(i 2A g;i hQ s$ 2i.


public void testSendFile() throws Exception {
File f = createTestFile("testSendFile", "I am sending this file.");

c.setFilename("testSendFile");
assertTrue(c.connect());
assertTrue(c.prepareFile());
assertTrue(c.sendFile());
}

"T(t," Jerry g0t 2>u. "My li6u tr"7c l mnh sK c>n m3t method pha client c tn l
sendFile().

"ng v0y," ti ni. "Method ny sK g;i hQ s$ no 2"#c chuBn bF tr"7c."

Ti tr; lRi v7i ph>n test v bF tr; ngRi. Lm sao ti kiAm nghi6m 2"#c hQ s$ ti tRo ra v
"g;i 2i" th0t s9 2"#c g;i 2n server trong khi chng ti chVng c hQ s$ no? Ph/i chUng ti
c>n vit c/ ph>n server tr"7c khi ti c thA kiAm nghi6m chuy6n ny? Ti 2Fnh test g v0y
nh<?

Ti b9c d:c ngQi yn trong khi Jerry nhn ti chD 2#i. Th rQi khi ti xoay qua v gi/i thch
2iAm kh khUn. G gi/i thch "Khng, my khng c>n ph/i vit ci server," "Chng ta ch<
test mXi kh/ nUng g;i hQ s$ c*a client, ch7 chVng ph/i kh/ nUng nh0n hQ s$ c*a server."

"Nh"ng lm sao ti g;i hQ s$ trong khi chVng c server 2A nh0n?"

"My c thA tRo ra "stub" server ch< lm t(i thiAu cng vi6c my c>n thi," Jerry tr/ lDi. "N
chVng c>n ph/i th9c s9 nh0n hQ s$ - n ch< tip bo l my 2 g;i hQ s$ 2ng cch."

"H&m... nh" th ny chUng?"

assertTrue(server.fileReceived);

"Nh" v0y 2"#c rQi," Jerry g0t 2>u. "By giD lm cho ci test 2Rt 2i." Ti nghE v@ v-n 2@ ny
v nh0n ra n khng qu kh, th nn ti vit m3t ci server gi/ chVng lm g ht:

class TestSMCRServer implements SocketServer {
public boolean fileReceived = false;
public void serve(Socket socket) {
}
}

Jerry ni, ", lRi thm trng lLp!" Ti xem lRi v th-y tr"7c 2oRn ng?t, chng ti 2 Hng
hi6u server gi/ t"$ng t9 trong method testConnectToSMSRemoteServer() - th nn ti loRi
b5 n.

Th rQi ti b?t 2>u ph>n server v7i method SetUp() trong ph>n test v 2ng n bPng
method TearDown(). Tr"7c khi mXi method c*a test 2"#c g:i, server kh;i 23ng; khi method
c*a test tr/ ng"#c v@, n 2ng lRi.

protected void setUp() throws Exception {
c = new SMCRemoteClient();

server = new TestSMCRServer();
smc = new SocketService(SMCPORT, server);
}

protected void tearDown() throws Exception {
smc.close();
}

Cu(i cng ti vit method gi/ sendFile() trong SMCRemoteClient:

public boolean sendFile() {
return false;
}

M-y ci test bF h5ng. Ti th; di. "Lm g by giD?"

"G;i ci hQ s$ 2i," g ra l6nh.

"Ch< m; hQ s$ ra v t(ng n qua socket sao?" Ti h5i.

"Khng, c lK mnh c>n cho server bit 2A tip nh0n hQ s$ - cho nn hy g;i m3t thng 2i6p
2$n gi/n v g;i tip theo 2 ph>n hQ s$." Jerry thay 2Ti SMCRemoteClient nh" sau.

">u tin, mnh c>n l-y ci "stream" ra t& socket," g ni.

public boolean connect() {
boolean connectionStatus = false;

try {
Socket s = new Socket("localhost", 9000);
is = new BufferedReader(new InputStreamReader(s.getInputStream()));
os = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
connectionStatus = true;
}
catch (IOException e) {
e.printStackTrace();
connectionStatus = false;
}
return connectionStatus;
}

"RQi," Jerry tip tWc, "2A 2:c 2"#c hQ s$ ph/i c sSn."

public boolean prepareFile() {
boolean filePrepared = false;

File f = new File(itsFilename);
if (f.exists()) {
try {
itsFileLength = f.length();
fileReader = new BufferedReader(
new InputStreamReader(new FileInputStream(f))
);
filePrepared = true;
}
catch (FileNotFoundException e) {
filePrepared = false;
e.printStackTrace();
}
}
return filePrepared;
}

"Sau cng," g ni, "chng ta c thA g;i hQ s$."



public boolean sendFile() {
boolean fileSent = false;
try {
writeSendFileCommand();
fileSent = true;
}
catch (Exception e) {
fileSent = false;
}
return fileSent;
}
private void writeSendFileCommand() throws IOException {
os.println("Sending");
os.println(itsFilename);
os.println(itsFileLength);
char buffer[] = new char[(int) itsFileLength];
fileReader.read(buffer);
os.write(buffer);
os.flush();
}

"i!" ti ni. "G ra c/ 2(ng m chVng thC nghi6m." Jerry nhn ti m3t cch ng"#ng ngFu.
"`a, tao c[ng run l?m." G nh-n nt test v ph>n test bF h5ng v server.fileRecieved tr/ lRi
sai. "Ui cha!" Jerry ni. "Mnh trnh mRch 20p Muon -2- 2!"

"Th," ti ni, b?t ch"7c gi:ng th0t gi(ng Dr. Watson, "bRn s?p sCa tin hnh hQ s$ v7i ba
dng. Dng thH nh-t gQm string "Sending", dng thH hai gQm tn hQ s$ v dng thH ba
gQm chi@u di c*a hQ s$. Sau 2, bRn g;i hQ s$ theo dRng chuXi k t9."

"RQi," Jerry m<m c"Di. "Tao 2 ni v7i my tr"7c buTi gi/i lao l mnh c>n chi@u di c*a hQ
s$ rQi m."

"H&m, ti 2on th, Sherlock," ti ni m3t cch miZn c"Ing.

"By giD mnh ch< c>n nh0n hQ s$ t& server gi/. My mu(n thC m3t pht khng?" Jerry h5i.
Ti kh ch?c nn ph/i lm g nn 2>u tin ti 2Ti ci test 2A ch?c Un chng ti c tn hQ s$,
chi@u di v n3i dung hQ s$:

public void testSendFile() throws Exception {
File f = createTestFile("testSendFile", "I am sending this file.");
c.setFilename("testSendFile");
assertTrue(c.connect());
assertTrue(c.prepareFile());
assertTrue(c.sendFile());

Thread.sleep(50);
assertTrue(server.fileReceived);
assertEquals("testSendFile", server.filename);
assertEquals(23, server.fileLength);
assertEquals("I am sending this file.", new String(server.content));
f.delete();
}

K tip ti 2Ti ci server gi/ cho n phn gi/i dO li6u vo v b/o 2/m th9c tnh:

class TestSMCRServer implements SocketServer {
public String filename = "noFileName";
public long fileLength = -1;
public boolean fileReceived = false;
private PrintStream os;
private BufferedReader is;
public char[] content;
public String command;

public void serve(Socket socket) {
try {
os = new PrintStream(socket.getOutputStream());
is = new BufferedReader(new InputStreamReader(socket.getInputStream()))
os.println("SMCR Test Server");
os.flush();
parse(is.readLine());
}
catch (Exception e) {
}
}
private void parse(String cmd) throws Exception {
if (cmd != null) {
if (cmd.equals("Sending")) {
filename = is.readLine();
fileLength = Long.parseLong(is.readLine());
content = new char[(int)fileLength];
is.read(content,0,(int)fileLength);
fileReceived = true;
}
}
}
}

Cu(i cng ti 2i@u ch<nh SMCRemoteClient.connect() 2A n 2#i thng 2i6p SMCR 2"#c g;i t&
server gi/:

public boolean connect() {
...
String headerLine = is.readLine();
connectionStatus = (headerLine != null) && headerLine.startsWith("SMCR");
...
}

Ti khng g ht nhOng thH trn cng m3t lc. Ti thay 2Ti t&ng b"7c nh5, chRy test giOa
mXi thay 2Ti. Ti bit Jerry c -n t"#ng t(t, 2Lc bi6t v g cn bF qu chuy6n thay 2Ti to l7n
; trn. Sau cng, khi m:i test 2@u 2Rt, ti c/m th-y h$i cha n3i h$n m3t t, ti 2nh li@u
bPng m3t nh0n xt.

"Jerry," ti ni. "oRn code ny x-u x qu."

" my th no?" g h5i.

"Hm, g;i ba dng: tn hQ s$, chi@u di v dng "Sending"."

Jerry nhn ti m3t cch nhn nh"Dng. "CH cho l my bit cch hay h$n."

"Ti nghE th." ti m<m c"Di v b?t 2>u g....



-1- Cherenkov display: thu3c nghin cHu v0t l cao c-p. M3t 2@ ti ht sHc th vF v 2"#c nhi@u nhm nghin cHu
quan tm. C m3t pdf phn tch Chrenkov display r-t cW thA ;: www.lip.pt/~varela/projfc/Showers/Auger-3.pdf.
Ngoi ra cn c v s( ti li6u v@ v-n 2@ ny trn Internet cho nhOng ai thch 2o su.

-2- Muon: M3t "muon" l m3t phn t( khng Tn 2Fnh trong vng ph/n xR g>n b@ mLt tri 2-t. N c tr:ng l"#ng
h$n 207 l>n tr:ng l"#ng m3t electron v tQn tRi trong c/ thA dRng m hoLc d"$ng.
The Crafsman 13.
The Bester Solution

M6t giCi php t$t h5n

Trong khi lm vi,c v#i bi t1p SocketServer, Alphonse khm ph ra vi,c chuyGn t<i objects
8$n gi<n v hi,u xu2t h$n chuyGn t<i strings - ph<i chJng anh ta 8 "Micahed" -1- kE du
hnh cAa chng?

Robert C. Martin

\ mHc .045 hi6n tRi, Ci 8ch vNn l nhOng ph>n 2Di c*a t"$ng lai. MXi th h6 t& lc kh;i
hnh c/m nh" nhOng ph>n 2Di ko di v t0n tr"7c khi chng x/y ra. i khi c/m gic ny
2>y tuy6t v:ng - nh"ng hm nay khng ph/i th. Hm nay, ti dng m3t t thDi gian v t0n
-y 2A ch diZu Jerry.

Ti duXi tay ra pha tr"7c bn phm v b4 m-y kh7p tay. Ti l?c l" ci 2>u, gi/ vD ch<nh
x"$ng cT. Ti d&ng lRi, nhn l$ lo, t5 v4 tr>m ngm. "!" ti ni, "ti nghE l ti bit m3t
cch hay h$n!" Jerry 2/o m?t v th; di, 2#i ti b?t tay vo lm. Ti quyt 2Fnh khng 2i
qu tr7n, th rQi ti b?t 2>u lm vi6c.

A vit m3t hQ s$ xuyn qua socket, Jerry 2 ph/i g;i ba dng chO tr"7c. M3t dng c
string "Sending", dng k tip chHa tn hQ s$ v dng cu(i ch< 2Fnh chi@u di c*a hQ s$. RQi
sau 2 Jerry m7i g;i chnh hQ s$ -y nh" m3t chuXi t&. oRn m nh" sau:

private void writeSendFileCommand() throws IOException {
os.println("Sending");
os.println(itsFilename);
os.println(itsFileLength);
char buffer[] = new char[(int) itsFileLength];
fileReader.read(buffer);
os.write(buffer);
os.flush();
}

Khi 2:c hQ s$ ng"#c lRi t& socket, g g:i readLine ba l>n, mXi l>n cho mXi ba dng g g;i 2i.
G dng "Sending" string nh" m3t ph"$ng thHc nh0n di6n c*a m3t chuyAn xu-t v l"u giO
ci thH nh nh" tn c*a hQ s$; ci thH ba l chi@u di c*a hQ s$. G dng n 2A ch< 2Fnh
chuXi t& 2"#c dng nh" m3t t>ng 26m. RQi sau 2 g dng chi@u di 2A 2:c s( l"#ng t&
thch Hng t& socket.

private void parse(String cmd) throws Exception {
if (cmd != null) {
if (cmd.equals("Sending")) {
filename = is.readLine();
fileLength = Long.parseLong (is.readLine());
content = new char[(int)fileLength];
is.read(content,0, (int)fileLength);
fileReceived = true;
}
}
}

M:i thH lm vi6c ngon lnh, nh"ng ti bit cch hay h$n. >u tin, ti 2Ti 2oRn test 2A 2:c
objects thay v nhOng dng:


public void serve(Socket socket) {
try {
os = new PrintStream(socket.getOutputStream());
is = new ObjectInputStream(socket.getInputStream());
os.println("SMCR Test Server");
os.flush();
parse((String)is.readObject());
}
catch (Exception e) {
}
}

private void parse(String cmd) throws Exception {
if (cmd != null) {
if (cmd.equals("Sending")) {
filename = (String)is.readObject();
fileLength = is.readLong();
content = (char[]) is.readObject();
fileReceived = true;
}
}
}

K tip ti thay 2Ti ph>n SMCRemoteClient 2A vit objects thay v strings.

public boolean connect() {
...
os = new ObjectOutputStream(smcrSocket.getOutputStream());
...
}

private void writeSendFileCommand() throws IOException {
os.writeObject("Sending");
os.writeObject(itsFilename);
os.writeLong(itsFileLength);
char buffer[] = new char[(int) itsFileLength];
fileReader.read(buffer);
os.writeObject(buffer);
os.flush();
}

Ti chRy tr:n b3 cc tests v chng lm vi6c ngon lnh. "Th-y ch"a?" ti gy. "Ti nghi6m
ra vit objects thay v strings th t(t h$n."

Eureka!
Ti nhn Jerry, nh"ng c g 2 thay 2Ti - 2i m?t g khng t0p trung. G 2Hng d0y v b?t
2>u r/o quanh. Th<nh tho/ng g d&ng lRi, nhn vo mn hnh, nhn ti, l?c 2>u v lRi tip tWc
r/o b"7c. G lBm nhBm g 2 v@ nUm thng, kinh nghi6m v s9 ngu xuBn. Ti h$i hi.

Sau r(t, g d&ng lRi, nhn ti thVng vo m?t v ni: ", Alphonse, my xong rQi 2."

"Ti lm g sai v0y Jerry?" ti th th>m.

G nhn ti chPm chLp vi giy. Th rQi g xoay ng"Di h"7ng v@ thang my v ra l6nh, "2i
theo tao."

Chuyn 2i trn thang my yn lLng nh" nh mQ. TrRng thi c*a Jerry kh m 2on nTi: g
khng hVn l gi0n dO nh"ng ch?c ch?n l g b9c d:c, v lK g 2 ti 2 dnh vo s9 b9c d:c
ny. Trong thang my, chng ti lLng lK thay 2Ti vF tr 2A gi/m mHc l6ch coriolis -2- ti c(
nghi6m ra l do tRi sao ph>n m nguQn 2$n gi/n ti thay 2Ti c thA tRo /nh h";ng gh g7m
2n g nh" th.

Ti theo Jerry vo m3t phng khch ; m3t trong nhOng t>ng thu3c "low-g". Cc tay h:c vi6c
khng th"Dng 2"#c php vo cc t>ng trn .49g. Trn 2"Dng 2i ln, ti khng di cc b/ng
hi6u c*a cc t>ng l>u nh"ng t>ng ny c v4 th-p h$n .4g. Bn trong phng khch c nUm
g "du hnh" l0p trnh vin khc. Jerry gi7i thi6u ti v7i nhm ny. Ti g?ng nh7 ht tn c*a
m:i ng"Di: Johnson, Jasmine, Jason, Jasper v Jennifer. Jerry b/o ti 2Hng giOa phng
khch trong khi g v m:i ng"Di ngQi trn salon xung quanh ti. Sau 2 Jerry xoay v@ pha
nhm l0p trnh vin v v7i v4 kiAu cch, g tuyn b(, ", c chuy6n 2 x/y ra. Ti tin rPng
Alphonse l tay h:c vi6c 2>u tin trong nUm vo "Micah his Journeyman."

Ti c/m th-y ng9c ti ng&ng 20p m3t nhFp v m?t ti m; r3ng ra. y l 2i@u ht sHc 2$n
gi/n! ti khng d9 t";ng 2i@u ny!

"C ai lm Micahed nUm nay ch"a nh<?" Jerry h5i. Ting x x>m lan ra kh?p phng nh"ng
m:i ng"Di 2@u l?c 2>u - hiAn nhin l ch"a c ai.

Jasmine nhn ti chPm chLp hQi lu. Trong khi c ta dn m?t vo ti, nng b/o Jerry: "OK,
Jer, cho b:n ti nghe cu chuy6n -y 2i."

Jerry th; di, g c( g?ng m3t cch r r6t 2A l-y lRi t" th v b?t 2>u ni.

"Nh" cc bRn bit, ng C yu c>u ti lm ci SMCRemote cho n chRy." m l0p trnh vin
2@u g0t 2>u; hiAn nhin h: bit chuy6n ny. "Alphonse v ti b5 ra c/ ngy cho bi t0p
SocketServer; v n lm vi6c r-t t(t."

Thm m3t c s(c: SocketServer ch< l m3t bi t0p?

"T& lc lm cho n chRy 2"#c, chng ti b?t 2>u 2Lt ph>n client c*a SMCRemote lRi v7i
nhau. M3t trong nhOng test cases l chuyAn t/i m3t hQ s$ t& client 2n server qua socket."
LRi thm nhOng ci g0t 2>u trong phng.

Jerry cng b(i r(i th-y r. G trUn tr; trn gh v trnh nhOng nh m?t, g nhn chPm chLp
xu(ng sn nh. "Ti ch<nh 2Fnh vi6c chuyAn xu-t hQ s$ bPng cch g;i ba dng chO theo sau
bPng m3t chuXi t&. Dng 2>u tin l danh tnh c*a vi6c chuyAn xu-t, dng thH hai l tn hQ
s$ v dng thH ba l chi@u di hQ s$." LRi thm g0t 2>u - 2i@u ny chVng lm h: ngRc nhin
t no.

"R rng, 2y ch< l m3t cch 2$n gi/n cho m-y ci test c thA 2Rt 2A chng ti c thA
refactor thnh m3t dRng t(t h$n." LRi thm g0t 2>u; thm nhOng ting x>m x 2Qng . "V
rQi..." Jerry ng&ng lRi. "Alphonse ni l h?n nghE l h?n c ... D.... m3t kin hay h$n."

CUn phng tr; nn yn tEnh. i m?t c*a Jasmine vNn dn chLt vo ti, nh"ng ci nhn c*a
nng chuyAn t& trRng thi 2nh gi sang suy 2on. T&ng ng"Di m3t, ti c/m th-y nhOng tia
nhn c*a cc tay "du hnh" ng&ng lRi ; ti. Lm g m l7n chuy6n v0y? TRi sao h: 2ang 2i
ci Micah cho ti nh<?

Johnson l ng"Di ph tan khng kh u m.

"Khng ph/i bQ mu(n cho b:n ti bit --" g bu3c mi6ng ni, rQi ghm lRi bPng m3t c ht
vo nLng n@.

Lic nhn, ti th-y Jerry 2ang g0t 2>u. G0t 2>u cho chuy6n g nh<?

@ nghF ngy th$
Ti khng chFu nTi nOa. Ti rDi kh5i ci nhn c*a Jasmine, nhn thVng vo m?t c*a t&ng tay
"du hnh" trong pht ch(c rQi ni: "T-t c/ nhOng g ti 2@ nghF ch< l vi6c chuyAn t/i objects
thay v strings! ti chVng th-y vi6c -y lRi l m3t Micah!"

Jennifer b"7c v@ pha ti v ni, "Vng, bQ ch< lm ng>n -y. V, khng, ti khng gi/ 2Fnh l
bQ nghE ng#i g nhi@u v@ n - nh"ng v7i b:n ti, 2y l chuy6n l7n."

"TRi sao?" ti rt ln, th0t s9 ho/ng s#.

"B;i," Jerremy gi/i thch, "2Lc 2iAm quan tr:ng nh-t c*a m3t l0p trnh vin gi5i l kh/ nUng
suy nghE m3t cch tr&u t"#ng. Th0t ra r-t t ng"Di c thA lm nh" th. My m7i v&a chHng
t5 l my c thA lm 2i@u ny."

Ti 2m nghi ngD. "N ch< l m3t object thi m," ti lLp b?p.

"Chnh xc," Jennifer ni. B:n h: 2@u g0t 2>u m3t cch nghim ch<nh.

Ti l?c 2>u. "i, th, nu 2y l 2i@u hay - m3t Micah g 2 - tRi sao Jerry c v4 cu k<nh
v0y?"

", chuy6n -y!" Jasmine c"Di to. "Jerry xu(ng 2y vo giD ngh< l>n tr"7c v kA cho b:n
mnh v@ v-n 2@ chi@u di hQ s$ c*a c0u. Anh -y ch?c rPng c0u sK r-t c -n t"#ng khi th-y
chi@u di c*a hQ s$ sK kh7p kht vo chuyAn xu-t hQ s$. Anh -y d9 ph5ng c0u sK ngRc nhin
bit ch&ng no."

"`a," Jasper c"Di 2i6u 2ng, "v c0u lRi 2i m ch< cho g chi@u di ny tr; nn lRc 2@."

Ti nu(t n"7c b:t, c( chFu 29ng. "Ti 2 lm th sao?"

Jerry 2Hng d0y v ni, "ngNm lRi chuy6n 2 2i Alphonse. Nu my g;i m3t chuXi t& nh" m3t
object, tRi sao my cn ph/i g;i chi@u di c*a hQ s$ ring ra nOa? Trong su thng t7i 2y,
m-y tay ny th no c[ng sK nRo s"Dn tao v@ chuy6n ny" g ni thm m3t cch thiAu no.

"B:n t7 ch?c ch?n sK lm th!" Jennifer c"Di toe tot. "MXi khi xt duy6t m nguQn c*a anh
-y, b:n t7 sK h5i anh tham s( chi@u di hQ s$ ; 2u!" C ta c"Di rc rch trong khi Jerry
nhUn nh v cHng 2D khun mLt.

"C0u ph/i bit, Alphonse," Jasmine gi/i thch, "khng nhOng c0u 2 tRo nn m3t b"7c tr&u
t"#ng 2ng kA, gi/i php c*a c0u cn 2$n gi/n h$n gi/i php c*a Jerry. H$n nOa, n l m3t
cch 2$n thu>n ph b5 d9 tnh c*a Jerry v7i nhu c>u chi@u di c*a hQ s$. C0u 2 Micahed
anh -y!"

Ti b?t 2>u hiAu ra s9 thA. t ra ti khng bF dnh vo m3t phi@n toi no...

"Ti nghE l," Jasmine ni, "m3t bin c( nh" th ny c>n 2Ti cLp (lm vi6c). Jerry, ti 2Ti
ng"Di h:c vi6c v7i anh. Anh nh0n Andy v ti sK lm vi6c v7i Alphonse vi ngy."

... hay l ti?


-1- "Micah" ; 2y, trong bi ny, c lK l m3t loRi 2Lc quy@n hoLc m3t vinh d9 l7n lao. Theo t9 2iAn Merriam-
Webster th Micah l tn c*a m3t nh tin tri ng"Di Do Thi ; th ke thH 8 sau Cng nguyn. "Micah" xu-t xH t&
nguyn th*y chO MIkhAyAh (ting Hebrew).

-2- Coriolis: tn c*a nh ton h:c, kd s" cng chnh ng"Di Php Gaspard G. Coriolis. Xem thm tiAu sC v cng
nghi6p c*a Coriolis ;: http://www-gap.dcs.st-and.ac.uk/~history/Mathematicians/Coriolis.html
The Crafsman 14.
Transaction Action

Hnh +6ng chuyDn tCi

Lm vi,c v#i m&t tay du m4c -1- m#i l m&t kinh nghi,m nNng nO cho Alphonse. Li,u chng
chLu n6i tia nhn s=c bn cAa Jasmine v x3ng 8ng v#i ci tn lng m#i cAa mnh?

Robert C. Martin

"OK, cao th* -2- xem thC c0u th no." f3 cUng thVng trong ci nhn c*a Jasmine lm ti
dn chLt vo gh. "... c th no?" ti l?p b?p. "Thi 2i cao th*, b3 c0u 2Fnh khng lm
ti qu nh" c0u 2 lm Jerry qu sao," nng ni. "Ti chVng c( tnh lm cho ai qu c/," ti
ch(ng ch m3t cch yu 7t. "Ti ch<...." "`a, hVn nhin rQi," nng b-t ch#t ng?t ngang cu
ni c*a ti, t5 v4 chng ch"Dng. "Thi, hy b?t tay vo cng vi6c cho rQi. C0u 2Fnh sK thay
2Ti nhOng g tip theo 2y?"

Chng ti ngQi trong phng lm vi6c, xem xt 2oRn m Jerry v ti v&a vit xong. Ti ch<
cho Jasmine cch ti thay 2Ti 2oRn code c*a Jerry dng 2A g;i strings thay v objects xuyn
qua socket.

"Ti... m... D khng bit. Ti ch< nghE l g;i objects ch?c t(t h$n strings." Nng lm ti ht
sHc b(i r(i. MHc cUng thVng cH 2T dQn t& nh m?t v thi 23 c*a nng. "Suy nghE 2i cao
th*, suy nghE! C0u khng ch< thu>n tu gi vi ci strings v integers vo trong m3t object,
ph/i th khng? Gi nh" v0y ng>m 2Fnh v-n 2@ g? C0u c thA lm g v7i n?"

"Ti, m...." gi nh" 2i m?t nng ng"ng 2 nLng ln ti, c lK ti c thA suy gNm. Ti
nh?m nghi@n 2i m?t v th>m tWng m3t 2oRn kinh -3-. Trong vng vi giy, ti 2 c thA
xem xt cu h5i c*a nng.

Ci test case chng ti 2 lm dng 2A xc th9c chng ti c thA g;i hQ s$ c xuyn qua
socket. foRn m dng 2A g;i hQ s$ nh" th ny:

private void writeSendFileCommand() throws IOException {
os.writeObject("Sending");
os.writeObject(itsFilename);
os.writeLong(itsFileLength);
char buffer[] = new char[(int) itsFileLength];
fileReader.read(buffer);
os.writeObject(buffer);
os.flush();
}

Nh"ng tRi sao chng ti lRi g;i hQ s$ 2i? Chng ti g;i n 2n SMCRemoteServer 2A 2"#c
bin dFch. Sau 2 server sK tr/ v@ hQ s$ 2 2"#c bin dFch. TRi sao Jerry lRi g;i "Sending"
string tr"7c? G ni rPng mWc 2ch l 2A bo server c hQ s$ 2ang 2"#c g;i 2n - nh"ng
chng ti lRi khng mu(n thng bo cho server l c hQ s$ 2ang 2"#c g;i 2n; chng ti
mu(n ra l6nh cho server bin dFch m3t hQ s$ v g;i ng"#c lRi kt qu/.

Ti suy nghE r-t kd l"Ing, nh"ng m3t ph>n no 2 trong no b3 c*a ti vNn 2ang tip tWc
tWng kinh. H>u nh" trong trRng thi nCa t<nh, nCa m, ti 2i thVng 2n bHc t"Dng v vK ra
s$ 2Q "kt qu/ bin dFch". Ti nhc th-y khun mLt nghim tr:ng c*a Jasmine thong m3t
nW c"Di. "Ti khoi ci l(i suy nghE c*a c0u 2 cao th*. f&ng d&ng lRi ; 2."

B(n mBu dO li6u 2"#c g;i 2n server: tn hQ s$, 23 di hQ s$, n3i dung hQ s$ v chuXi
"Sending". TRi sao nhOng mBu ny 2"#c g;i ring bi6t? Chng 2@u thu3c vo m3t gi tin
c*a m3t xu-t chuyAn t/i! fng rQi! Ti t9 l?c 2>u v7i chnh mnh v thay 2Ti 2oRn test nh"
sau:

public void testCompileFile() throws Exception {
File f = createTestFile("testSendFile", "I am sending this file.");
c.setFilename("testSendFile");
assertTrue(c.connect());
assertTrue(c.prepareFile());
assertTrue(c.compileFile());
Thread.sleep(50);
assertTrue(server.fileReceived);
assertEquals("testSendFile", server.filename);
assertEquals(23, server.fileLength);
assertEquals("I am sending this file.", new String(server.content));
f.delete();
}

Th rQi ti 2Ti hm sendFile c[ nh" sau:

public boolean compileFile() {
boolean fileSent = false;
char buffer[] = new char[(int) itsFileLength];
try {
fileReader.read(buffer);
CompileFileTransaction cft =
new CompileFileTransaction(itsFilename, buffer);
os.writeObject(cft);
os.flush();
fileSent = true;
}
catch (Exception e) {
fileSent = false;
}
return fileSent;
}

Jasmine theo di r-t st sao. Ti khng thA d nTi c/m gic c*a nng nh"ng ti bit ch?c l
mnh 2ang 2i 2ng h"7ng. K tip ti vit CompileFileTransaction class:

public class CompileFileTransaction implements Serializable {
private String filename;
private char contents[];
public CompileFileTransaction(String filename, char buffer[]) {
this.filename = filename;
this.contents=buffer;
}
public String getFilename() {
return filename;
}
public char[] getContents() {
return contents;
}
}

foRn ny cho php ch"$ng trnh 2"#c bin dFch. T-t nhin l m-y ci test bF h5ng, b;i th
ti lRi thay 2Ti ph>n server gi/ nh" sau:





public void serve(Socket socket) {
try {
os = new PrintStream(socket.getOutputStream());
is = new ObjectInputStream(socket.getInputStream());
os.println("SMCR Test Server");
os.flush();
parse(is.readObject());
}
catch (Exception e) { }
}
private void parse(Object cmd) throws Exception {
if (cmd != null) {
if (cmd instanceof CompileFileTransaction) {
CompileFileTransaction cft = (CompileFileTransaction) cmd;
filename = cft.getFilename();
content = cft.getContents();
fileLength = content.length;
fileReceived = true;
}
}
}

NhOng thay 2Ti ny gip cho cc ph>n test 2@u 2Rt. "Ph/i c gi(ng nh" th ny khng?"
Ti h5i. "`a, ch< l kh;i 2iAm thi," nng xc nh0n m3t cch d ch&ng. "Ch?c ch?n l n hay
h$n l(i chuyAn mXi ph>n dO li6u thnh strings c*a Jerry - v n c[ng hay h$n l(i chuyAn g;i
mXi ph>n dO li6u ring bi6t." "V0y c lm th no cho hay h$n nOa v0y?" Ti h5i. "HSn 2,"
nng ni m3t cch thiu kin nhNn. "Ngay lc ny hy hon t-t ph>n chuyAn t/i. C0u ph/i
lm cho client tip nh0n hQi 2p t& server." "Ci 2 ch?c khng kh l?m," ti 2p, c/m th-y
ph-n ch-n h$n m3t cht, v thm vo ba dng nh" sau vo 2oRn testCompileFile nh" sau:

File resultFile = new File("resultFile.java");
assertTrue("Result file does not exist", resultFile.exists());
resultFile.delete();

Ti chRy 2oRn test v xc th0t n bF h5ng. "Sau khi mnh g:i compileFile, kt qu/ hVn ph/i
2"#c vit vo m3t hQ s$," ti gi/i thch cho Jasmine, rQi ni thm, "ngay lc ny ti khng
quan tm 2n chuy6n c g trong hQ s$; ti ch< mu(n ch?c l hQ s$ 2 2"#c tRo ra." "V0y
c0u lm cch no 2A tRo ra n?" nng thch thHc. "Ti sK cho c th-y," ti ni, thay 2Ti
2oRn server gi/ nh" sau:

private void parse(Object cmd) throws Exception {
if (cmd != null) {
if (cmd instanceof CompileFileTransaction) {
CompileFileTransaction cft = (CompileFileTransaction) cmd;
filename = cft.getFilename();
content = cft.getContents();
fileLength = content.length;
fileReceived = true;
CompilerResultsTransaction crt =
new CompilerResultsTransaction("resultFile.java");
os.writeObject(crt);
os.flush();
}
}
}

Th rQi ti tRo ph>n bin dFch ny bPng cch thm m3t ci s"Dn c*a
CompileResultsTransaction class


public class CompilerResultsTransaction implements Serializable {
public CompilerResultsTransaction(String filename) { }
public void write() { }
}

T-t nhin ph>n test vNn h5ng, b;i th ti thay 2Ti compileFile nh" sau:

public boolean compileFile() {
boolean fileCompiled = false;
char buffer[] = new char[(int) itsFileLength];
try {
fileReader.read(buffer);
CompileFileTransaction cft =
new CompileFileTransaction(itsFilename, buffer);
os.writeObject(cft);
os.flush();
Object response = is.readObject();
CompilerResultsTransaction crt = (CompilerResultsTransaction)response;
crt.write();
fileCompiled = true;
}
catch (Exception e) {
fileCompiled = false;
}
return fileCompiled;
}

Cu(i cng, ti th9c hi6n chi tit ph>n chuyAn t/i:

public class CompilerResultsTransaction implements Serializable {
private String filename;
public CompilerResultsTransaction(String filename) {
this.filename = filename;
}

public void write() throws Exception {
File resultFile = new File(filename);
resultFile.createNewFile();
}
}





KEt quC bin dFch
TRi sao tn, 23 di, n3i dung c*a hQ s$ v "Sending" string 2@u 2"#c g;i 2n server ring
bi6t nu chng 2@u thu3c v@ m3t chLng chuyAn t/i?

"\ giai 2oRn ny 2"#c v0y l t(t rQi," Jasmine ni. "Ti 2i gi/i lao m3t ch(c trong khi c0u
th9c hi6n xong quy trnh CompileResultsTransaction th9c s9 vit thnh hQ s$ thay v ch< tRo
ra n. C[ng nn d:n dYp cht 2<nh nOa. C kh nhi@u m/nh vWn vLt cn st lRi trong lc
c0u v Jerry khu-y v:c chuy6n g;i strings v integers. Nh"ng tr"7c khi ti 2i, ti mu(n bit
kin c*a c0u trong ph>n instanceof c0u dng trong 2oRn server gi/."

f l gi/i php 2$n gi/n nh-t m thi c thA nghE ra dng 2A kiAm tra xem object s?p tr/ lRi
c th0t s9 l CompileFileTransaction hay khng." Ti ni, b?t 2>u c/m th-y b(i r(i. "C g
sai v7i ph>n ny sao?"

Nng 2Hng ln, nhn v@ pha ti v tr/ lDi, "khng c g sai tr>m tr:ng, nh"ng c0u c nghE
rPng server th0t sK lm th sao? Li6u server th0t sK c chuXi if/else di ngoPng cho
instanceof 2A m bin xu-t cc chuyAn t/i 2i vo?"

"Ti ch"a nghE xa 2n nh" th," ti th nh0n. "Khng," nng ni m3t cch thVng th&ng, "Ti
khng hnh dung c0u nghE xa nh" v0y." V rQi nng r/o b"7c ra kh5i phng.

CUn phng tr(ng rXng khi khng c nng, nh" thA s9 hi6n di6n c*a ti chVng c gi trF g.
Ti th; di v ngc ngo?c ci 2>u. Lm vi6c v7i Jasmine s?p t7i sK 2>y m6t m5i v 2>y s9
gio hu-n 2* m:i kiAu. M3t 2i@u ti bit ch?c - ti ght bF g:i l cao th*. Ti lRi th; di v
b?t 2>u gi/i quyt cng tc nng giao cho.


-1- D9a trn gp c*a cl trong bi thH 13 , journeyman c thA 2"#c xem nh" nhOng k4 du mWc, 2i tm nhOng
vng "2-t m7i". NghEa bng cho journeyman c[ng ht sHc thch h#p cho nhOng l0p trnh vin c ci nhn khai ph.
Ti tRm dFch journeyman l du mWc theo tinh th>n ny.

-2- Hotshot: ting lng ch< cho m3t c nhn kinh nghi6m v nTi b0t. Hotshot c[ng c thA dng v7i tnh cch chm
bim, bIn c#t hoLc thn thi6n. Trong bi ny, c lK Jasmine g:i Alphonse v7i tnh cch bIn c#t.

-3- Mantra: c nghEa chung l 2oRn kinh k6. Theo 2Ro Hindu v 2Ro Ph0t, mantra c kh/ nUng ho gi/i nhOng tr?c
tr;.
The Crafsman 15.
Ess Are Pee
"Hch" l "B" -1-

T> chuy,n tay h+c vi,c nhi,t tnh cAa chng ta d+n dPp h@ s$ Jasmine yu cu, dQn 8.n
tnh tr/ng qu thi trong lc anh chng hnh dung m&t cu&c 80i tho/i t"9ng t"7ng - v#i
chnh anh ta.

Robert C. Martin

Hnh /nh cu(i ti th-y tr"7c khi cnh cCa khp lRi l mi tc di ng m"#t c*a Jasmine,
vung vBy theo nhFp b"7c 2>y ch* c*a nng. Khi cUn phng tan l?ng bng dng nng , ti
c/m th-y lQng ng9c c*a mnh nhY nhm trt 2i m3t luQng kh nn chLt. fi m?t ti m-t 2i
tiu 2iAm, v su(t nhi@u pht g>n nh" t<nh to, ti ngQi th&, nhn v@ cnh cCa mD nho 2i
trong t>m m?t.

VNn cn 2D ng"Di ra, ti nh0n ra mnh ph/i tr; lRi lm vi6c - nh"ng lm th no 2y? Khng
bit nu Jasmine lm, nng sK vit hQ s$ v d:n dYp 2oRn m ra sao nh<? Ti bit ch?c l
nng sK ni l ti chVng c g xu-t s?c cho nng xem khi nng tr; lRi: "Cao th* m ho ra
nh" v0y sao! Ny giD c0u ch< ngQi th& ra 2 v:c khu-y m-y ngn tay ci ph/i khng?"

"OK, Jasmine, OK," Ti ni. "Mnh lm g tr"7c 2y?"

"No, cao thA, chng mnh ph<i lm sao cho CompilerResultsTransaction chuyn ch9 n&i
dung cAa m&t h@ s$ t> server 8.n client, v r@i vi.t h@ s$ 2y xu0ng client."

"^, 2ng rQi", ti 2p. "Trnh dFch sK tRo ra m3t hQ s$ xu-t trn server, v chng ta ph/i dDi
n 2n client - y nh" thA chng ta v&a th9c hi6n trong CompileFileTransaction."

public class CompileFileTransaction implements Serializable {
private String filename;
private char contents[];
public CompileFileTransaction(String filename, char buffer[]) {
this.filename = filename;
this.contents=buffer;
}
public String getFilename() {
return filename;
}
public char[] getContents() {
return contents;
}
}

"Chng ta m; v 2:c hQ s$ trong compileFile method, rQi tRo v chuyAn tn hQ s$ v chuXi
k t9 vo constructor c*a CompileFileTransaction." Ti tip tWc.

public boolean compileFile() {
char buffer[] = new char[(int) itsFileLength];
try {
fileReader.read(buffer);
CompileFileTransaction cft =
new CompileFileTransaction(itsFilename, buffer);

"R@i, cao thA, mnh v>a lm 8ng y nh" v1y. C 8iGm no c1u khng v>a lng chJng?"

Ti khng mu(n vit 2oRn m y h6t nh" nhau hai l>n. Jerry ph/n 2(i c9c l9c chuy6n lLp lRi
m nguQn.

"Jerry khng ph<i l con dao bn nh2t trong tA 8u -2-, cao thA."

"Ti khng r chuy6n 2 nh"ng ti nghE, v7i quan 2iAm ny th anh ta 2ng. B;i th, ti
nghE l ti mu(n vit m3t class dng 2A mang hQ s$ xuyn qua socket."

"Ci g 8 t"$ng t* nh" FileCarrier?"

"`a, ci tn 2 hay !"

"R@i, cao nhn -3-, vi.t m&t ci test cho n 8i."

"Cao nhn? - m, OK. Th ny nh?"

public class FileCarrierTest extends TestCase {
public void testAFile() throws Exception {
final String TESTFILE = "testFile.txt";
final String TESTSTRING = "test";
createFile(TESTFILE, TESTSTRING);
FileCarrier fc = new FileCarrier(TESTFILE);
fc.write();
assertTrue(new File(TESTFILE).exists());
String contents = readFile(TESTFILE);
assertEquals(TESTSTRING, contents);
}
}

"Hay l=m, ng mnh. Ti.p t4c 8i."

"f"#c rQi, th"a c J. Sau 2y l hai function ti6n ch..."

private String readFile(final String TESTFILE) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(TESTFILE));
String line = reader.readLine();
return line;
}

private void createFile(final String name, final String content)
throws IOException {
PrintWriter writer =
new PrintWriter(new PrintWriter(new File Writer(name));
writer.println(content);
writer.close();
}

"... v 2y l ph>n Hng dWng rt g:n c*a FileCarrier sK lm cho ph>n test bin dFch v
khng chRy khi test."

public class FileCarrier {
public FileCarrier(String fileName) { }
public void write() { }
}

"RQi, qu 2 -4-, mnh ch< c>n lm cho ci test 2Rt bPng cch 2:c hQ s$ trong constructor v
vit n trong function write."

"Ch"a 8u, ng t"#ng - 8u tin l ch/y ci test v bi.t ch=c n hRng ci 8."

"], nng J, ch"a c Hng dWng FileCarrier. T-t nhin l n sK h5ng thi."

"H<, ho< qun c1u v ti bi.t nh" v1y. Nh"ng li,u ch"$ng trnh c bi.t th. khng?"

"Ti th0t l khoi nhOng khi c mu(n ti chRy test. OK, ny." [Ph>n test 2Rt] "H;? lm sao
c thA nh" v0y 2"#c?"

"QuS tha, ti khng r nUa. Lm sao phn test c thG 8/t trong khi chHng c g trong
FileCarrier 8.n --"

"Egad, Auriculatum! -5- mnh ch"a h@ xo hQ s$ test."

", ng kP. Th. sao c1u khng chUa n 8i?"

"OK, 2y."

public void testAFile() throws Exception {
final String TESTFILE = "testFile.txt";
final String TESTSTRING = "test";
createFile(TESTFILE, TESTSTRING);
FileCarrier fc = new FileCarrier(TESTFILE);
new File(TESTFILE).delete();
c.write();
assertTrue(new File(TESTFILE).exists());
String contents = readFile(TESTFILE);
assertEquals(TESTSTRING, contents);
}

"Ngon lnh, by giV n hRng r@i! nh"ng m ng thn, c1u lm cho n 8/t 8"7c khng?

"HiAn nhin rQi, JJ - xem 2y!"

public class FileCarrier implements Serializable {
private String fileName;
private char[] contents;

public FileCarrier(String fileName) throws Exception {
File f = new File(fileName);
this.fileName = fileName;
int fileSize = (int)f.length();
contents = new char[fileSize];
FileReader reader = new FileReader(f);
reader.read(contents);
reader.close();
}

public void write() throws Exception {
FileWriter writer = new FileWriter(fileName);
writer.write(contents);
writer.close();
}
}

"Yee Hah! 8/i nhn, by giV c1u m#i nn c$m nn cho 8y -6-!"

"Khng c chi, cm $n 2Ri n"$ng -7-, nh"ng c c[ng ch"a th-y g m. Hy xem l(i ti tch
h#p FileCarrier vo CompileFileTransaction -- ci ny ch?c sK lm c ch ."



public class CompileFileTransaction implements Serializable {
FileCarrier sourceFile;
public CompileFileTransaction(String filename) throws Exception {
sourceFile = new FileCarrier(filename);
}
public String getFilename() {
return sourceFile.getFileName();
}
public char[] getContents() {
return sourceFile.getContents();
}
}

"V by giD ti sK 2Ti function compileFile 2A dng ci CompileFileTransaction m7i 2y!"

CompileFileTransaction cft = new CompileFileTransaction(itsFilename);
os.writeObject(cft);
os.flush();
Object response = is.readObject();
CompilerResultsTransaction crt = (CompilerResultsTransaction)response;
crt.write();

"V by giD ti chRy m-y ci test v.... th-y ch"a? Chng 2Rt ht!"

", 8/i cao thA, tuy,t! C1u 8 xu2t ra dJm ba tuy,t chiu!"

"Tnh tr"7c ht rQi m, DR H"$ng -8-, tnh ht rQi. By giD hy xem ti 2Lt ci FileCarrier v
trong CompilerResultsTransaction!"

public class CompilerResultsTransaction implements Serializable {
private FileCarrier resultFile;

public CompilerResultsTransaction(String filename) throws Exception {
resultFile = new FileCarrier(filename);
}

public void write() throws Exception {
resultFile.write();
}
}

"i chao!"

"V hy xem cch ti 2Ti ci test dng trong transaction m7i m3t cch nh ngh@ 2y!"

private void parse(Object cmd) throws Exception {
if (cmd != null) {
if (cmd instanceof CompileFileTransaction) {
CompileFileTransaction cft = (CompileFileTransaction) cmd;
filename = cft.getFilename();
content = cft.getContents();
fileLength = content.length;
fileReceived = true;

TestSMCRemoteClient.createTestFile("resultFile.java", "Some content.");

CompilerResultsTransaction crt =
new CompilerResultsTransaction("resultFile.java");
os.writeObject(crt);
os.flush();
}
}
}

"Lm sao c1u bi.t 8"7c h.t m2y th3 ny v1y, Alphonse?"

"C th-y 2, Jasmine, ti bit ht m:i chuy6n thu3c v@ objects. FileCarrier l m3t object 2
Jasmine. C c th-y n c thA 2"#c xC dWng nhi@u h$n ch< m3t n$i khng? C c th-y m3t
object ch< hm chHa m3t trch nhi6m? C th-y khng? C c bit Nguyn L Trch Nhi6m
f$n -9- khng Jasmine? C khi no c nghe 2n n ch"a? 2 nghin cHu n ch"a? Ti
nghin cHu n rQi 2. C bit n ni sao khng, Jasmine? N ni rng m"t class ch& nn
c m"t v ch& m"t l do )* thay ),i. N ni rng m-i functions v variables c.a
m"t class ch& nn lm vi0c )* cng )1a )2n m"t m3c )ch. M"t class khng nn c4
g5ng hon thnh nhi6u h7n m"t m3c )ch.... C c 2ang l?ng nghe 2 khng,
Jasmine?"

"Vng, Alphonse. Ti 8ang chJm ch m."

"Tip tWc l?ng nghe, Jasmine. Trong 2m b:n mnh ai m bit nguyn l ny g:i n l SRP -
10-. f l ESS ARE PEE Jasmine."

"ESS ARE PEE, Alphonse. Ess are pee."

"Cn nh7 function compileFile khng? Cn nh7 cch n dng 2A 2:c hQ s$ v chuyAn chuXi
chO ci vo trong CompileFileTransaction khng? C h5i ti chuy6n ti khng thch ci g
trong function 2 - ti sK ni cho c hay ti khng thch ci g: n vi phRm nguyn l SRP!
N c hai l do 2A thay 2Ti thay v m3t. N phW thu3c vo c/ chi tit cch 2:c hQ s$ lNn ch
23 xy d9ng v g;i transactions. Lm nh" v0y qu nhi@u trch nhi6m, Jasmine hIi - qu
sHc nhi@u."

"C1u lm ti ho<ng ln 8y, Alphonse - i! Alphonse!"

Ngay lc -y, cng m3t lc hng loRt s9 ki6n x/y ra. Ti th-y cnh cCa 2 m; ra. Ti nh0n ra
chic gh bn cRnh tr(ng rXng. Ti nghe ting v:ng c*a gi:ng ti nhRi Jasmine cn d3i lRi t&
m-y bHc t"Dng. V, h$n ht, ti th-y Jasmine 2ang 2Hng ngay cCa ra vo.

fi m?t nng lRnh nh" ti@n.

cn tip.... khng bit ch&ng.



-1- Nguyn b/n ting Anh tc gi/ ch$i chO SRP thnh ESS ARE PEE. CWm ny hnd khng bit ph/i dFch ra sao cho
Tn nn dFch trRi thnh "ch l b" cho d d5m. Nu c bRn no c kin no hay, xin 2ng .

-2- "the sharpest knife is the drawer", m3t ngRn ngO m ch< cho m3t c nhn no 2 ti gi5i nh-t trong nhm hoLc
m3t vi6c g 2 t(t nh-t trong hon c/nh cho php.

-3- Cc t& lng "hottie", "hot stuff", "over-temp", exotherm", "boiling point", "tepid breath", "latent heat", "electron
volt", "fever man" dng trong bi c ch* gia tUng c"Dng 23. NhOng t& ny 2@u dng 2A 2@ cao m3t c nhn m3t
cch d d5m, thn m0t v cht g 2 ch diZu. hnd tRm dFch nhOng t& ny l "cao nhn", "ng mnh", "ng t"7ng",
"ho/ qun", "ng kY", "ng th>n", "2Ri nhn", "2Ri cao th*" v bit ch?c l khng thA tm cc t& hm h<nh ting
Vi6t t"$ng t9 2A chuyAn dFch cho mXi chO lng ting Anh ny.

-4- "Jazzy-wazzy" c[ng l m3t cWm t& lng ch< cho s9 ngon lnh, nhu>n nhuyZn, v&a . hnd tRm dFch l "qu 2"
2A bnh dn ho t& lng ny.

-5- "Egad, Auriculatum": Egad l m3t cch g:i c/m thn t"$ng t9 nh" "oh God!" v Auriculatum c nguQn g(c t&
ting Latin, ch< cho b3 "nghe" hoLc miu t/ hnh dRng gi(ng nh" chic l, hoLc vnh tai. Ngoi ra, "auricula" cn
m3t s( nghEa bng khc. CWm "Egad, Auriculatum" ny c thA dFch nm na l "i trDi, nghe 2y" nh"ng hnd 2A
nguyn vUn cho thm ph>n.... ba ch ;)

-6- CWm "you are cooking" l m3t idiom r-t phT bin, ch< cho s9 tin triAn 2ng h"7ng v t(t 2Yp.

-7- "Grandiflorum" t& grandiflora ting La tinh ch< cho gi(ng hoa hQng m:c theo dRng bWi, khm. T& ny m ch<
cho nO gi7i. \ trn JJ g:i Alphonse l 2Ri nhn nn bn d"7i hnd tRm dFch theo l 2Ri n"$ng cho kh7p v7i tinh
th>n.

-8- "Night Bloomer" ch< cho cc gi(ng hoa n; ban 2m nn tRm dFch l DR H"$ng.

-9- "Single Responsibility Principle" tRm dFch l nguyn l trch nhi6m 2$n.

-10- "SRP" hay Single Responsibility Principle, xin 2:c thm ti li6u ting Anh ;:
http://www.objectmentor.com/resource...icles/srp.
The Crafsman 16.
Excess Politesse

Qu m>c bJt thi.p

Khi chng 8 nhIn xu0ng v h6 thPn, m&t 8 nNng cn vO chuy,n thi 8& gip Alphonse
hon thnh m ngu@n - v nng Jasmine m#i ny lm chng c*c kW kh chLu.

Robert C. Martin

Jasmine 2Hng 2, nhn ti chPm chLp. Sau m3t pht im lLng cUng thVng, nng 2/o m?t, l?c
2>u v r/o thVng 2n ti. "Alphonse", nng ni m3t cch nghim kh?c, "2&ng bao giD ti
diZn tr 2 nOa." Qu x-u hT, ti g0t 2>u v ni, "vng, Jasmine."
"V t& ry v@ sau, g:i ti l c J." "Vng.... c J," ti ch(ng ch. BPng ci khFt m[i kh
khan, nng ni, "hy xem thC c0u 2 lm nhOng g." Ti ch< cho nng xem 2oRn m
FileCarrier v cc 2oRn tests. Lc 2>u nng c v4 tho/ mn nh"ng rQi nng ni, "FileCarrier
2:c hQ s$ bPng m3t c 2:c 2$n v vit bPng m3t c vit 2$n."

public class FileCarrier implements Serializable {
private String fileName;
private char[] contents;

public FileCarrier(String fileName) throws Exception {
File f = new File(fileName);
this.fileName = fileName;
int fileSize = (int)f.length();
contents = new char[fileSize];
FileReader reader = new FileReader(f);
reader.read(contents);
reader.close();
}

public void write() throws Exception {
FileWriter writer = new FileWriter(fileName);
writer.write(contents);
writer.close();
}

public String getFileName() {
return fileName;
}

public char[] getContents() {
return contents;
}
}

"Ph>n ny c thA lm vi6c cho cc v dW nh5," nng tip tWc, "nh"ng ti chVng dm ch?c
ph>n 2:c sK khng kt thc s7m, v n ch< trm m3t ph>n c*a chuXi. H$n nOa, hQ s$
chuyn ch; qua socket 2n m3t h6 th(ng khc, h6 th(ng ny khng bit ch&ng 2ang dng
m3t loRi k t9 kt thc dng kiAu khc. B;i th, ti khng nghE FileCarrier sK lm vi6c ngon
lnh xuyn qua cc h6 th(ng bn ngoi. Mnh nn lm g 2y Alphonse?"
Ti khng st m3t m/y. "... D... c J, c lK chng ta nn 2:c v vit cc hQ s$ mXi l>n m3t
dng v chuyn ch; nhOng hQ s$ ny theo danh sch cc dng."

"f"#c rQi, Alphonse. C0u thay 2Ti n nh" v0y 2i." T&ng cht m3t, ti thay 2Ti FileCarrier.
Ti 2Lc bi6t cBn th0n v7i vi6c lm cc tests c thA chRy. Khi m:i thH 2u vo 2, ti refactor
class ny cho n 2:c v vit r rng v sRch sK ; mHc t(i 2a.

public class FileCarrier implements Serializable {
private String fileName;
private LinkedList lines = new LinkedList();

public FileCarrier(String fileName) throws Exception {
this.fileName = fileName;
loadLines();
}

private void loadLines() throws IOException {
BufferedReader br = makeBufferedReader();
String line;
while ((line = br.readLine()) != null)
lines.add(line);
br.close();
}

private BufferedReader makeBufferedReader() throws FileNotFoundException {
return new BufferedReader(
new InputStreamReader(
new FileInputStream(fileName)));
}

public void write() throws Exception {
PrintStream ps = makePrintStream();
for (Iterator i = lines.iterator(); i.hasNext();)
ps.println((String) i.next());
ps.close();
}

private PrintStream makePrintStream() throws FileNotFoundException {
return new PrintStream(new FileOutputStream(fileName));
}

public String getFileName() {
return fileName;
}
}

"Hay l?m Alphonse," nng ni. "Nh"ng ti khng nghE FileCarrierTest th9c s9 b/o 2/m
FileCarrier ti l0p hQ s$ m3t cch c>n mNn. Ti mu(n xem thm vi ci tests."
Lc ny nng ht sHc bLt thi6p. M3t l>n nOa, ti d9ng 2oRn m t&ng ph>n m3t, giO cho cc
tests vNn chRy 2"#c trong khi thay 2Ti m nguQn. Ti refactor cho 2n khi m nguQn sRch
v r rng t7i mHc t(i 2a ti c thA lm 2"#c. Ti khng mu(n tRo thm b-t cH l do no
lm cho nng nTi cu nOa.

public class FileCarrierTest extends TestCase {
public void testFileCarrier() throws Exception {
final String ORIGINAL_FILENAME = "testFileCarrier.txt";
final String RENAMED_FILENAME = "testFileCarrierRenamed.txt";
File originalFile = new File(ORIGINAL_FILENAME);
File renamedOriginal = new File(RENAMED_FILENAME);

ensureFileIsRemoved(originalFile);
ensureFileIsRemoved(renamedOriginal);

createTestFile(originalFile);
FileCarrier fc = new FileCarrier(ORIGINAL_FILENAME);
rename(originalFile, renamedOriginal);
fc.write();

assertTrue(originalFile.exists());
assertTrue(filesAreTheSame(originalFile, renamedOriginal));

originalFile.delete();
renamedOriginal.delete();
}

private void rename(File oldFile, File newFile) {
oldFile.renameTo(newFile);
assertTrue(oldFile.exists() == false);
assertTrue(newFile.exists());
}

private void createTestFile(File file) throws IOException {
PrintWriter w = new PrintWriter(new FileWriter(file));
w.println("line one");
w.println("line two");
w.println("line three");
w.close();
}

private void ensureFileIsRemoved(File file) {
if (file.exists()) file.delete();
assertTrue(file.exists() == false);
}

private boolean filesAreTheSame(File f1, File f2) throws Exception {
FileInputStream r1 = new FileInputStream(f1);
FileInputStream r2 = new FileInputStream(f2);
try {
int c;
while ((c = r1.read()) != -1) {
if (r2.read() != c) {
return false;
}
}
if (r2.read() != -1)
return false;
else
return true;
}
finally {
r1.close();
r2.close();
}
}
}

Nng thBm tra m nguQn trong khi ti vit v khng h@ nhn ti - ngay c/ m3t l>n. Kh/
nUng t0p trung v phn cc cu nh0n 2Fnh c*a nng cn h$n hVn thi 23 lRnh lng kiAu
cch c*a nng.

"T(t l?m, m nguQn sRch 2 Alphonse. Ti thch cch c0u b/o 2/m hQ s$ nguyn thue 2"#c
2Lt tn lRi v hQ s$ m7i 2"#c tRo ra. Khng c 2i@u g c thA nghi ngD rPng FileCarrier tRo
hQ s$ ; 2y. C[ng khng c cch no hQ s$ c[ bF b5 r$i. Nh"ng ti ch"a th-y method
filesAreTheSame bF h5ng. C0u c nghE l n th9c s9 lm vi6c 2u vo 2 khng?"
Ti chVng th-y m3t t s$ st no trong m nguQn, nh"ng ti khng c 2Fnh kiAm chHng
trong khi thiu bPng chHng. B;i th ti b?t 2>u vit vi ci tests cho method
fileAreTheSame. f>u tin, ti vit m3t ci test chHng minh method ny lm vi6c ngon lnh
cho hai hQ s$ nh" nhau. RQi ti vit m3t ci test khc chHng minh hai hQ s$ khc nhau
khng mang lRi kt qu/ so snh bPng nhau. Ti vit tip thm m3t ci test nOa 2A chHng
minh rPng nu hQ s$ ny l ti@n hi6u (prefix) c*a hQ s$ kia th sK khng thA so snh.

Kt cWc ti vit tTng c3ng nUm tr"Dng h#p test khc nhau v chng c c/ l m trng lLp:
MXi test vit hai hQ s$. MXi test so snh hai hQ s$. MXi test xo hai hQ s$. fA loRi tr& ph>n
trng h#p ny, ti dng mNu thit k@ Template Method. Ti dDi tr:n b3 cc ph>n m chung
vo trong m3t abstract class n@n g:i l FileComparator, rQi dDi tr:n b3 cc ph>n m khc
bi6t thnh dRng v danh (anonymous). V th l mXi tr"Dng h#p thC nghi6m tRo m3t ph
b/n 2A dng khng g h$n ngoi n3i dung c*a hai hQ s$ v tinh th>n c*a giai 2oRn so snh.

public class FileCarrierTest extends TestCase {

private abstract class FileComparator {
abstract void writeFirstFile(PrintWriter w);
abstract void writeSecondFile(PrintWriter w);

void compare(boolean expected) throws Exception {
File f1 = new File("f1");
File f2 = new File("f2");
PrintWriter w1 = new PrintWriter(new FileWriter(f1));
PrintWriter w2 = new PrintWriter(new FileWriter(f2));
writeFirstFile(w1);
writeSecondFile(w2);
w1.close();
w2.close();
assertEquals("(f1,f2)", expected, filesAreTheSame(f1, f2));
assertEquals("(f2,f1)", expected, filesAreTheSame(f2, f1));
f1.delete();
f2.delete();
}
}

public void testOneFileLongerThanTheOther() throws Exception {
FileComparator c = new FileComparator() {
void writeFirstFile(PrintWriter w) {
w.println("hi there");
}

void writeSecondFile(PrintWriter w) {
w.println("hi there you");
}
};
c.compare(false);
}

public void testFilesAreDifferentInTheMiddle() throws Exception {
FileComparator c = new FileComparator() {
void writeFirstFile(PrintWriter w) {
w.println("hi there");
}

void writeSecondFile(PrintWriter w) {
w.println("hi their");
}
};
c.compare(false);
}

public void testSecondLineDifferent() throws Exception {
FileComparator c = new FileComparator() {
void writeFirstFile(PrintWriter w) {
w.println("hi there");
w.println("This is fun");
}

void writeSecondFile(PrintWriter w) {
w.println("hi there");
w.println("This isnt fun");
}
};
c.compare(false);
}

public void testFilesSame() throws Exception {
FileComparator c = new FileComparator() {
void writeFirstFile(PrintWriter w) {
w.println("hi there");
}

void writeSecondFile(PrintWriter w) {
w.println("hi there");
}
};
c.compare(true);
}

public void testMultipleLinesSame() throws Exception {
FileComparator c = new FileComparator() {
void writeFirstFile(PrintWriter w) {
w.println("hi there");
w.println("this is fun");
w.println("Lots of fun");
}

void writeSecondFile(PrintWriter w) {
w.println("hi there");
w.println("this is fun");
w.println("Lots of fun");
}
};
c.compare(true);
}
}

"Alphonse, qu tuy6t." ChuBn y chnh thHc c*a nng th0t khc xa thi 23 lRnh lng th"Dng
l6 lm ti cH mu(n go ln.
"Ti thch cch c0u xC dWng mNu thit k Template Method 2A loRi tr& s9 trng lLp. Nhi@u
tay h:c vi6c khng h:c cc mNu thit k cho 2n khi h: bF p ph/i h:c. Ti c[ng thch cch
c0u thC nghi6m ph>n so snh n3i t"$ng (communitavity of equality). M:i ph>n so snh 2@u
x/y ra song ph"$ng. Tuy6t h/o!"
"Cm $n c J," ti l nh, th; pho nhY nhm khi bit ch?c mnh khng lm h" s9 l>n ny.
The Crafsman 17.
Call The Guard

G-i bCo k

D* ki.n chuy,n t, h/i nh2t sau khi "84ng" v#i Jasmine, Alphonse h+c 8"7c cch dng m#i
cho 8iOu ki,n cch if - v khm ph bn trong ngo/i di,n bnh th"Vng cAa ng"Vi h"#ng dQn
m#i hm ch3a m&t ci 8u tX mX - ch"$ng 17

Robert C. Martin

Nh0t k thn mn: Tu>n h:c vi6c 2>u tin c*a ti v7i ng C 2 hon t-t. Ti h:c 2"#c th0t
nhi@u nh"ng ti c[ng 2 lm r(i lung tung c/ ln. HQi thH Hai, Jerry yu c>u ti vit m3t
ch"$ng trnh 2A tRo s( nguyn. fn thH Ba, g lRi yu c>u ti vit ch"$ng trnh tRo s(
nguyn t(. Tr:n ngy thH T" dnh cho vi6c lm SocketServer c thA chRy 2"#c. ThH NUm
chng ti b?t 2>u lm vi6c v7i SMCRemoteClient v ti 2 Micahed -1- Jerry. Ti gLp
Jasmine chi@u hm -y trong phng khch c*a cc tay du mWc -2-. Nh"ng 2n thH Su lRi l
m3t ngy ti x-u hT nh-t trong 2Di. Ti khng gLp lRi Jasmine (Ms. J) t& khi chng ti hon
t-t cng vi6c chi@u thH Su. Qu/ l m3t tu>n "ln voi xu(ng ng9a" -3-

Ti tr/i qua m-y ngy cu(i tu>n b6 rRc, ch?c mBm th no c[ng bF chuyAn sang b3 ph0n v6
sinh v ti dWng, d:n rCa l ph/n Hng hoLc kb c: m7 ru m(c. Ti chVng mng mLc qu>n o
hay Un u(ng.

D g 2i chUng nOa, by giD l t(i thH Hai v ti 2ang vit 2A kA c0u nghe s9 thA c*a ngy
2>u trong tu>n thH nh. N c[ng khng qu t6. Th0t ra ti b?t 2>u c/m th-y ph-n ch-n tr;
lRi.

Sng hm nay, ti thHc d0y trong lng nLng trEu. Sau khi dng xong 2iAm tm, ti lt thch
l 2n phng lm vi6c, ph5ng ch&ng c J 2ang 2#i ti ; bn my nh"ng thay vo 2 l m3t
phW nO trung tu>n 2Ny 2 v7i m7 tc 2iAm s"$ng ngang vai v nW c"Di hi@n t&, nW c"Di t
nhi@u cn ph/ng ph-t d-u -n c*a nhOng nUm t"$i tr4 ngy tr"7c. Lc nhn ti, m?t b nh-p
nhy v b c"Di khK. "C0u hVn l Alphonse," b ni, 2"a tay ra. "Ti tn l Jean. Ti nghe
kh nhi@u v@ c0u. C0u 2i bWng khng? Ti c m3t t bnh m sandwich ngon l?m trong gi5
nu c0u mu(n, hay c0u thch m3t qu/ to hay m3t tri chu(i."

Qu/ th0t c chic gi5 to trn sn cRnh n$i b ngQi. Trng ch&ng nh" n khng ch< chHa
sandwich v chu(i. B(i r(i, ti b?t tay b v ni, "dR vng, th"a b - ti, khng th"a b -
ti - vng, ti 2ng l Alphonse, v khng, cm $n b 2 mDi ti sandwich v ti - "Dm...
D.... r-t vui khi 2"#c gLp b."

B nhn ti m3t cch nghim kh?c nh"ng ci nhch mp ph/ng ph-t nt hi@n t& c*a m3t
ng"Di mY. "Ny, chng ta khng l>n khn v7i ci m7 "B" ng7 ngBn 2 nghe ch"a. Ti nh-t
2Fnh khng ph/i l "B" c*a ai c/. C0u g:i ti l Jean thi, c0u b thn mn."

aDm, cm $n Jean," ti tr/ lDi. "V0y c J 2u nh<?"

"Ai th c0u b?"

"m... Jasmine 2," Ti tr/ lDi m3t cch miZn c"Ing. "LK ra c ta v ti lm vi6c chung v7i
nhau."

"i giDi, tr"7c giD ti ch"a h@ nghe ai g:i c ta l c J c/. Ch?c c nng bu3c c0u g:i nh"
th ph/i khng? Ti khng nghE c ai g:i c ta g khc ngoi ci tn Jasmine. Con b th0t
2ng yu, ph/i khng nh<? M thi, c0u b thn mn, hi6n tRi ng C mu(n c ta lo cng vi6c
khc, cho nn t& ry v@ sau ti sK lm vi6c v7i c0u."

"B?" ti 27 ng"Di ra. "," ti lLp bLp. "i..."

"No, c0u ngQi 2y 2i c0u b thn mn v 2A ti ni cho c0u nghe ti 2ang nghE g," Jean
ni, trong khi khi vX nhY trn chic gh cRnh b.

"fang nghE g?"

"Ti xem xt ch"$ng trnh ny trong su(t nCa giD qua - ti thch lm vi6c s7m, c0u bit
khng -- nh"ng chVng ph/i s7m h$n th"Dng l6 g 2u -- ti bit m3t c0u con trai 2ang l7n
th c>n ng* v 2iAm tm. M thi, ti r-t hi lng v7i ch"$ng trnh ny. C0u c m3t chuXi
test r-t l th v ph>n m nguQn r-t dZ 2:c, c-u trc lRi g:n gng. Nh"ng c m3t 2i@u lm
ti th?c m?c, c0u b thn mn."

"m -- th?c m?c?"

"fng th c0u b! Ti xem xt kh?p n$i trong ch"$ng trnh ny v khng h@ th-y hm
main. Khi no c0u sK vit ph>n ny v0y h; c0u?"

"m, , Jerry ni l -" ti l0p bLp.

"^, 2A ti 2on thC Jerry ni g. Jerry l m3t thPng b 2ng yu," Jean ng?t ngang, 2i m?t
b nh-p nhy. "Nh"ng ti nghE 2i khi c0u ta nn c>n thm manh m(i 2A l gi/i v-n 2@.
Nh"ng thi, ti khng nn c kin khng t(t v@ ng"Di khc. Jerry l m3t l0p trnh vin
gi5i, c0u b thn mn, c0u 2&ng 2A 2n nhOng 2i@u ti ni nh. No, hy vit hm main.
C0u mu(n b?t 2>u khng? Sng nay m-y ngn tay ti h$i bF cHng. Hy nghe ti khuyn
ny," b c"Di khc khch "2&ng bF lo ho."

f7 ng"Di ra t& m3t chuXi ngn t& thPng tuQn tu3t c*a b, ti nhn l-y bn phm v b?t 2>u
g:

public void main(

", no no, c0u b thn mn!" Jean ng"ng ti lRi. "C0u lm vi6c ; 2y 2"#c bao lu rQi
nh<? c0u ph/i vit m3t ci test tr"7c - c0u khng thA c?m 2>u vo vit hm main ngay nh"
v0y 2"#c! Chng ta sK 2i v@ 2u nu ai c[ng vit m-y ci hm m khng vit tests tr"7c?
Ti c thA cho c0u bit: (chng ta sK ;) trong m3t qu/ d"a chua! -4- Khng, c0u b, xo n
2i v vit ci test tr"7c."

B l-y ra t& trong gi5 m3t 2i que 2an v b?t 2>u lm vi6c v7i m3t m/nh y phWc nhi@u mu
c hnh dng na n nh" m3t m/nh khUn chong -5-, khe khK ngm nga m3t giai 2i6u 2$n t4
trong khi ti xo m7 chO v&a vit xong v b?t 2>u lRi.

Lm cch no 2A test hm main? cch t(t nh-t l g:i n v b/o 2/m n lm nhOng g n
nn lm. Hm main gi/i dFch cc thng s( trn dng l6nh, b;i th, g:i n ch< 2$n thu>n l
vi6c chuyAn cc thng s( cho 2ng. Th nn ti b?t 2>u g lRi:

public void testMain() throws Exception {
SMCRemoteClient.main(new String[]{"myFile.sm"});

Jean gh m?t nhn v b/o, "t(t 2, nh"ng ; 2u ra ci myFile.sm v0y? Mnh khng thA 2A
n nPm ngTn ngang nh" th 2"#c, ph/i khng no? Khng, mnh sK tRo n ; ngay 2y, ph/i
khng? v 2&ng qun xo n khi mnh 2 xong nh c0u b thn mn. Khng g t6 hRi bPng
m3t m7 hQ s$ c[ nPm chTng ch$, lc no ti c[ng b/o th."

Th rQi ti tip tWc g:

public void testMain() throws Exception {
File f = createTestFile("myFile.sm", "the content");
SMCRemoteClient.main(new String[]{"myFile.sm"});
f.delete();
File resultFile = new File("resultFile.java");
assertTrue(resultFile.exists());
resultFile.delete();
}

Jean hon t-t thm m3t dng (2an) trn m/nh khUn chong trong khi ti g m. B ng"7c
ln nhn khi ti hon t-t v ni: "No, c0u b, m rQi 2, nh"ng th0t tnh ti nghE main c
thA khng 2* thDi gian 2A hon thnh trch nhi6m tr"7c khi phn 2oRn xo 2 c tc dWng.
Nn nh7 c0u b, c0u c hng l cc socket threads 2ang chRy v dZ th-y trong m7 thread
ny c m3t thread vNn 2ang chRy ngay khi main tr/ v@. Khng, c0u b, khoan hSn lm g c/
ngay lc ny; ch< ghi nh7 trong 2>u thi. By giD c0u nn vit main, ph/i khng?"

Ti t9 nh* b gi ny kh s?c s/o v b?t 2>u vit ph>n hm main.

public static void main(String[] args) {
SMCRemoteClient client = new SMCRemoteClient();
client.setFilename(args[0]);
if (client.prepareFile())
if (client.connect())
if (client.compileFile())
client.close();
else { // compileFile
System.out.println("failed to compile");
}
else { // connect
System.out.println("failed to connect");
}
else { // prepareFile
System.out.println("failed to prepare");
}
}

"i chao $i, xem c th0t s"7ng m?t khng! Ti nghE cch c0u ch thch nhOng 2oRn 2i@u
ki6n cch else r-t mNn 2Rt. DNu v0y, ti khng bit nu c0u thC 2/o ng"#c c*a cc 2oRn
2i@u ki6n cch v dng chng nh" nhOng ph>n b/o k th c dZ 2:c h$n khng. f&ng, c0u
b thn mn, hSng khoan 2Ti n. Hy xem n c chRy 2"#c hay khng ci 2. Khng 2ng
2A thay 2Ti qu nhi@u thH cho 2n khi mnh bit ch?c ch"$ng trnh c lm vi6c hay khng,
c0u 2Qng khng no? f>u tin lm cho n chRy tr"7c, rQi m7i lm cho n ch<nh sau."

Th rQi ti chRy thC ci test, v n lm vi6c ngon lnh ngay l>n 2>u.

"^, 2ng l ngoRn mWc!" B ta ni trong khi gh m?t nhn. "By giD chng ta thC thay 2Ti
ph>n 2i@u ki6n cch if."

Th rQi ti 2Ti hm cho ph>n 2i@u ki6n cch if 2"#c b/o v6.

public static void main(String[] args) {
SMCRemoteClient client = new SMCRemoteClient();
client.setFilename(args[0]);
if (!client.prepareFile()) {
System.out.println("failed to prepare");
return;
}
if (!client.connect()) {
System.out.println("failed to connect");
return;
}
if (!client.compileFile()) {
System.out.println("failed to compile");
client.close();
return;
}
client.close();
}

Jean 2Lt m7 2Q 2an vo gi5 v xem xt kd l"Ing 2oRn m. "RQi, ti xem n 2"#c h$n m3t
cht rQi 2, ti khng c cm rm ph>n lLp ; 2oRn close. V tnh ch-t vi phRm trong l(i
nh0p 2$n, xu-t 2$n, m-y ci ny h$i bF v"7ng vu m3t cht. DNu v0y, n cn b/nh h$n m7
dng m nguQn 2"#c 2By vo (t& l@ bn tri) -6-, c0u 2Qng khng no? T-t nhin chng
ta c thA thay 2Ti ba hm 2 cho php chng throw exceptions -7-, nh"ng rQi chng ta ph/i
catch -7- chng, v th c[ng kh phi@n. Thi, by giD cH 2A yn nh" v0y. No, ti nghE 2
2n lc gi/i lao, ph/i khng c0u b? C0u thch mang dm ti chic gi5 xch ny vo phng
Un khng? Ti lun c thi nhQi nht vo gi5 nhi@u h$n c>n thit v sau t lu ci c*a kh<
ny tr; nn nLng trnh trFch."


-1- T& ny 2 2"#c gi/i thch m3t l>n trong ph>n 13 - "M3t gi/i php t(t h$n". "Micah" ; 2y, trong bi ny, c lK
l m3t loRi 2Lc quy@n hoLc m3t vinh d9 l7n lao. Theo t9 2iAn Merriam-Webster th Micah l tn c*a m3t nh tin tri
ng"Di Do Thi ; th ke thH 8 sau Cng nguyn. "Micah" pht triAn t& nguyn th*y MIkhAyAh (ting Hebrew).

-2- journeymen 2 2"#c ch thch ; bi 14 - Transaction Actions. Journeymen c nghEa bng ch< cho nhOng tay lo
luy6n trong ngh@ v thch "lang thang" 2i tm nhOng chn trDi m7i.

-3- "roller-coaster week": roller-coaster l m3t loRi xe tr"#c chRy vng vo theo c-u trc d9ng sSn c*a m3t gin
gio. Xe l"7t trn roller-coaster v7i v0n t(c nhanh v ln xu(ng theo c-u trc d9ng sSn. \ 2y, tc gi/ hnh t"#ng
ho m3t tu>n lm vi6c c*a Alphonse nh" 2i roller-coaster ch< cho m3t tu>n 2i qua r-t nhanh v ; trRng thi "khi
ln, khi xu(ng". Ti tRm dFch l m3t tu>n ln voi, xu(ng ng9a cho g>n v7i ting Vi6t.

-4- in a pickle, m3t ngRn ngO ch< cho tnh trRng hoLc mi tr"Dng khng hay v khng dZ thot ra. "Pickle" l m3t
loRi d"a chua trong d-m v dW nh" tri d"a leo * chua (ng"Di chu u, chu Md v chu c r-t thch Un loRi ny).
hn th thch nh"ng thC t";ng t"#ng bF * trong m3t tri d"a chua th sao?

-5- shawl, m3t loRi khUn chong 2>u v vai dnh cho ma lRnh. C lK t& "khUn s" 2i t& chO shawl ny chUng? T&
2Qng nghEa ting Php l "chle", c[ng 2:c nm na l "s". ChO shawl ting Anh c nguQn g(c t& chO "shAl" ting
Persian (ng"Di Iran cT 2Ri). Ti ch"a tm ra 2"#c chnh xc nguQn g(c chO "khUn s" c*a ting Vi6t. C nguQn cho
rPng "khUn s" 2i t& g(c v/i s chuyn dng lm khUn chong, c[ng c nguQn cho rPng "khUn s" l m3t dRng t&
vay m"#n t& ting n"7c ngoi. Ai c hHng th (v thDi gian) kh/o cHu (v@ ngn ngO h:c), xin 2ng gp kt qu/ v
kin.

-6- indentation, l(i 2By dng chO thWt vo t& l@ trang gi-y (t& bn tri hoLc bn ph/i).

-7- throw exceptions v catch exceptions, c lK dn l0p trnh nhn nhn cht 2<nh 2n Java hVn bit cc thu0t ngO
ny. Ti 2A nguyn thu0t ngO ny m khng c( g?ng dFch v c thA lm sai lRc khi c( g?ng chuyAn ngO.
The Crafsman 18
Slow and Steady

ChKm m chLc

"f"#c rQi c0u b thn mn, ti nghE 2 2n lc chng ta b?t 2>u lm vi6c v7i ph>n server
c*a ch"$ng trnh ny, ph/i khng c0u b? fn lc ny ph>n client lm vi6c c v4 ngon lnh
nh" chng ta th-y 2"#c, v m3t client m khng c server th trng c 2$n qu. C0u 2Qng
khng no?"

Jean 2 an toR trong chic gh bnh c*a b. Trong khi ni, b vi tay vo trong gi5 v li ra
b3 2Q 2an. Chic s (hay ci g 2) 2 di ra m3t cch 2ng kA sau buTi gi/i lao (kho/ng
thDi gian ti bit 2"#c v@ con v chu c*a Jean).

", server?" Ti ch< c thA rLn ra hai t& ny 2A tr/ lDi m3t trng pht biAu c*a Jean.

"fng v0y, c0u b thn mn, server. Server s?p sCa nh0n hQ s$ m c0u 2 chUm ch g;i,
l"u trO vo 2Ea v bin dFch n v7i SMC. Nn nh7 c0u b, chng ta 2ang xy d9ng m3t trnh
dFch t& xa cho SMC, State Machine Compiler. By giD, c0u b thn mn $i, chng ta nn vit
test case 2>u tin ra sao?"

Test case g 2y hIi? ti g?ng v?t c nghE ng#i v@ chuy6n ny. Pha server c*a ch"$ng trnh
l?ng nghe trn m3t socket v nh0n cc CompileFileTransaction objects. NhOng object ny
chHa cc gi -1- hQ s$ trong cc sub-objects -2- FileCarrier. Server c>n vit nhOng hQ s$
2"#c gi ny 2n m3t n$i an ton trn 2Ea, bin dFch chng v g;i kt qu/ ng"#c lRi client
trong m3t object g:i l CompilerResultsTransaction.

fi@u 2>u tin ti lo ngRi l cch bin dFch cc hQ s$ ny. BPng cch no 2, chng ta c>n
g:i trnh dFch v 2i h5i n bin dFch hQ s$ 2 l"u.

"m.... mnh c thA vit ci test case cho phn 2oRn g:i trnh dFch khng nh<?"

Jean m<m c"Di theo l(i b ngoRi m<m c"Di v7i 2Ha chu ch0p chOng b"7c 2i 2>u tin. "Sao
lRi khng, t-t nhin rQi c0u b thn mn, kh;i 2>u ; 2iAm ny th vF 2y. C0u bit cch g:i
trnh dFch khng? Hy xem, ti nghE chng ta ch< d9ng 2ng dng l6nh v g:i n thi. No,
c php dng l6nh -y sao nh<? f lu ti khng m 2n SMC, ti chVng nh7 r. Nghe 2y
c0u b, g thC l6nh ny: java smc.Smc. fng rQi 2 c0u, by giD xem thC n bo lXi g?
Class def not found? ^ vng, chng ta qun ci classpath. f&ng bF lo ho nha c0u b, c0u
sK b?t 2>u qun 2* thH. G ci ny: java -cp C:/SMC/smc.jar smc.Smc -3-. T(t rQi, v0y
thng 2i6p -y ni g v0y?"

Thng 2i6p trn mn hnh bo lXi cch dng v m t/ m:i thng s( c>n thit 2A dng SMC.

".. 2 l m3t thng 2i6p ch< dNn cch dng."

"fng rQi c0u b, 2ng rQi. V hnh nh" mu(n g:i SMC, chng ta dng l6nh sau: java -cp
C:/SMC/smc.jar smc.Smc -f myFile.sm. fQng ch7 c0u b? Sao c0u khng thC vit m3t ci
test case dng 2A tRo dng l6nh -y?"

Th nn ti tRo m3t unit test class tn l SMCRemoteServerTest.

public class SMCRemoteServerTest extends TestCase {
public void testBuildCommandLine() throws Exception {
assertEquals("java -cp C:/SMC/smc.jar -f myFile.sm",
SMCRemoteServer.buildCommandLine("myFile.sm"));
}
}

V ti6n thA ti vit lun SMCRemoteServer.

public class SMCRemoteServer {
public static String buildCommandLine(String file) {
return null;
}
}

"T(t l?m, c0u b thn mn. Ci test bF h5ng nh" d9 t";ng. C0u h:c vi6c kh l?m. By giD
lm cho n 2Rt l chuy6n 2$n gi/n, ph/i khng no?"

"m.... hVn nhin rQi."

public static String buildCommandLine(String file) {
return "java -cp C:/SMC/smc.jar smc.Smc -f " + file;
}

"T(t rQi c0u b, chRy thC ti xem no? T(t. i! LR nh<, ci test bF h5ng rQi c0u b thn mn,
chuy6n g 2 x/y ra nh<?"

Thng 2i6p trn mn hnh l: expected:<......> but was: <...smc.Smc ...>. Ti cBn th0n
xem xt 2oRn m v nh0n ra ti qun ph>n smc.Smc trong test case. "... ti 2on l ti
vit sai 2oRn test."

"fng rQi, 2ng rQi. Vng, 2i khi chng ta vit test sai. Bugs -4- c thA x/y ra b-t cH n$i
no. f l l do tRi sao vit c/ test lNn m nguQn l vi6c nn lm. BPng cch ny, c0u vit
m:i thH hai l>n. Ti c c0u chu lm k ton cho tu v0n t/i, v c0u -y lun lun l"u cc chi
tit chuyAn ngn vo hai hQ s$ k ton ring bi6t. C0u -y g:i n l g nh<? ^, vng, sT sch
2i. -5- C0u -y ni rPng cch ny gip c0u ngUn ng&a v lWc tm cc sai st. V 2y chnh l
chuy6n chng ta 2ang lm, ph/i khng c0u b thn mn. Chng ta vit t-t c/ cc hm hai
l>n. M3t l>n trong ph>n test, v m3t l>n trong m nguQn. V n th0t s9 gip chng ta ngUn
ng&a v tm cc sai st, ph/i khng no?"

Trong khi b ta tip tWc v7i m thanh c*a gi:ng ni 2@u 2@u, 2$n t4, ti 2 sCa xong test
case. Jean l m3t b gi dZ th"$ng v r-t gi5i nOa nh"ng lX nhE c*a ti lng bng v7i l(i ni
khng ng&ng ngh< c*a b.

public void testBuildCommandLine() throws Exception {
assertEquals("java -cp C:/SMC/smc.jar smc.Smc -f myFile.sm",
SMCRemoteServer.buildCommandLine("myFile.sm"));
}

Thay 2Ti ny lm 2oRn test 2Rt.

"Tuy6t vDi, c0u b, tuy6t vDi; nh"ng 2oRn m h$i r(i, c0u nghE th khng? Hy d:n dYp n
tr"7c khi tip tWc. D:n 2(ng b&a b3n tr"7c khi chng b?t 2>u (tr; nn b&a b3n), ti lun ni
nh" th."

Ti xem 2oRn m v chVng th-y c g b&a b3n c/. Th nn ti ngoi lRi (v@ h"7ng Jean
ngQi) v ni: "m, b thch kh;i 2>u t& 2u v0y?"

"TrDi ph0t $i, sao h5i v0y c0u b, n 2$n gi/n nh" chic m[i trn khun mLt c0u v0y thi!
hm buildCommandLine 2 c>n ch<nh 2(n m3t cht. ChuXi string trong dng tr/ v@ 2>y tnh
gi/ 2Fnh v nh-t 2Fnh sK lm ai 2 2:c 2oRn m ny sK b(i r(i. Chng ta khng mu(n lm
cho ai b(i r(i c/, ph/i khng no? Ti mu(n ni l chng ta khng mu(n lm nh" th. fy
c0u, 2"a cho ti ci bn 2nh."

B 2Lt bQ 2Q 2an xu(ng (hnh nh" m/nh 2an b?t 2>u ph>n cT tay c*a ci khUn chong) v
v7i s9 c( g?ng r r6t 2A 2i@u khiAn bn 2nh, b g ch0m ri nh"ng 2>y ch* 2Fnh nh" thA
mXi c g lm b 2au 27n. R(t cu3c b thay 2Ti 2oRn tr/ lRi nh" sau:

return "java -cp " + "C:/SMC/smc.jar" + " " + "smc.Smc" + " -f " + file;

RQi b chRy thC 2oRn test v n 2Rt.

"RQi 2 c0u b thn mn, c0u th-y ch"a? Chng ta c>n thay th 2oRn string -y bPng cc gi
trF b-t bin 2A gi/i thch dng l6nh 2 2"#c hnh thnh bPng cch no. C0u mu(n lm th
khng, hay 2A ti?"

V4 2au 27n c*a b 2 2* tr/ lDi. Ti v7 l-y bn 2nh v thm vo cc gi trF b-t bin ti
nghE l b mu(n 2"a vo.

public class SMCRemoteServer {
private static final String SMC_CLASSPATH = "C:/SMC/smc.jar";
private static final String SMC_CLASSNAME = "smc.Smc";

public static String buildCommandLine(String file) {
return "java -cp " +
SMC_CLASSPATH + " " +
SMC_CLASSNAME +
" -f " + file;
}
}

"fng rQi c0u b thn mn, 2ch thF 2i@u ti mu(n. C0u khng nghE rPng nh" th sK gip
nhOng ng"Di khc sK dZ hiAu h$n sao? -6- Ti bit ch?c nu ti l h:, ti sK c/m th-y dZ
hiAu h$n. By giD, c0u b thn mn, sao c0u v ti khng 2i 2n phng gi/i lao 2A cho 2>u
c ngh< ng$i 2i cht nh<?"

fi@u g 2 n/y ra trong 2>u ti.

"Jean, chng ta ch"a lm 2"#c t g c/!"

"Sao c$, c0u th no, chng ta 2 hon thnh kh nhi@u rQi."

Ti chVng nghE 2n chuy6n ti 2ang ni v7i ai. Ti vNn m3t m9c l/m nh/m m3t cch 2>n
23n. "Chng ta ch< m7i xong m3t ci hm ngu xuBn m thi. Nu mnh giO ci 2 "con sn"
ny -7-, ng C sK thuyn chuyAn chng ta 2n b3 ph0n canh tc 2A d:n chuQng thi!" -8-

"Th0t th sao c0u b, tRi sao c0u lRi nghE ng7 ngBn 2n nh" v0y nh<? Ti lm vi6c v7i vUn
phng ny h$n ba m"$i nUm, c0u b thn mn, v ch"a bao giD c ai 2@ c0p 2n chuy6n
d:n chuQng."

B ta ng"ng ch(c lt nh" thA b 2ang tTng h#p cc nghE. RQi b nhn ti v7i ci nhn 2n
h0u nh"ng nghim kh?c hi6n r trn khun mLt.

"Alphonse thn mn, cch duy nh-t 2A hon thnh ch"$ng trnh ny nhanh chng l lm t(i
2a nhOng g c0u c thA. Nu c0u v3i v, hay nu c0u 2i 2"Dng t?t, c0u tr/ ph/i tr/ gi xHng
2ng trong giai 2oRn tm lXi. ng C tr/ cng cho thDi gian c*a c0u, c0u b, v ng -y mu(n
kt qu/ t(t nh-t c0u c thA lm 2"#c. M nguQn chnh l s/n phBm c*a c0u, c0u b thn
mn, v ng -y khng mu(n tr/ cho thH s/n phBm km ch-t l"#ng. ng ta khng mu(n
nghe rPng c0u hon t-t 2"#c ngy lm do v-y v cho xong chuy6n b;i v ng ta bit c0u sK
tr/ m3t gi r-t 2?c cho tnh v-y v. ng -y ch< mu(n thH m nguQn t(t nh-t m c0u c thA
vit 2"#c. ng ta mu(n m nguQn sRch, c nghEa l v 2 2"#c thC nghi6m cBn th0n ; mHc
t(i 2a c0u c thA tRo ra. V rQi, c0u b thn mn, ng C th&a bit rPng nu c0u lm nh"
v0y, c0u sK hon t-t nhanh chng h$n nhOng c0u ng(c non choYt kia cH ngI chng c thA
xong chuy6n nhanh h$n v7i thi nhch nhc. By giD, mnh hy 2i lm m3t chn tr nh<?"




-1- encapsulated: m3t thA trRng 2"#c gi bn trong m3t thA trRng, ph"$ng ti6n no khc. V dW, m3t Vector object
"encapsulate" cc object bn trong v cc object ny c thA khc nhau v@ tnh ch-t v thA loRi. Hay ni ng"#c lRi,
cc object bn trong m3t Vector 2"#c encapsulated.

-2- sub-objects: cc thA trRng (object) ng>m. V dW, m3t Vector chHa cc object v cc object ny chHa nhOng
object khc bn trong.

-3- Trong nguyn b/n tc gi/ cho php t/i smc.jar t&: http://www.objectmentor.com/resource.../smc_java

-4- Bugs: lXi v v-n 2@ trWc trLc trong l0p trnh. T& "bug" ny ht sHc thng dWng v 2Lc th cho nn ti dng t&
nguyn thue thay v c( dFch sang m3t t& t"$ng 2"$ng ting Vi6t (nh" m3t s( t& khc 2 2"#c dng trong su(t
series Craftsman ny).

-5- dual entry bookkeeping: hQ s$ k ton 2"#c ghi nh0n v l"u giO hai n$i khc nhau. Trn th9c t, ti khng r
c ph"$ng php k ton nh" th ny khng nh"ng 2y l chi tit dng 2A lin h6 2n v-n 2@ vit test v vit code
nn 2"#c ghi nh0n l m3t chi tit quan tr:ng.

-6- Cu ni ; dRng negative (negative form) 2Lc bi6t 2"#c nhn v0t Jean dng th"Dng xuyn. C lK tc gi/ mu(n
tRo nhn v0t Jean ny v7i c tnh r-t m@m m5ng v nhY nhng trong khi trao 2Ti. Tuy nhin, nhOng 2i@u Jean 2"a
ra r-t xc th9c v c>n thit cho d l(i ni c*a b ta r-t dng di.

-7- snail's pace: mHc 23, t(c 23 c*a con sn. ni s9 vi6c tin triAn r-t ch0m chRp.

-8- Clean out the Dribin cages: ti khng tm 2"#c nguQn g(c c*a cWm t& ny. f3c gi/ c ai r, xin gp .

The Crafsman 19.
Tolerance

Kin nhn

Jean 2"a ti 2n thang my 2A xu(ng t>ng ng>m 36 thu3c cnh gamma, phng khch c*a
cc tay du mWc. B ni t>ng ng>m ny -1- lm cc kh7p x"$ng c*a b ht sHc dZ chFu. Khi
chng ti 2n n$i, ti th-y c Jerry, Jasmine v m3t vi tay du mWc 2ang tW lRi m3t bn.
Jean c[ng th-y h: v r/o b"7c 2n n$i h: ngQi. Ti miZn c"Ing 2i theo.

"Cho cc c, cc c0u thn mn!" B th(t ln m&ng rI nh" thA khng gLp h: sau nhi@u tu>n
lZ. B:n h: 2@u cho lRi c[ng v7i v4 thn m0t (nh" b dnh cho h:). Th rQi b co lXi v
r/o b"7c v@ chic gh 2-m bp b5 tr(ng, 2A lRi m3t mnh ti 2(i di6n v7i hai c9u hu-n luy6n
vin.

"Cho Jerry; cho c J. fPng -y c kho4 khng?"

Jerry trng c v4 sCng s(t. "Ci c*a kh< 'c J'. g 2y nh<?"

Jasmine v3i vng l/ng 2i th0t nhanh cho xong chuy6n: "Qun ci chuy6n 'Ms. J' 2i cao th*.
Chuy6n ny 2 qu 2*." fi m?t nng ch"a bao giD dFu nh" v0y, v ti nh0n ra chnh mnh
c[ng khng thA tr/ lDi nng m3t cch kho lo v g:n gng.

Chic xe phWc vW c-ph 2i ngang. Ti m&ng rI v7 ngay m3t c(c v c dFp may 2A 2nh
tr(ng l/ng v rQi ti lRi tip tWc 2(i di6n v7i cc tay c9u hu-n luy6n vin ny.

"Jean 2(i xC v7i c0u th no h; cao th*?" Jasmine h5i.

Jerry chm vo: " `a, lm sao my "gI" 2"#c m3t "mn" c*a b ta v0y?"

Sau khi ; trong hon c/nh khng thA ni h$n ba chO m3t l>n su(t c/ buTi sng v7i Jean, nXi
b9c d:c trong lng ti vI tung ra.

"Ti khng "gI" g ht, b -y b-t thnh lnh xu-t hi6n sng nay. Th0t tnh m ni, lm vi6c
v7i b ti th-y h$i kh chFu. B ta lc no c[ng g:i ti l 'c0u b thn mn'; v b ni qu
nhi@u, nghE gi/i lao c[ng qu nhi@u. Chng ti khng hon t-t 2"#c bao nhiu vi6c c/. Ti
khng ch?c ti c mu(n tip tWc lm vi6c v7i b ta hay khng."

Jasmine v Jerry nhn ti, h: nhn nhau, rQi 23t nhin ph ra c"Di. Jerry tr; lRi bnh th"Dng
m3t cch nhanh chng nh"ng Jasmine khng thA t9 ch* 2"#c. MXi khi nhn ti, nng lRi c"Di
ph ln; ting c"Di hao hao nh" gi:ng con h/i s" g:i bRn -2-.

"G v0y?" ti h5i.

Jerry dNn ti qua m3t bn trong khi Jasmine tip tWc tun ra hng trng c"Di l/nh lt.
"Alphonse, my khng bit my may m?n nh" th no. B:n tao ; 2y 2Ha no c[ng sSn
sng 2nh 2Ti b-t cH 2i@u g -3- 2A 2"#c lm vi6c v7i Jean. Tao bit b -y h$i khc th"Dng
nh"ng 2&ng nn l>m v7i ci v4 "b ngoRi" bn ngoi c*a b ta. B -y l m3t trong nhOng
tay thi6n ngh6 nh-t v my sK h:c 2"#c r-t nhi@u t& b."

Ti ng7 ra nh"ng khng thA 2(i 2p thm 2"#c t g v ngay khi -y Jean kh0p khiZng t&
chic gh 2-m bp 2i 2n.

"]n trDi, ti c/m th-y kho4 h$n r-t nhi@u."

Trao 2Ti v7i Jerry ti tm 2"#c nhOng thng tin nhi@u h$n c>n thit cho nn ti 2Ti ch* 2@
bPng cch 2@ nghF g:i ng"Di phWc vW c ph.

"^ thi c0u b. Ti nghE chng ta nn v@ lRi t>ng 6 thiu ti6n nghi c*a chng ta v tip tWc
lm vi6c v7i SMCRemote, c0u c nghE th khng? Chng mnh cn qu nhi@u thH ph/i lo
trong ngy hm nay v hVn nhin chng ta sK chVng th9c hi6n 2"#c nu chng ta ; 2y,
ph/i khng no? .... Khng hiAu sao Jasmine lRi pht ra nhOng m thanh kh*ng khip v0y
nh<? m thanh gi(ng nh" con th no 2 2ang giNy cht v0y. Jasmine, u(ng cht n"7c 2i c
b thn mn..."

Chng ti dng thang my 2i v@ phng lm vi6c. T>ng l>u cao ny lm Jean ch0m chRp
hVn. \ d"7i phng khch b ta nhanh nhYn h$n r-t nhi@u.

Sau khi yn Tn ngQi vo bn my, b ni: "No, Alphonse thn mn, ti nghE chng ta nn
xem thC c thA chRy 2"#c 2oRn l6nh mnh 2 tRo ra khng. C0u nghE sao?"

Ti 2 ngNm nghE cch th9c hi6n nn ti 2Qng ngay. "... vng."

"T(t l?m c0u b thn mn. By giD th ny, 2oRn l6nh mnh s?p chRy sK g:i ch"$ng trnh
bin dFch SMC, ti nghE vi6c 2>u tin mnh c>n lm l tRo ra m3t 2oRn m 2$n gi/n 2A trnh
dFch 2 2:c. Th, hy vit m3t ci test dng 2A tRo hQ s$ ny 2i, rQi g:i trnh dFch v kiAm
tra xem trnh dFch c tRo ra hQ s$ xu-t 2ng hay khng."

B lRi li ra b3 2Q 2an len v khng h@ t5 mu(n 23ng 2n bn 2nh, b;i v0y ti v7 l-y n
v b?t 2>u g:

public void testExecuteCommand() throws Exception {
File sourceFile = new File("simpleSourceFile.sm");
PrintWriter pw = new PrintWriter(new FileWriter(sourceFile));
pw.println("
}

Khng bit ph/i tip tWc th no nn ti nhn b v7i chD 2#i.

"T(t l?m c0u b thn mn. fy, 2A ti g vo c php SMC cho c0u."

public void testExecuteCommand() throws Exception {
File sourceFile = new File("simpleSourceFile.sm");
PrintWriter pw = new PrintWriter(new FileWriter(sourceFile));
pw.println("Context C");
pw.println("FSMName F");
pw.println("Initial I");
pw.println("{I{E I A}}");
pw.close();
}

"N c nghEa th no v0y Jean?"

", c0u b thn mn, v7i mWc 2ch ring c*a chng ta th n c nghEa l trnh dFch sK tRo ra
hQ s$ tn l F.java. Lc ny c0u ch< c>n bit ng>n -y thi. Tuy nhin, khi c0u tr; v@ phng
ring c*a mnh, c0u nn tm kim ti li6u SMC v tham kh/o thm; vi6c ny l vi6c c>n
thit. Ti vit ti li6u ny nhi@u nUm v@ tr"7c 2 c0u b thn mn v ti vNn nghE n l m3t
trong nhOng ti li6u hay c*a ti. N g:i l "Care and Feeding of the State Map Compiler" -4-
. By giD mnh xem thC c chRy 2"#c l6nh bin dFch -y khng."

Ti khng ch?c ph/i lm g 2A chRy l6nh ny; nh"ng ti h:c 2"#c t& Jerry v Jasmine thng
th"Dng cch hay nh-t l ch< vit cc c g:i diZn t/ 2Fnh c*a mnh. B;i th ti tip tWc g:


public void testExecuteCommand() throws Exception {
File sourceFile = new File("simpleSourceFile.sm");
PrintWriter pw = new PrintWriter(new FileWriter(sourceFile));
pw.println("Context C");
pw.println("FSMName F");
pw.println("Initial I");
pw.println("{I{E I A}}");
pw.close();
String command = SMCRemoteServer.buildCommandLine("simpleSourceFile.sm");
assertEquals(true, SMCRemoteServer.executeCommand(command));

File outputFile = new File("F.java");
assertTrue(outputFile.exists());
assertTrue(outputFile.delete());
assertTrue(sourceFile.delete());
}

"Md mn! Alphonse. Ti nghE rPng 2oRn trn n?m b?t ph>n test m3t cch r-t 2ng khen.
Chng ta ch"a vit executeCommand nh"ng ch?c ch?n mnh c thA diZn 2Rt cch mnh
mu(n n 2"#c g:i ra sao, ph/i khng no. By giD chng ta hy tRo stub -5- cho b"7c ny
v xem 2oRn test bF h5ng. Lc no ti c[ng th-y th vF khi th-y chng h5ng, c0u c nghE
th khng?"

Th rQi ti b-m vo executeCommand v ch:n "Create Method", v IDE c*a ti -6- tRo stub
method ti mu(n. V rQi, y nh" th0t, ph>n test bF h5ng.

public class SMCRemoteServer {
...
public static boolean executeCommand(String command) {
return false;
}
}

"f"#c rQi c0u b thn mn, hy lm cho ci test -y 2Rt nh."

Jean lRi c v4 m6t m5i. Ti bit b s?p mu(n ngh< tay thm l>n nOa. f g>n 2n giD Un
tr"a, nn ti hy v:ng b c thA nn lRi cho 2n lc -y. Ti nhanh chng r/o xuyn qua
javadocs 2A tm cch th9c thi m3t l6nh. Jean th-y v0y bn ni:

"Trong Runtime class 2, c0u b. Th rQi ti g 2oRn m ti nghE n chRy.

public static boolean executeCommand(String command) {
Runtime rt = Runtime.getRuntime();
try {
rt.exec(command);
return true;
}
catch (IOException e) {
return false;
}
}

Nh"ng khi ti chRy ph>n test, n khng tm 2"#c hQ s$ xu-t. Ti tm trong th" mWc v qu/
th0t, F.java khng c ; 2.

"Sao n h5ng v0y, Jean?"

B nhn ln v b/o: "C0u khng 2#i cho process ch-m dHt 2 c0u b thn mn. Khi c0u th9c
hi6n m3t l6nh, n tRo ra m3t process m7i chRy 2Qng thDi v7i process c*a c0u. C0u ph/i 2#i
cho n hon t-t tr"7c khi thot ra kh5i executeCommand."

Ti tham kh/o ph>n Runtime.exe trong JavaDoc v th-y n tr/ lRi m3t object Process. Ti
c[ng th-y rPng mnh c thA 2#i object Process hon t-t v c thA truy kh/o tnh trRng thot
-7- c*a n. B;i th ti tRo nhOng thay 2Ti nh" sau:

public static boolean executeCommand(String command) {
Runtime rt = Runtime.getRuntime();
try {
Process p = rt.exec(command);
p.waitFor();
return p.exitValue() == 0;
}
catch (Exception e) {
return false;
}
}

L>n ny ph>n test 2Rt.

"C[ng khng kh l?m." Ti pht biAu.

"T-t nhin l khng rQi c0u b thn mn. Chng ta ch< chRy m3t ci l6nh thi m. T-t nhin
n sK tr; nn phHc tRp h$n m3t cht khi chng ta ph/i n?m b?t thng 2i6p m trnh dFch
th"Dng in ra trn console -8-. Chng ta sK ph/i g?n vo standard output v standard error -
9- c*a Process. Nh"ng hy lm chuy6n -y sau giD Un tr"a c0u b thn mn, ti b?t 2>u c/m
th-y 2i, c0u c th-y v0y khng?"

Ti th; di v 2Hng d0y. Ti c/m th-y d"Dng nh" chng ti vNn tin triAn ch0m chRp. Tuy
v0y, xt lRi th ti th-y chng ti 2 hon t-t ph>n client v lm cho server chRy 2"#c trong
nCa ngy 2>u lm vi6c v7i Jean. Chng ti khng dnh t thDi gian no cho vi6c tm lXi. C
lK chng ti tin triAn nhanh h$n ti nghE.

Jean b5 b3 2Q 2an vo gi5 v giUng ra chic o len. "fy, c0u b thn mn, thC ci ny vo
xem."
Nu khng cn g 2ng 2A ni th chic "2Q" ny c*a Jean dRy cho ti thm tnh kin nhNn.




-1- Nguyn vUn "low-g", m3t dRng ting ting lng ch< cho "lower ground". fy l l(i ni r-t Md.

-2- "sounded like a sea lion calling to its mate" tRm dFch l "ting c"Di hao hao nh" gi:ng con h/i s" g:i bRn". C lK
tc gi/ mu(n ph>n no b3c t/ tnh c/m c*a Alphonse lc -y bPng l(i so snh 2>y hnh t"#ng ny. Theo ti, gi:ng
con h/i s" g:i bRn qu/ th0t kh c thA "c/m" nTi (nh"ng c lK lRi h-p dNn 2(i v7i gi(ng h/i s" chUng).

-3- "Give our eyeteeth", m3t thnh ngO ch< cho s9 2nh 2Ti r-t 2?t gi.

-4- "Care and Feeding of the State Map Compiler", tRm dFch l "ChUm sc v bQi d"Ing trnh dFch State Map".
Trong nguyn b/n, tc gi/ cho 2"Dng dNn 2n:
http://www.objectmentor.com/resources/downloads/bin/smcJava.zip 2A t/i smcJava.zip.

-5- stub theo nguyn b/n, tRm dFch l n3i 26m v c lK skeleton sK l ngoRi 26m (dFch theo ngO c/nh). f(i v7i
nhOng ai tip xc v7i RMI (Remote Method Invocation - 2:c thm ; http://java.sun.com/products/jdk/rmi/) v
J2EE ch?c khng lR v7i khi ni6m "stub" v "skeleton".

TTng qut m ni, "stub" l m3t class n3i b3 (local class) c cng interface v7i m3t class t>m xa (remote class).
V7i RMI, class t>m xa l class 2"#c g:i 2A th9c hi6n m3t cng tc no 2. fA th9c hi6n m3t cng tc ny, bRn ch<
c>n g:i "stub" n3i b3 m khng c>n ph/i quan tm 2n chuy6n cng tc ny 2"#c th9c hi6n b;i m3t class no 2
t& xa.

Trong khi 2, "skeleton" l m3t class t>m xa dng 2A tip nh0n thng 2i6p v lo li6u c g:i 2n m3t class no 2
trn m3t my t>m xa v class ny chnh l class th9c hi6n cng tc. Ch< c>n ghi nh0n tTng qut: stub dnh cho
local v skeleton dnh cho t>m xa trong c$ ch RMI.

-6- IDE, vit t?t t& Integrated Development Environment (khng ph/i l Intergrated Drive Electronics dnh 2A ch<
cho T cHng), tRm dFch l b3 tch h#p mi tr"Dng pht triAn. IDE l m3t b3 cng cW dng 2A pht triAn ch"$ng trnh.
V dW, Java Netbeans, Eclipse, VC++ l cc IDE. Ch< c>n nh7 IDE l 2* :)

-7- exit status, tRm dFch l "tnh trRng thot". Exit status l thu0t ngO quen thu3c v7i nhOng ai 2 t&ng l0p trnh,
n d9a trn cc m s( 2 2"#c quy 2Fnh tr"7c 2A xc 2Fnh m3t ch"$ng trnh sau khi thot ra thu3c tnh trRng no.

-8- console, m3t thu0t thng dWng trong ngnh 2i6n ton. Tr"7c 2y "console" l m3t mn hnh g?n li@n v7i bn
2nh trong mi tr"Dng mainframe hoLc cc h6 th(ng UNIX (khng dng giao di6n 2Q hnh). MXi mn hnh l m3t
"console". Cho 2n ngy nay, cc h6 2i@u hnh hi6n 2Ri km theo giao di6n 2Q hnh nh"ng vNn cn ph"$ng ti6n 2A
m; ln m3t "console" (nh" DOS prompt trn Windows hoLc term trn *nix ni chung). Ni theo ph"$ng di6n kd
thu0t, console l m3t giao di6n, hay m3t c$ ch 2Hng giOa ch"$ng trnh lm vi6c v h6 2i@u hnh.

-9- "standard output", "standard error" v "standard in", 2i khi cn vit t?t l "stdin", "stdout", "stderr". Cc thu0t
ngO ny 2"#c dng 2A ch< cho c$ ch xC dWng cc thit bF xu-t, nh0p dO li6u hoLc hiAn thF lXi trn console (; trn).
V7i stdin, stdout v stderr trong mi tr"Dng Java, nn tham kh/o ti li6u "The ins and outs of standard
input/output" c*a Jeff Friesen ; http://www.javaworld.com/javaworld/jw-03-2001/jw-0302-java101.html

The Crafsman 20.
SMCRemote Part X
Backslide.

ChMng g-ng -1-

Ti tr; lRi phng lm vi6c sau buTi tr"a nh"ng Jean khng c 2. ChVng c m3t mBu tin hay
e-mail c*a b 2A lRi; v ngay c/ gi5 2Q 2an c*a b c[ng chVng th-y tUm h$i. Sau vi pht,
ti quyt 2Fnh ngQi xu(ng v tip tWc lm vi6c v7i SCMRemoteServer.

Cho 2n lc ny server chVng phWc vW g ht. N ch< c vi ci hm dng 2A d9ng v thi
hnh dng l6nh SMC. Ti nghE 2ng ra m nguQn c*a server ph/i m; m3t socket v tip
nh0n cc 2"Dng n(i t& SMCRemoteClient m chng ti 2 vit lc tr"7c.

Ti kh ngn ngBm v7i 2 lm vi6c c*a chng ti hm nay. M-t c/ buTi sng m chng ti
ch< hon thnh hai ci hm b tYo thm vo m-y ci unit test. Ti mu(n th-y s9 tin triAn.
B;i th ti v7 l-y bn 2nh v b?t 2>u g.

"f>u tin," ti nghE, "cc server ny c>n phWc vW g 2. Th th hy dng SocketServer class
m Jerry v ti xong tu>n tr"7c."

Lm cho server phWc vW kh 2$n gi/n. Ti ch< c>n vit m3t constructor dng 2A tRo m3t
SocketService object v chuyAn vo trong m3t SocketServer. RQi SocketServer.serve hVn sK
t9 23ng 2"#c g:i khi SMCRemoteClient mu(n truy c0p.

public SMCRemoteServer() throws Exception {
service = new SocketService(9000, new SocketServer(){
public void serve(Socket socket) {
// SMCRemoteClient has connected.
}
});
}

Ti xem trong m nguQn c*a SMCRemoteClient v th-y rPng client 2#i m3t string 2"#c g;i
2i (t& server) sau khi 2 kt n(i. string 2 b?t 2>u bPng "SMCR". Th nn ti vit 2oRn
string 2 trong method serve().

public void serve(Socket socket) {
// SMCRemoteClient has connected.
try {
ObjectOutputStream os =
new ObjectOutputStream(socket.getOutputStream());
os.writeObject("SMCR");
}
catch (IOException e) {
}
}

K tip server c>n 2:c m3t CompileFileTransaction t& client. N c>n vit cc hQ s$ chHa
trong transaction -y, g:i trnh dFch v sau 2 tr/ vA kt qu/ (cc hQ s$) bn trong
CompileResultsTransaction. Vit nn n c v4 khng kh m-y, th....





public void serve(Socket socket) {
// SMCRemoteClient has connected.
try {
ObjectOutputStream os =
new ObjectOutputStream(socket.getOutputStream());
os.writeObject("SMCR");
ObjectInputStream is =
new ObjectInputStream(socket.getInputStream());
CompileFileTransaction cft =
(CompileFileTransaction)is.readObject();
String filename = cft.getFilename();
cft.sourceFile.write();
String command = buildCommandLine(filename);
executeCommand(command);
//OK, what file do I put into the Result?
}
catch (Exception e) {
}
}

H&m. Bin dFch hQ s$ c v4 khng kh l?m nh"ng ti nn 2"a vo kt qu/ transaction c*a
m3t hQ s$ xu-t ra sao? Tn n l g? Ti nh7 hQi sng nay Jean 2 h"7ng dNn ti vit m3t
ci test 2A g:i trnh dFch. Ti xem lRi ph>n test -y v th-y hQ s$ nh0p c ci 2ui l a.sm, v
hQ s$ xu-t c ci 2ui a.java . Th nn ti ch< thay th ".sm" bPng ".java" cho tn hQ s$.

public void serve(Socket socket) {
// SMCRemoteClient has connected.
try {
ObjectOutputStream os =
new ObjectOutputStream(socket.getOutputStream());
os.writeObject("SMCR");
ObjectInputStream is =
new ObjectInputStream(socket.getInputStream());
CompileFileTransaction cft =
(CompileFileTransaction)is.readObject();
String filename = cft.getFilename();
cft.sourceFile.write();
String command = buildCommandLine(filename);
executeCommand(command);
//Figure out the file name.
String compiledFile = filename.replaceAll("\.sm", ".java");
CompilerResultsTransaction crt =
new CompilerResultsTransaction(compiledFile);
os.writeObject(crt);
socket.close();
}
catch (Exception e) {
}
}

Nhn c v4 ngon lnh. By giD ti ch< c>n kh;i 23ng server v chRy client. f$n gi/n thi. Th
rQi ti tRo hQ s$ nguQn trong th" mWc c*a ti c ci tn l F.sm, y nh" ci Jean mu(n ti tRo
ra sng nay.

Context C
FSMName F
Initial I
{I{E I A}}

V rQi ti vit m3t hm main trong SMCRemoteServer

public static void main(String[] args) throws Exception {
SMCRemoteServer server = new SMCRemoteServer();
}

Sau 2 ti chRy thC. V n ch< treo ngay 2, 2#i cho client truy c0p. Ci ny m7i th0t l
thch! t ra ti 2 hon thnh 2"#c ci g 2! Th rQi tip theo 2 ti chRy client v7i "F.sm"
lm thng s(. V n CHZY! Hay ni cch khc, n thot ra sau nhi@u giy 2Qng hQ v7i tn
hi6u thot -2- bnh th"Dng v chVng c b-t cH thng bo lXi no c/ t& client c[ng nh"
server. Qu thch!

Nh"ng n 2 lm nhOng g? ti khng thA xc 2Fnh ngay 2"#c. B;i th, ti thC kiAm tra th"
mWc v th-y m3t hQ s$ F.java n?m chZm ch6 ; 2! N c 2ng ngy trn 2, th c nghEa
n 2 2"#c tRo ra t& l>n client chRy v&a rQi. Qu tuy6t! Ti m; hQ s$ ra xem v n trng
gi(ng nh" m Java 2 2"#c tRo nn. N cn ni l 2"#c SMC tRo ra. M nguQn c*a ti chRy
2"#c! -3-

f m-y tu>n nay ti ch"a h@ c/m th-y vui s"7ng th ny, th0t s9 m ni, kA c/ t& tr"7c khi
lm vi6c v7i Jerry. fy m7i 2ng l l0p trnh! Ti dng trn c/m gic mu(n chng lm cho
m nguQn chRy. Ti l "23c c c>u bRi"! -4- Ti 2Hng ln v nhn nh/y m3t vng quanh
chic gh, mi6ng l/m nh/m "i! i! ti l m3t l0p trnh vin. i!"

Jerry hVn ; 2u 2 g>n bn b;i v g b"7c vo phng lm vi6c ngay lc -y. " Alphonse,
my 2ang r3n rng chuy6n g v0y?"

"^, cho Jerry! Xem ny! ti m7i lm cho SMCRemoteServer chRy 2"#c!"

"Th0t v0y ? V0y l chin l?m 2." V4 nhn trn mLt g trng buQn c"Di -- nh" thA g khng
tin ti. Th nn ti ch< cho g xem. Ti ch< cho g xem server -y lm vi6c ra sao. Ti chRy
client m3t l>n nOa. Ti ch< cho g xem hQ s$ F.java v7i 2ng ngy giD 2"#c tRo ra. Th0m ch
ti ch< cho g xem hQ s$ ny chHa m java.

Jerry nhn ti g>n nh" kinh hi, v rQi g lic ra cCa m3t cch s# s6t. "Alphonse, m-y ci
tests c*a my 2u?"

"Jerry, ng khng c>n m-y ci unit tests cho nhOng thH 2$n gi/n nh" th ny. Nhn xem,
ch< c m3t chWc dng m nguQn hoLc h$n thi m. Jerry, ti 2 c tin b3 2y ny. Ti 2
hon t2t -5- dUm ba 2i@u. V n khng c>n ph/i m-t c/ ngy 2A hon thnh! Ti nghE m-y
ng b ph qu nhi@u thDi gian v7i m-y ci unit test!"

Jerry nhn ti chPm chLp vi giy nh" thA g khng thA tip thu nhOng 2i@u ti b/o g. Th
rQi g 2ng cCa phng lm vi6c lRi v ngQi xu(ng bn cRnh ti.

"Alphonse, b Jean th-y m-y ci ny ch"a v0y?"

"Ch"a, ti ch"a th-y b tr; lRi sau giD tr"a."

"Xo n 2i, Alphonse."

"Xo ci g?"

"Xo 2oRn m my v&a vit xong 2. N v dWng."

"Ti 2 t&ng 2Wng kiAu ph/n Hng ny tr"7c 2y. Ti cong c7n b/o: "i, thi 2i Jerry! n
chRy m! lm sao n c thA v dWng?"

"My c ch?c n chRy khng?"

"Th chnh ng c[ng th-y 2!"

"MY c ch?c n chRy khng?"

"T-t nhin l n chRy. HQ s$ F.java chnh l bPng chHng!"

"Alphonse, tRi sao ngy giD c*a hQ s$ F.sm gi(ng y h6t ngy giD trn hQ s$ F.java v0y?"

"Ci g?" Ti nhn vo th" mWc th qu/ th0t, chng gi(ng nhau cho 2n t&ng giy. Nh"ng
khng thA hiAu nTi. Ti vit hQ s$ F.sm bPng tay nhi@u pht tr"7c 2y. TRi sao n c cng
ngy giD v7i hQ s$ F.java v&a 2"#c tRo ra m-y giy tr"7c, khi ti biAu diZn cho Jerry xem?
Ti chUm chUm nhn n m3t 2Xi v th nh0n ti khng bit tRi sao.

"Xo m nguQn ny 2i Alphonse. My khng hiAu g ht."

"i, thi 2i Jerry, ti hiAu m. Ti ch< khng tm ra l do tRi sao m7 ngy giD lRi khng 2ng
thi. N chRy m Jerry... n chRy." Nh"ng ti khng cn dm ch?c nOa. T/i sao phn ngy
giV 2y ph<i khc nhau nhX?

"Alphonse, c thA no my chRy client v server t& cng m3t th" mWc khng?"

"Ui da..." Ti khng -n 2Fnh th" mWc khc nhau cho chng nn ti 2on chng ch?c 2 chRy
trong cng m3t n$i. ".... Ti 2on l th."

"V0y c/ client v server 2@u 2:c v vit cng hQ s$ trong cng m3t th" mWc?"

"... i.."

Jerry g0t 2>u v7i v4 2?c th?ng. "`a."

Ti g0t 2>u. "OK, Jerry, ng c l l?m. Ti khng hiAu ht nhOng g x/y ra. Nh"ng hy xem,
hQ s$ F.java nPm ch"Dng ra ka. Nh-t 2Fnh ph/i c ci g 8 chRy 2"#c!"

"Th th sao? My khng bit ci g chRy v ci g khng. My khng hiAu my 2 lm g.
M-y thH ny trng c v4 nh" chRy 2"#c theo kiAu ch ngp nh>m ruQi. -6- C thA no, v dW
nh" hQ s$ F.java bF st lRi t& ci unit test tr"7c khng?"

C thA l?m! Chu choa, Jean v ti lm cho h6 th(ng vit m3t ci F.java sng nay! "Que tha!
Vng, c thA l?m -- nh"ng khng e khng ch?c l nh" v0y!"

"Xo 2oRn m 2i Alphonse. Ton rc r";i."

Ti nhn g chPm chPm. Ti 2 tin triAn que tha n 2i! By giD g lRi mu(n ti xo ht
nhOng d-u -n ti.n triGn -y. Nh"ng g -y 2ng. Ti khng hiAu 2oRn m. V ti chVng c t
test no c thA chHng minh t&ng b"7c m3t l m:i thH chRy 2ng nh"ng d9 t";ng. Nu m
nguQn c*a ti th9c s9 lm vi6c 2ng (v by giD ti b?t 2>u th0t s9 bUng khoUn khng bit
n lm vi6c 2ng 2"#c m-y ph>n) n chRy 2"#c do may m?n h$n do thit k 2ng hong.

"Xo 2oRn m 2i Alphonse. My ch7 c 2A b -y th-y m7 m nguQn 2. Ngay lc ny, b ta
ht lng quan tm -7- 2n my, v m7 m ny sK lm b th-t v:ng 2."

L0p tr"Dng c*a ti r(t cu3c h5ng bt. fi vai trZ xu(ng, ci 2>u cHng 2$ v ti chQm sang,
xo ht 2oRn m. Jerry b"7c ra kh5i phng, 2>u ngc ngo?c.

Vi pht sau, b Jean b"7c vo. "Cho Alphonse thn mn. Ti xin lXi v ch0m trZ v ti bF
dnh vo cu chuy6n v7i ng"Di bRn c[ v b:n ti sa 2 vo chuy6n so hnh c*a m-y 2Ha
chu. Ti m khoe hnh m-y 2Ha chu ti l?m. C0u th-y chng ch"a nh<, c0u b thn mn?
^, 2&ng 2A 2n ti, chng ta c vi6c c>n ph/i lm. C0u lm g trong khi ti bF "tRm giam"
v0y?"

"Khng lm g c/ Jean, ti ch< 2#i b thi."




-1- Backslide: ch< cho tnh trRng hWt hNng, bF r7t xu(ng m3t mHc th-p h$n. TRm dFch l "chTng g:ng" cho thm
ph>n... d d5m.

-2- Exit Code: tRm dFch l tn hi6u thot. Exit code l thu0t ngO quen thu3c v7i nhOng ai 2 t&ng l0p trnh, n d9a
trn cc m s( 2 2"#c quy 2Fnh tr"7c 2A xc 2Fnh m3t ch"$ng trnh sau khi thot ra thu3c tnh trRng no.

-3- foRn ny tc gi/ dng r-t nhi@u d-u ch-m thang (!) sau mXi cu Alphonse th(t ra 2A nh-n mRnh tnh trRng
c/m xc c*a Alphonse lc ny. Thng th"Dng d-u ch-m thang 2"#c xp loRi v di6n "kj dng" qu nhi@u trong vUn
vit nh"ng trong ph>n ny, d-u ch-m thang 2"#c huy 23ng t(i 2a v c tc dWng r-t thch 2ng.

-4- Invincible: khng thA bRi. TRm dFch l "23c c c>u bRi" cho g>n v7i tinh th>n "kim hi6p" c*a dn chu ni
chung.

-5- Ch cc chO hoLc cWm chO in nghing trong bi ny. Chng dng 2A nh-n mRnh c[ng nh" 2A tRo kFch tnh
trong cu chuy6n.

-6- working by accident: st nghEa l "chRy 2"#c nhD may r*i". TRm dFch l "chRy 2"#c theo kiAu ch ngp nh>m
ruQi" 2A c( g?ng l3t t/ c tnh c*a Jerry.

-7- think the world of someone: ht lng ht dR v7i ai 2, 2A ht tm 2n ai 2.

You might also like