Forum NIIT ChoLon


 
IndexPortalli*Trợ giúpTìm kiếmĐăng kýNhómĐăng Nhập
Navigation
Latest topics
» Project 2 - Case Study 3 : ABC Corp.
by phumylinh92 10/01/12, 01:51 pm

» Mu Thăng Long.Vn open 23/10/2011 - SeaSon 6
by muthanglong 19/10/11, 04:04 pm

» MuThangLong.Vn - open 15/10/2011 season 6
by muthanglong 11/10/11, 01:17 pm

» tìm lớp học tiếng trung
by lanhqua 04/10/11, 01:52 pm

» Quater8(Java)
by lenoxnguyen 10/06/11, 05:06 am

» Project 1 - case 2: New Tech Book Store
by gauhuongbong 03/10/10, 11:56 am

» Sự rắc rối của con gái:
by oahqvan8011 30/09/10, 03:10 pm

» Mu Kim Long Season 5 Episode 5 - Nhân Thần Chiến(Tháng 9)
by ztaitrangz 08/09/10, 01:15 pm

» NIIT anh Em Q6 Net vào giúp mình với
by kanwonbi 27/08/10, 10:37 am

» Tru Tiên Sever Private (new)
by blackcat8438 11/07/10, 07:07 pm

» Không đề
by 7113 21/09/09, 02:55 pm

» Tw
by 7113 11/09/09, 09:32 pm

» Clip động phòng của Dra
by cpudual1 07/07/09, 08:26 pm

» Vài lời của bố
by dratwister 05/04/09, 06:41 pm

» Anh Hưng giúp em với
by dratwister 05/04/09, 06:40 pm

» An choi Next time
by dratwister 14/11/08, 02:34 pm

» giúp đỡ check textbox
by anhcaucoi 04/11/08, 12:03 pm

» Lớp học nhóm ^^
by ..:Habie Babie:.. 31/10/08, 03:05 am

» SpAm...sPaM by English
by dratwister 17/10/08, 10:54 pm

» Kinh dị - The Rogue 2007
by lucius.sj24 10/10/08, 07:08 pm

Tìm kiếm
 
 

Display results as :
 
Rechercher Advanced Search
Diễn Đàn

Quảng Cáo
forum gratuit Annuaire des forums
Le bottin des forums
Kouaa



Share | 
 

 Crafsman

Xem chủ đề cũ hơn Xem chủ đề mới hơn Go down 
Tác giảThông điệp
7113
Hết Chổ Nói
Hết Chổ Nói


Nữ
Tổng số bài gửi : 409
Đến từ : nơi chứa rất nhiều phiền não
Registration date : 18/05/2007

Bài gửiTiêu đề: Crafsman   05/08/07, 10:59 am

The crafsman One.
Robert C. Martin
13 Tháng 2, 2002

Bài viết này lược trích 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.

Nhật ký thân mến,
13 tháng 2, 2002.

Hôm nay đúng là một ngày xui xẻo - Tôi làm hỏng cả chuyện. Tôi rất muốn gây ấn tượng với các ngài "cựu học việc" ở đây nhưng rút cuộc chỉ làm rối tung cả lên.

Ðó là ngày đầu tiên tôi được một chân học việc với ông C. Tôi quả là may mắn có được chân học việc này. Ông C là một tay trùm lớp lang trong vấn đề phát triển phần mềm. Ðấu để giành được chân việc này đúng là nẩy lửa. Các tay học việc của ông C thường trở nên các tay "cựu học việc" sáng giá. Ðiều này có nghĩa được làm việc với ông C có giá trị rõ ràng.

Tôi cứ ngỡ là hôm nay tôi sẽ được gặp ông ta nhưng thay vì đó tôi bị một gã "cựu học việc" níu tôi qua một bên. Gã bảo ông C luôn luôn dẫn các tay học việc đi xuyên qua phần định hướng trong những ngày đầu. Gã nói ông C nhất quyết cho rằng phần thực tập định hướng là thiết thực với các tay học việc và nó dẫn đến mức chất lượng mã nguồn mà ông ta ta dự tưởng.

