Professional Documents
Culture Documents
The Crafsman 1. Opening Diaster. Robert C. Martin
The Crafsman 1. Opening Diaster. Robert C. Martin
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.