Tôi náo nức kinh khủng. Ðây là một cơ hội cho họ thấy tôi là một tay lập trình "ngon" cỡ nào. Thế là tôi bảo Jerry tôi không chờ được nữa. Gã đáp lại sự náo nức của tôi bằng cách bảo tôi thử viết một chương trình đơn giản cho gã. Gã muốn tôi dùng "Sieve of Eratosthenes" để tính các số nguyên. Gã còn bảo tôi phải chuẩn bị xong chương trình bao gồm trọn bộ các "unit tests" sẵn sàng để "chấm" sau buổi ăn trưa.

Thật là khoái! Tôi có gần 4 tiếng đồng hồ để "xào nấu" một chương trình giống như Sieve. Tôi quyết tâm thực hiện công tác này một cách hết sức có ấn tượng. Mã dẫn 1 đưa ra những gì tôi đã viết. Tôi nắm chắc là chương trình của tôi được chú thích cẩn thận và trình bày gọn gàng.

Mã dẫn 1:

Code:
/**
 * This class generates prime numbers up to a user-specified maximum.
 * The algorithm used is the Sieve of Eratosthenes.
 *
 * 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.
 *
 * 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.
  }
 }
[/i]Sau đó tôi viết một cái "unit test" cho GeneratePrimes. Xem ở mã dẫn 2. Ðoạn mã này dùng JUnit framework như Jerry đã chỉ dẫn. Nó dùng tính chất hướng thống kê; kiểm tra xem cái "generator" có thể tạo ra các số nguyên tới 0, 2, 3 và 100. Trong trường hợp thứ nhất hẳn không có số nguyên nào cả. Trong trường hợp thứ nhì hẳn phải có một số nguyên và nó phải là số 2. Trường hợp thứ ba phải có hai số nguyên và chúng phải là số 2 và 3. Trường hợp cuối phải là 25 số nguyên và số cuối phải là 97. Nếu các bước kiểm tra đều đúng, tôi giả định là cái "generator" làm việc đúng. Tôi e rằng khó có thể tin cậy tuyệt đối cách ở trên, nhưng tôi không nghĩ ra được một trường hợp nào một "function" có thể bị hỏng mà các bước kiểm tra đều đúng.

Mã dẫn 2:
Code:
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);
  }
 }

Tôi mất khoảng một giờ đồng hồ để làm những bước trên chạy được. Jerry không muốn gặp tôi cho đến sau buổi ăn trưa, bởi thế, tôi dành trọn bộ thời gian còn lại đọc cuốn Design Patterns mà Jerry đưa cho tôi.

Sau buổi ăn trưa, tôi ghé văn phòng của Jerry và cho gã biết tôi đã thực hiện xong chương trình. Gã nhìn tôi và với một nụ cười khó tả, hắn nói: "Ðược lắm, hãy xem thử nó thế nào."

Gã dẫn tôi và phòng thí nghiệm và cho tôi ngồi trước một máy. Gã ngồi bên cạnh tôi và yêu cầu tôi đưa chương trình của tôi vào máy này. Thế là tôi chuyển mã nguồn từ máy laptop của tôi lên.

Jerry xem xét hai mã nguồn chừng năm phút rồi gã lắc đầu và bảo: "Mày không thể đưa những cái này cho ông C xem được! Nếu tao để ổng xem mấy cái này, ổng sẽ đuổi cổ cả tao lẫn mày. Ông ấy không phải là người kiên nhẫn đâu."

Tôi đánh thót một phát nhưng cố giữ bình tĩnh và hỏi gã: "Chớ nó sai chỗ nào?"

Jerry thở dài và nói: "Tụi mình nên đi xuyên qua mã nguồn này với nhau." "Tao sẽ chỉ cho mày từng điểm một cách ông C muốn thực hiện nó như thế nào."

"Quá rõ ràng", gã tiếp tục, "cái main function muốn làm ra ba cái functions riêng biệt. Cái thứ nhất khởi tạo tất cả các biến hàm và thiết lập cái "sieve". Cái thứ nhì thực sự thi hành cái "sieve" và cái thứ ba tải kết quả của "sieve" vào một dãy số nguyên."

Tôi nhận ra được ý gã muốn nói gì. Có ba khái niệm chôn trong cái function đó. Tuy vậy, tôi không biết gã muốn tôi phải làm gì với nó.

Gã nhìn tôi một lúc, rõ ràng đang đợi tôi phản ứng sao đó. Nhưng rốt cuộc gã thở dài, lắc đầu và....

<đón đọc bài kế tiếp>

(tác giả: hnd dịch từ diendantinhoc.net)

Bảng gốc (tiếng Anh): down here

P/s: thấy cái này trên mạng cũng hay hay nên chép về cho các bạn đọc :D
Về Đầu Trang Go down
Xem lý lịch thành viên
7113
Hết Chổ Nói
Hết Chổ Nói


Nữ
Tổng số bài gửi : 409
Đến từ : nơi chứa rất nhiều phiền não
Registration date : 18/05/2007

Bài gửiTiêu đề: Re: Crafsman   05/08/07, 11:54 am

The Crafsman Two.
Trong phần trước * Jerry, một tay cựu học việc, yêu cầu Alphonse, một tay học việc, viết một chương trình tạo các số nguyên tố dùng phương pháp lượt Eratosthenes (sieve of Eratosthenes). Jerry, nhận thấy Alphonse đã cài đặt toàn bộ thuật toán vào một function "khổng lồ" nên đã yêu cầu Alphonse tách nó ra theo ba khái niệm: khởi động, thực hiện (loại bỏ các số không nguyên tố) và cho ra giá trị output (đưa ra danh sách các số nguyên tố);... nhưng Alphonse không biết phải bắt đầu từ đâu...

Gã nhìn tôi một lúc, rõ ràng đang đợi tôi làm gì đó. Nhưng rốt cuộc gã thở dài, lắc đầu, rồi nói: "Ðể mở rộng ba khái niệm rõ hơn, tao muốn mày tách chúng ra thành ba methods riêng biệt. Ðồng thời vứt hết những cái phụ chú không cần thiết và đặt một cái tên khá hơn cho cái class. Mày làm xong những thứ đó rồi, nhớ bảo đảm là mấy cái test vẫn còn chạy được."

Các bạn có thể thấy những điểm tôi đã làm trong mã dẫn 3. Tôi đã đánh dấu những thay đổi bằng chữ đậm, y hệt như Martin Fowler trình bày trong cuốn Refactoring của ông ta. Tôi đổi tên của cái class thành dạng danh từ, vứt hết những phụ chú về chuyện Eratosthenes và tạo ra ba methods từ ba khái niệm trong generatePrimes function.

Tách ra ba functions buộc tôi phải chuyển một số biến local trong cái function "khổng lồ" trước đây, thành static fields của class. Jerry nói cách này làm rõ những biến hàm nào là local và những biến hàm nào có ảnh hưởng rộng lớn hơn.

Mã dẫn 3:
Code:
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() {{{/b}
    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() {{{/b}
    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) {{{/b}
    // 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;
    }
  }
[/i]Jerry bảo tôi mã này hơi lộn xộn, nên gã giành lấy bàn đánh và chỉ tôi cách dọn dẹp. Mã dẫn 4 minh hoạ những gì gã đã làm. Thoạt tiên gã vứt đi cái biến hàm s trong initializeSieve và thay thế nó bằng f.length. Sau đó gã đổi tên của ba functions (theo kiểu) gã cho là có ấn tượng hơn. Cuối cùng gã sắp xếp lại cái "bộ lòng" initializeArrayOfIntegers (từ initializeSieve) để cho dễ đọc hơn một chút. Các cái test vẫn chạy nhưng thường.

Mã dẫn 4:
Code:
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[an[maxValue + 1];
    f[0] = f[1] = false; //neither primes nor multiples.
    for (int i = 2; i < f.length; i++)
    f[i] = true; 

Tôi phải công nhận mã này rõ hơn một chút. Trước giờ tôi nghĩ tạo functions có tên sinh động là phí thời giờ , nhưng những chỉnh đổi của gã quả thật làm cho mã nguồn dễ đọc hơn.

Tiếp theo Jerry trỏ vào crossOutMultiples, nói là gã nghĩ cụm if(f[i] == true) có thể làm cho dễ đọc hơn nữa. Tôi nghĩ đến điểm này chừng một phút. Ý định của các cụm này dùng để kiểm tra xem i không bị loại trừ; thế là tôi đổi tên của f thành unCrossed.

Jerry nói mã này coi được hơn nhưng vẫn chưa vừa ý vì nó dẫn đến khả năng phủ định đôi (double negative) như unCrossed[i] = false. Bởi thế gã đổi tên của dãy số thành dãy isCrossed. Các cái test vẫn chạy được.

Jerry bỏ qua phần khởi động : gán cho isCrossed[0]isCrossed[1] giá trị true . Gã nói, chúng ta có thể giả sử không chỗ nào của thuật toán dùng dãy isCrossed với với chỉ số nhỏ hơn 2 . Các cái test vẫn chạy được.

Jerry tách phần lặp bên trong (inner loop) của crossOutMultiples function và gọi nó là crossOutMultipleOf. Gã bảo rằng các cụm tương tự như if (isCrossed[i] == false) dễ nhầm lẫn nên gã tạo ra function có tên notCrossed và thay cụm if thành if (notCrossed(i)). Kết tiếp gã chạy thử mấy cái test lại.

Sau đó Jerry hỏi tôi ý nghĩa của phần số căn đó là gì. Tôi tốn một ít thời giờ viết phụ chú giải thích tại sao cần phải lặp lại cho đến phần số căn của chiều dài dãy số. Tôi cố tranh đua với Jerry bằng cách tách phần tính toán thành một function, nơi tôi có thể đưa vào phần phụ giải. Trong khi viết ghi chú tôi nhận ra rằng căn số là thừa số nguyên tố cực đại của một số bất kỳ trong một dãy số. Bởi thế để ứng phó, tôi chọn cách gọi đó (maxValue) cho các biến, hàm. Cuối cùng tôi bảo đảm các tests vẫn chạy được. Kết quả của các thay đổi trong mã dẫn 5.

Mã dẫn 5:

Code:
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;
  }
 
Tôi bắt đầu nắm bắt được vấn đề nên liền xét lại method xét lại method putUncrossedIntegersIntoResult.
Tôi thấy rằng method này có hai phần. Phần thứ nhất đếm các số nguyên không bị loại trong dãy số, và tạo nên dãy kết quả (bằng chiều dài của dãy số). Phần thứ nhì dời các số nguyên không bị loại vào dãy kết quả này. Bởi thế, như bạn thấy trong mã dẫn 6, tôi tách phần thứ nhất ra để hình thành function cho chính nó và dọp dẹp lặt vặt đôi chút. Các tests vẫn chạy được. Jerry chỉ thoáng gật đầu. Gã có thật sự khoái những điều tôi đã thực hiện không?

Mã dẫn 6:

Code:
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;
  }
<đón xem phần kế tiếp>


*Trong nguyên bản là "In the last month's column..." nhưng ở đây tạm dịch thoáng ra là "trong phần trước" cho phù hợp với tinh thần các bài craftsman được post lên diễn đàn.

(tác giả: hnd dịch từ diendantinhoc.net)

Bảng gốc (tiếng Anh): down here
Về Đầu Trang Go down
Xem lý lịch thành viên
7113
Hết Chổ Nói
Hết Chổ Nói


Nữ
Tổng số bài gửi : 409
Đến từ : nơi chứa rất nhiều phiền não
Registration date : 18/05/2007

Bài gửiTiêu đề: Re: Crafsman   08/08/07, 09:50 am

The crafsman Three.
Lần trước, Jerry, một cựu học việc yêu cầu tay học việc Alphonse viết một chương trình tạo số nguyên tố dùng phương pháp lượt Eratosthenes (sieve of Eratosthenes). Jerry duyệt và giúp Alphonse tách lược (refactor) mã nguồn đó. Anh ta không được hài lòng với kết quả của Alphonse. Lần trước Alphonse thực hiện xong phần refactoring và nghĩ chắc Jerry sẽ chấp thuận...

Jerry chỉ thoáng gật đầu. Liệu gã có thật sự khoái những điều tôi đã làm không?

Sau đó Jerry đi xuyên qua trọn bộ chương trình, đọc lại từ đầu đến cuối như thể gã đang đọc bài chứng minh hình học. Gã bảo tôi đây là một bước hết sức quan trọng. "Ðến bước này, tụi mình đã thực hiện refactoring các mảnh mã. Bây giờ tụi mình xem thử trọn bộ chương trình có thể nối liền nhau như một dạng tổng thể".

Tôi hỏi: "Jerry, bộ ông cũng làm như thế với chính mã nguồn của ông sao?"

Jerry quắc mắt lên và nói: "Ở đây tụi tao làm việc với nhau theo nhóm nên không có cái mã nào là của riêng tao hết. Bộ mày cho là cái mã này của riêng mày hở?"

Tôi trả lời hết sức nhỏ nhẻ: "hết nghĩ như vậy rồi, ông ảnh hưởng rất lớn đến mã nguồn này."

Gã trả lời: "Cả hai thằng mình đều ảnh hưởng đến nó, và đây là cách ông C ưa chuộng. Ông ấy không khoái bất cứ một ai làm chủ mã nguồn hết đâu. Trả lời riêng cho câu hỏi của mày: Ðúng vậy, ở đây tụi tao thực nghiệm cái "rơ" refactoring và dọn rác và đây là phương pháp của ông C."

Trong khi đọc qua mã nguồn, Jerry thấy gã không khoái cái tên initializeArrayOfIntegers.

Gã nói: "Cái được khởi tạo ở đây thực ra không phải là một dãy số nguyên, mà là một dãy booleans. Nhưng initializeArrayOfBooleans không hẳn là cách cải tiến. Ðiều chúng ta thực sự muốn làm ở method này là liệt kê ra một danh sách các số nguyên phù hợp và để chúng lên một cái sàng, rồi sau đó lọc và loại ra các số không phải số nguyên tố (ie loại ra những bội số)". (Do đó, danh sách lúc đầu sẽ không bị gạch chéo, những số bị loại sẽ sẽ bị gạch chéo (crossed out )).

Tôi trả lời: "Tất nhiên!" Thế là tôi vớ lấy bàn đánh và sửa tên của method đó thành uncrossIntegersUpTo. Tôi cũng thấy không khoái cái tên isCrossed lại dùng cho một dãy booleans, nên tôi đổi nó thành crossedOut. Các cái test vẫn chạy. Tôi bắt đầu thấy thích mấy cái trò này nhưng Jerry vẫn không hề tỏ vẻ đồng tình.

Sau đó Jerry quay lại, hỏi tôi có phải tôi đã mơ màng theo khói thuốc khi viết cái mớ maxPrimeFactor. (Xem mã dẫn 6).
Thoạt đầu tôi hết sức ngỡ ngàng nhưng khi xem lại đoạn mã và các phụ chú tôi nhận thấy gã có lý. Eo ôi, tôi thấy mình thật là ngu! Căn bậc 2 (Square root )* của chiều dài một dãy số không hẳn là nguyên số. Method đó không tính thừa số nguyên tố cực đại (max prime factor) **. Phần chú giải sai bét nên, hết sức ngượng ngùng tôi viết lại phần phụ chú để giải thích rõ hơn cái căn bậc 2 này dùng để làm gì và đổi tên những biến , hàm cho thích hợp. Các test vẫn chạy.

Mã dẫn 6:
Code:
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;
    }
"dùng +1 ở đây làm quái gì vậy?" Jerry tru tréo lên.

Tôi nuốt cái ực, xem lại đoạn mã và cuối cùng tôi phát biểu: "Tôi ngại là khi chỉ lấy phần nguyên của căn bậc 2, thì phần thập phân của căn bậc 2 đó bị mất đi, do đó vòng lặp có thể bị thiếu."

Gã bèn hỏi: "Cho nên mày xả rác trong đoạn mã với phần gia tăng "+1" bởi vì mày bị hoảng? Như thế thì ngốc quá, dẹp ngay cái trò gia tăng "+1" đó đi và thử test lại."

Tôi làm như thế và trọn bộ các test đều chạy. Tôi suy nghĩ lại phần này một lúc vì nó làm tôi run quá. Thế nhưng tôi quyết định có thể giới hạn lặp lại thực sự chính là số "thừa số nguyên tố cực đại" và "thừa số nguyên tố" đó <= căn bậc 2 chiều dài của dãy số.

"Phần thay đổi vừa rồi làm tôi khá bối rối". Tôi nói với Jerry. "Tôi hiểu nguồn gốc đằng sau cái căn bậc 2, nhưng tôi cảm thấy không yên, biết đâu có trường hợp "biên" nào đó mình chưa thấy hết."

Gã lầm bầm "OK, vậy thì viết một cái test khác để kiểm tra chuyện đó đi."

"Tôi nghĩ tôi có thể kiểm tra xem trong các danh sách số nguyên từ 2 đến 500 không có trường hợp ở trên".

"OK, nếu nó làm cho mày cảm thấy dễ chịu hơn, thì thử đi." Gã nói. Rõ ràng là gã bắt đầu trở nên mất kiên nhẫn.

Thế là tôi viết cái testExhaustive function như trong mã dẫn 8. Phần test mới này chạy đúng và nỗi lo sợ của tôi lắng xuống.

Jerry dịu xuống một chút. Gã nói: "Biết được lý do tại sao một cái gì đó chạy được luôn luôn là một điều tốt; và lại càng tốt hơn khi mà kiểm chứng được mày đúng bằng cái test."

Sau đó Jerry dò qua trọn bộ mã nguồn và các cái tests một lần nữa (xem mã dẫn 7 và 8).
Gã ngã người ra và suy nghĩ chừng một phút rồi nói: "OK, tao nghĩ là tụi mình làm xong. Mã nguồn này xem ra đủ rõ ràng (clean) rồi đó. Tao sẽ đưa cho ông C xem."

Thế rồi gã nhìn tôi, lạnh lùng nói: "Phải nhớ, từ nay về sau khi mày viết một phần nào đó, nên tìm sự giúp đỡ và nhớ giữ cho mã nguồn rõ ràng (clean). Nếu mày nhúng tay vào những thứ dưới tiêu chuẩn này, mày không "thọ" ở đây đâu."

Gã rảo bước.

Mã dẫn 7:
Code:
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ã dẫn 8:
Code:
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
      verifyPrime(list[i]);
  }

  private void verifyPrime(int n) {
    for (int factor=2; factor
      assert(n%factor != 0);
  }
 }
Quả là tai hoạ! Tôi cứ ngỡ là giải pháp nguyên thủy của tôi là thượng thặng. Chút gì đó tôi vẫn còn cảm thấy như vậy. Tôi cố phô trương tài năng của tôi nhưng tôi đoán là ông C đánh giá cao sự cộng tác và tính minh bạch hơn tài năng cá nhân.

Tôi phải thú nhận rằng chương trình này dễ xem hơn lúc khởi đầu. Nó lại làm việc ngon hơn một tí nữa. Tôi khá hài lòng với kết quả và, mặc dù Jerry có thái độ cộc cằn, làm việc với gã tôi cũng thấy vui. Tôi học hỏi được rất nhiều.

Dẫu vậy, tôi thấy hơi chùn bước với chính hiệu suất của tôi. Tôi không dám nghĩ là mấy tay ở đây sẽ khoái tôi cho lắm. Tôi cũng không dám chắc đến bao bao giờ họ đánh giá tôi đủ "ngon". Sự thể sẽ khó khăn hơn tôi nghĩ nhiều lắm.

* Square root hay căn số là cách gọi trước đây cho căn bậc 2, một cách gọi được dùng sau này ở VN (chú thích này dành cho những ai thắc mắc với 1 số thuật ngữ toán học xưa và nay ;))

** max prime factor hay thừa số nguyên tố cực đại (hoặc phân tố cực đại nguyên số) cũng là những thuật ngữ toán (quen dùng) trước đây. cực đại [/i]có thể dịch là tối đa nếu muốn (chú thích này một lần nữa dành cho những ai thắc mắc với 1 số thuật ngữ toán học xưa và nay ;))

<đón đọc phần kế tiếp>
Bảng gốc (tiếng Anh): down here
Về Đầu Trang Go down
Xem lý lịch thành viên
7113
Hết Chổ Nói
Hết Chổ Nói


Nữ
Tổng số bài gửi : 409
Đến từ : nơi chứa rất nhiều phiền não
Registration date : 18/05/2007

Bài gửiTiêu đề: Re: Crafsman   08/08/07, 10:02 am

The crafsman Four.
Tối qua tôi ngồi tựa cửa sổ hàng giờ, nhìn các vì sao mờ dần trong bầu trời đêm. Tôi thấy việc làm của tôi và Jerry hôm qua có nhiều xung đột. Tôi học hỏi rất nhiều trong khi làm việc với Jerry với vấn đề tạo số nguyên tố, nhưng tôi không tin tôi gây ấn tượng gì với gã. Và, thật tình mà nói, tôi cũng không nể gã cho lắm. Thật ra, gã tốn khá nhiều thời gian mài dũa các
mảnh mã cho dù những mảnh mã này làm việc ngon lành.

Hôm nay với một bài tập mới, Jerry đến gặp tôi. Gã yêu cầu tôi viết một chương trình tính thừa số nguyên tố của số nguyên. Gã cho biết gã làm việc với tôi ngay từ đầu nên hai chúng tôi ngồi xuống và bắt đầu lập trình.

Tôi tin chắc tôi biết cách làm. Hôm qua chúng tôi đã viết chương trình tạo số nguyên tố. Dò tìm các thừa số nguyên tố chỉ là vấn đề đi xuyên qua danh sách các số nguyên tố và xét thử có thừa số nào từ các số nguyên đã định. Thế nên tôi vớ lấy bàn đánh và bắt đầu viết mã. Khoảng nữa giờ sau khi viết và kiểm tra, tôi làm được như sau:

Code:
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;
 }
}
Tôi kiểm tra chương trình bằng cách chạy nó với nhiều thông số khác nhau. Mọi thứ dường như ổn thoả. Chạy chương trình với giá trị thông số 100 cho tôi kết quả 2, 2, 5 và 5. Chạy nó với 32767 cho tôi 7, 31 và 151. Chạy với 32768 cho tôi mười lăm số hai.

Jerry ngồi nhìn tôi. Gã chẳng nói nửa lời. Ðiều này làm tôi hơi hoảng nhưng tôi tiếp tục nắn bóp và thử nghiệm mã nguồn cho đến lúc tôi hài lòng. Sau đó, tôi bắt đầu viết phần "unit tests".

Jerry hỏi: "Mày làm gì vậy?"

"Chương trình chạy nên tôi đang viết các unit tests." Tôi đáp lại.

"Nếu chương trình đã chạy việc gì mày cần unit tests?" Gã hỏi tiếp.

Tôi không nghĩ đến điểm này. Tôi chỉ biết theo thông lệ cần phải viết unit tests. Tôi liều lĩnh đoán mò: "Ðể mà các lập trình viên khác biết được là chương trình đó chạy?"
Jerry nhìn tôi khoảng 30 giây rồi gã lắc đầu và nói: "Thời buổi này họ dạy dỗ tụi mày cái gì ở trường vậy?"

Tôi đớ lưỡi không trả lời được nhưng gã ngăn tôi lại bằng một cái nhìn.

"OK", gã nói, "xoá hết những thứ mày đã làm đi. Tao chỉ cho mày cách tụi tao làm ở đây."

Tôi quả không chuẩn bị cho tình thế như vậy. Gã muốn tôi xoá những gì tôi đã tạo ra trong ba mươi phút qua. Tôi chỉ ngồi yên, không tưởng tượng nổi.

Cuối cùng Jerry nói: "Xoá đi."

Tôi trả lời: "Nhưng chương trình đó chạy mà."

"Thì sao?" Jerry đáp lại.

Tôi bắt đầu nổi cáu. Tôi nói cứng: "Chương trình này chẳng có gì sai hết!"

"Thực vậy hở?" gã lầm bầm và vớ lấy bàn đánh, xoá hết mã nguồn của tôi.

Tôi điếng người. Không phải, tôi điên tiết lên. Gã mới vừa chồm qua và xoá hết đồ của tôi. Trong phút chốc ấy tôi chẳng còn thiết gì đến ưu thế được làm một tay học việc cho ông C nữa. Học việc mà phải đụng đến những kẻ tàn bạo như Jerry thì còn hay ho gì nữa? Với ý nghĩ như thế và những ý nghĩ còn kém phần tưởng thưởng khác diễn nhanh qua trong đầu trong khi tôi nhìn gã chằm chặp.

"À, tao thấy mày nổi đoá rồi đó." Jerry nói một cách điềm tĩnh.

Tôi lắp bắp nhưng chẳng thốt được gì cho minh bạch.

"Này." Jerry nói, rõ ràng đang cố làm dịu tôi xuống. "Ðừng có đeo cứng vào mã nguồn của mà quá như vậy. Chỉ có ba mươi phút làm việc mà thôi chẳng phải là cái gì ghê gớm đâu. Mày phải chuẩn bị tinh thần vứt bỏ thêm cả đống mã nguồn nữa nếu mày muốn trở thành một thứ lập trình viên gì đó. Vứt bỏ được hàng đống mã nguồn thường là điều tốt nhất mà mày nên làm.

Tôi buộc miệng: "Nhưng làm như thế thì quả là phí!"

Gã hỏi lại: "Bộ mày nghĩ giá trị của chương trình nằm trong mã nguồn sao? Không phải vậy. Giá trị của một chương trình nằm trong cái đầu của mày đó."

Gã nhìn tôi chừng một giây rồi tiếp tục. "Có bao giờ mày lỡ tay xoá cái gì đó mày đang làm chưa? cái gì đó mất của mày vài ngày làm việc đó?"

"Có một lần, ở trường". Tôi nói "Cái disk bị hỏng và hồ sơ lưu trữ cũ đến hai ngày."

Gã cau mày gật đầu biểu lộ sự thông hiểu rồi hỏi: "Mày mất bao lâu để tái tạo lại những cái đã bị mất?"

"Tôi nắm khá rõ những cái bị mất nên chỉ mất có nửa ngày để tái tạo."

"Ra thế mày chẳng thật sự mất khối lượng hai ngày làm việc."

Tôi chẳng màng gì đến cái logic của gã. Tôi không bắt bẻ được nhưng tôi không khoái cái logic đó. Chỉ đơn giản là tôi cảm thấy bị mất một khối lượng hai ngày làm việc!

Gã hỏi tiếp: "Mày có nhận thấy phần mã làm lại tốt hơn hay tệ hơn phần mã mày bị mất không?"

"Ồ, tốt hơn nhiều." Tôi nói, ngay lập tức hối tiếc là đã phát biểu như thế.
"Lần thứ nhì tôi có thể dùng một cấu trúc tốt hơn nhiều."

Gã cười. "Thế thì cố thêm 25 phần trăm, mày đưa ra được một giải pháp tốt hơn."

Logic của gã làm tôi bực mình. Tôi lắc đầu và gần như thét lên: "Có phải ông giả định là chúng ta luôn luôn vứt bỏ mã nguồn sau khi làm xong?"

Trả lời cho sự ngạc nhiên của tôi, gã gật đầu và nói: "Gần như là như vậy. Tao giả định chuyện vứt bỏ mã nguồn là một việc giá trị và hữu dụng. Tao giả định mày không nên xem đó là chuyện hoang phí. Tao giả định mày không nên ôm khư khư cái mã nguồn của mày."

<đón xem phần kế tiếp>

Bảng gốc (tiếng Anh): down here
Về Đầu Trang Go down
Xem lý lịch thành viên
Sponsored content




Bài gửiTiêu đề: Re: Crafsman   Today at 05:11 pm

Về Đầu Trang Go down
 
Crafsman
Xem chủ đề cũ hơn Xem chủ đề mới hơn Về Đầu Trang 
Trang 1 trong tổng số 1 trang

Permissions in this forum:Bạn không có quyền trả lời bài viết
Forum NIIT ChoLon :: Diễn Đàn Giải Trí :: Thư giãn cuộc sống-
Chuyển đến