Pages

August 4, 2013

Để xóa được thư mục khi đường dẫn quá dài


--------------------------------------

Script to Delete Folder when Path Too Long

This script will delete a folder even if the path is too long.
The script requires Robocopy, which comes with Vista and Windows 7, or you can download the exe for XP and Server 2003 and save it in C:\Windows\System32.
Save the script as DelFolder.bat, in C:\Windows\System32
Usage: DelFolder
@echo off
if {%1}=={} @echo Syntax: DelFolder FolderPath&goto :EOF
if not exist %1 @echo Syntax: DelFolder FolderPath - %1 NOT found.&goto :EOF
setlocal
set folder=%1
set MT="%TEMP%\DelFolder_%RANDOM%"
MD %MT%
RoboCopy %MT% %folder% /MIR
RD /S /Q %MT%
RD /S /Q %folder%
endlocal

March 23, 2013

Niềm vui của sự đọc lại




Những cuốn sách trở nên tuyệt hơn khi chúng ta hiểu chúng hơn: đọc đi đọc lại, và biết rằng ta sẽ chẳng bao giờ hiểu hết được chúng. ĐBND giới thiệu bài của Joan Wickersham trên báo Địa cầu Boston (The Boston Globle).
Niềm vui của sự đọc lại
Vào năm mười tám tuổi, tôi kết bạn với một nhà văn tuổi tầm ba mươi. Một ngày nọ tôi hỏi ông đang đọc sách gì. “Tôi đang bắt đầu đọc lại” - ông nói. Chắc ông hết sách rồi, tôi nghĩ bụng. Lúc ấy tôi hơi tiếc cho ông, và chột dạ khi nghĩ rằng sau này chắc không còn nhiều sách hay cho mình trong khoảng mươi năm nữa. Phải chăng ông bạn vong niên ấy đã gợi ý rằng rồi sẽ có lúc chúng ta mắc kẹt với sự lặp lại?
Hôm nay, hơn ba thập kỷ sau, tôi mới vỡ ra những gì ông nói. Bạn không bao giờ hết sách để đọc, thế nhưng cũng giống như khám phá những điều mới lạ, một trong những niềm vui lớn của cuộc sống là đọc lại: trở lại với cuốn sách lần thứ hai hay thứ ba hay thậm chí lần thứ năm, và xem thử tác phẩm đã sâu sắc và rộng mở hơn chừng nào từ lúc bạn ghé thăm nó lần trước đó.
Lần đầu bạn đọc cuốn Ước vọng lớn lao của Dickens, hẳn bạn chỉ đọc để nắm cốt truyện. Điều xảy ra tiếp theo là gì? Ân nhân bí ẩn của Pip là ai? Và Estella, cô gái có trái tim lạnh lùng mà anh yêu, sẽ xiêu lòng và nhận lời cầu hôn của anh không? Dickens sẽ làm thế nào để dệt nên các sợi chỉ, và tấm thảm sẽ như thế nào vào lúc nó hoàn thành? Lần thứ hai đọc cuốn sách, bạn đã thấy hết toàn cục các họa tiết của tấm thảm. Bạn biết rằng đây là tác phẩm về sự ảo tưởng. Bạn nhận ra những sai lầm của Pip với tư cách là người dẫn truyện. Bạn có thể tin vào những điều anh ta kể, nhưng không nên tin tưởng khi anh ta nói với bạn về ý nghĩa của chúng. Bạn hiểu rằng đây là cuốn sách nói về những sai lầm – và diễn tả chi tiết cái cách chúng ta mắc sai lầm, Dickens đã làm rất đúng cách.
Lần đầu tiên đọc Ethan Frome, bạn thấy chán. Có lẽ bạn đang độ tuổi thiếu niên, và đọc tiểu thuyết trong một lớp học tiếng Anh ở trung học. Các giáo viên giới thiệu bởi vì nó ngắn. Tuyết, nước đá, và một đống người vùng Tân Anh Cát Lợi cộc cằn kiệm lời. Để làm cho mọi việc tồi tệ hơn, tác phẩm bắt đầu với cảnh các nhân vật chẳng đáng kể, điều đó khiến bạn có thể muốn ném cuốn sách ra cửa sổ - vẫn cái cửa sổ mà thông qua đó bạn sẽ muốn quăng cả Madame Bovary, Đỉnh gió hú và Antonia của tôi.
Nhưng nếu bạn đọc lại Ethan Frome một lần nữa hai mươi năm sau đó, bạn sẽ ngạc nhiên trước bao nhiêu niềm đam mê và lòng trắc ẩn mà Edith Wharton đã có thể đúc kết giữa các dòng của cuốn sách bình dị đó. Hình thức của tác phẩm hoàn toàn phù hợp với chủ đề của nó, đó là một cuốn tiểu thuyết kiệm lời về những người ít nói, về những cảm xúc sâu sắc khó diễn đạt thành lời. Cuốn sách trở nên khác đi khi bạn đọc lại, khi bạn đã sống đủ lâu để hiểu được những điều mà ngôn từ không thể diễn tả. Như những gì mà người thuật lại nói trong chương đầu tiên trước khi ông ấy biến mất khỏi cuốn sách. “Ý nghĩa sâu xa hơn của câu chuyện nằm trong các khoảng trống”.
Lần đầu tiên bạn đọc Middlemarch, hầu như là trong thời sinh viên, bạn nghĩ rằng đó là cuốn sách về những người khác. Bạn không bao giờ hướng cuộc sống của mình đi sai đường, giống như các nhân vật dễ mến nhưng lạc lối của George Eliot: Dorothea, kết hôn với một người đàn ông mà cô nghĩ là thiên tài nhưng hóa ra lại là một kẻ ích kỷ, đa nghi, nhăn nhó và luôn tỏ vẻ thông thái rởm. Lydgate, một bác sĩ trẻ theo chủ nghĩa lý tưởng, lại yêu phải một thằng ngốc vị kỷ. Fred, người vẫn cứ ngoan cố vung tiền cho dù cô gái mà anh yêu chỉ kết hôn với anh nếu anh biết dừng lại. Tất cả họ đều bắt đầu với những ước mơ và tham vọng, cuộc sống khiến họ thất vọng và ngay cả chính họ cũng làm bản thân mình thất vọng. Có thể bạn sẽ nghĩ, đáng thương thay cho những kẻ ngốc.
Khi bạn đọc cuốn sách một lần nữa - lúc bạn khoảng ba mươi tuổi chẳng hạn - bạn có một chút sợ hãi lạ lùng rằng đó là một cuốn sách về bạn. Bạn chưa từng phạm phải những sai lầm như các nhân vật của George Eliot, nhưng bạn đã phạm các sai lầm khác. Bạn có nỗi thất vọng của riêng bạn. Kế hoạch sự nghiệp không thành. Sai lầm trong chuyện tình cảm. Bí mật mà bạn giấu kín, với hậu quả tai hại; bí mật được đưa ra ánh sáng, lại chẳng khác gì thảm họa. Bạn vẫn còn ở đây, nhưng bạn điềm đạm, ít bóng bẩy hơn. Tóm lại, bạn đã từng trải.
Ngày tháng đi qua, càng lớn tuổi, bạn ngày càng sẵn sàng hơn cho việc đọc lại cuốn Middlemarch. Thời gian này bạn sẽ nhận ra rằng nó không phải là một cuốn sách về những người khác và nó cũng chẳng phải là một cuốn sách về bạn. Nó là cuốn sách về tất cả chúng ta. Trong thực tế, tác phẩm văn chương này là bức tranh toàn cảnh về con người mang tính bao quát nhất, đồ sộ nhất, vô tư nhất, và nhân bản nhất từng được viết. Tôi đọc lại tác phẩm khoảng một năm trước, với một người bạn bảy mươi bảy tuổi cũng từng đọc lại cuốn đó. Hầu như mỗi buổi sáng, chúng tôi đều gọi nhau ra để tán dóc về các cư dân của Middlemarch, những gì họ đã làm và tại sao. Thị trấn của George Eliot đã trở thành thị trấn của chúng tôi.
Việc đọc lại là không bao giờ cũ. Những cuốn sách thay đổi vì chúng ta thay đổi. Những cuốn sách trở nên tuyệt hơn khi chúng ta hiểu chúng hơn: đọc đi đọc lại, và biết rằng ta sẽ chẳng bao giờ hiểu hết được chúng.

December 17, 2012

Cấp độ bia

Có 1 bài post lưu truyền trên mạng thấy là khá Good, nói về cấp độ ăn nhậu của 1 sư phụ đã đi đến level max của nghệ thuật nốc, các bạn xem và tự đánh giá nhé.

1. Nhập môn:

Biểu hiện: thường ngồi im, ko nói năng gì, nhấp môi theo kiểu 1 ly bia uống đến sáng, hoặc có trường hợp cá biệt là nói năng hoạt bát, uống liên tục vài ly chứng tỏ rồi gục ngã ngay...

tỷ lệ đi xích lô 50%, chó ăn chè 30%, bình an 30%

Mức độ: 1 ly đến 3 lon tùy thể trạng
Khuyến cáo: nên ngồi im, nhấp môi và ăn là chính, hoăc uống ngụm nhỏ, đặc biệt phải ngừng ở chai thứ 3 , ko được hơn. Tốt nhất nên đi cùng bạn hoặc ko lái xe.

2. Lên đô:

Biểu hiện: điệu bộ , cử chí có vẻ tự nhiên hơn giai đoạn nhập môn, mọi thứ trên bàn nhậu đã dần hết bỡ ngỡ, có khả năng uống đến nửa ly 1 lần, có khả năng cùng bạn bè "dô dô..." mặc dù uống vẫn còn long đền, bắt đầu nói chuyện với bạn bè ngồi bên cạnh, ăn ít dần...

tỷ lệ đi xích lô 20%, chó ăn chè 20%, bình an 60%

Mức độ : 3 chai đến 8 chai tùy thể trạng

Khuyến cáo: vẫn còn là "ếch ngồi đáy giếng", ko nên nôn nóng khiêu khích đối thủ cùng bàn, nếu đụng bàn "ngọa hổ tàng long" thì người cho "chó ăn chè" là chính bạn chứ ko ai khác

3. Độc cô cầu bại:


Biểu hiện: trung tâm của nhóm, nói năng huyên thuyên, đôi lúc thành nói nhảm, từ đầu bàn nói đến cuối bàn, ăn rất ít, uống rất nhiều, khả năng uống 100% tốt, bắt đầu so bì về lượng bia rượu với đối thủ theo kiểu :" tại sao còn long đền, tại sao mới uống có 50% khi tao uống hết"...bắt đầu có thể có những hành vi ko tốt đối với bạn nhậu...

Tỷ lệ đi xích lô 10%, chó ăn chè 0%, bình an 30%

Mức độ: 8 chai đến 15 chai tùy thể trạng

Khuyến cáo: nên tập tạ để có thể trạng tốt, tránh hoặc chịu được những trận đòn do những "biểu hiện" trong khi "cầu bại"

4. Chủ xị:

Biểu hiện: uống ko biết say xỉn, luôn tìm kiếm không khí vui vẻ bên bàn nhậu, luôn là người đến sớm nhất, và là người về trễ nhất để nhìn từng chiến hữu gục ngã,đã có khả năng kêu xích lô cho bạn bè...và tất nhiên, luôn là ng trả tiền để có được đám "bạn tốt" vì mình thèm nhậu mà đến nhậu vì mình. Bắt đầu quên mất gia đình, vợ con, cha mẹ..chỉ là phù du, cuộc đời lấy đám bằng hữu và chai rượu làm lẽ sống.

Mức độ : 16 chai đến 1 két

Khuyến cáo: quay đầu là bờ, đừng để bia rượu lấn át lý trí, ảnh hưởng sức khỏe.

Tỷ lệ gục ngã 0%, chó ăn chè 0%, bình an 30%

5. Tiên tửu:

Biểu hiện: đã qua thời "coi trời bằng vung", có thể uống liên tục ko cần ăn, khả năng uống 100% là tuyệt vời. "bạn tới đâu, mình tới đó" rất đúng với giai đoạn này, và ai được uống với "tiên tửu", đó là 1 vinh dự. vì "tiên tửu" ko cần đông người, chỉ cần 1 người thôi cũng là quá đủ, lúc đó, bạn thành tri kỷ của họ, họ ko ép bạn uống, và bạn có vinh dự được nghe họ "huyên thuyên" kể về 1 đề tài nào đó, mặc dù bạn đã nghe mới vài phút trước từ chính họ.

Mức độ: ko thể ước lượng được

Khuyến cáo: nếu tiếp tục, có thể "tiên tửu" sẽ lên trời nhậu lẩu cá với ông Táo

Tỷ lệ gục ngã 0%, chó ăn chè 0%, bình an 90% ( do 10% đột tử)

6. Chí phèo:

Biểu hiện: uống bia rượu một mình mỗi ngày như thể sinh ra chỉ để như thế, có thể làm tất cả để có thể được uống bia rượu, bạn bè xa lánh, vợ con nghèo đói,bản thân nghèo kiết xác, có những khả năng "xuất quỷ nhập thần" như : chửi bức tường, nói chuyện với hòn đá...

Mức độ: ko có

Khuyến cáo: nên chết đi


Đây là giai đoạn cuối cùng của 1 "nhân tài" về bia rượu, cũng là cảnh giới tối cao mà trong giới "võ lâm trung nguyên" ai cũng ngưỡng mộ lẫn khiếp sợ, vì chỉ cần 1 cái v chạm, hay chỉ 1 ánh nhìn, hoặc chỉ cần "chí phèo" thấy ko vui, thì họ có thể tiễn bạn hoặc cả gia đình bạn đi về nơi xa lắm. 

Mình thì chỉ vừa chạm đến level 2. Còn bạn ?

December 12, 2012

Những lỗi phổ biến trong trình bày bằng Powerpoint


Đã dự rất nhiều hội nghị khoa học lớn và nhỏ ở nhiều nơi, kể cả ở Việt Nam, tôi thấy một số sai lầm phổ biến trong cách trình bày bằng powerpoint (PPT). Những sai lầm này thường liên quan đến cách soạn slide, nội dung, và cách trình bày. Thật ra, ngày xưa, lúc mới bước vào học, tôi cũng từng phạm phải những sai lầm như thế, nhưng nhờ có thầy chỉnh sửa và hướng dẫn, nên đã tránh được những sai lầm đó và học hỏi thêm nhiều kinh nghiệm. Nay đã đến lúc tôi có thể chia sẻ những kinh nghiệm cá nhân cùng các bạn.

Mục tiêu của bất cứ bài nói chuyện nào cũng là chuyển giao thông tin. Chuyển thông tin từ một cái đầu sang nhiều cái đầu. Không chỉ chuyển giao, mà còn phải chuyển giao một cách có hiệu quả. Để đạt được hiệu quả, diễn giả cần phải có nội dung tốt, một bộ slide hoàn chỉnh, và một phong cách trình bày chuyên nghiệp. Chỉ khi nào một bài thuyết trình hội đủ 3 nhu cầu trên thì mới có thể xem là thành công.
Nhưng trong thực tế, tôi đã thấy rất nhiều bài nói chuyện trong các hội nghị trở thành nhạt nhẻo, và khán giả chẳng học hỏi được gì từ bài nói chuyện. Chúng ta có câu Chiếc áo không làm nên thầy tu. Tương tự, nếu diễn giả có một nhúm slide, chưa chắc diễn giả đó đã có một bài thuyết trình. Một nhúm slide khác với một bài thuyết trình. Đã từng tham dự nhiều hội nghị và hội thảo ở Việt Nam, tôi rút ra một số kinh nghiệm, hay nói đúng hơn là một số sai lầm phổ biến dưới đây.
Những sai lầm khi soạn slide
1. Vấn đề chọn màu. Một trong những sai lầm phổ biến nhất là cách chọn màu cho slide. Có hai màu diễn giả cần phải chọn: màu nền (background color) và màu chữ (text color). Nhiều diễn giả không chú ý nên chọn màu không thích hợp. Chẳng hạn như nền màu xanh đậm mà chữ màu đỏ hay màu đen, hoặc nền màu trắng nhưng chữ màu vàng, v.v. là không thích hợp. Không thích hợp vì rất khó đọc. Nhiều người Việt có thói quen chọn màu đỏ chói làm màu nền, và đó là một cách chọn không thích hợp, vì màu đỏ là màu “high energy” làm cho người đọc rất khó chú ý.
Nếu hội trường rộng, nên chọn màu chữ sáng (màu vàng, trắng) trên nền tối (màu xanh đậm). Nếu hội trường nhỏ hay trung bình, nên chọn chữ màu đậm (xanh đậm hay đen) trên nền sáng (màu trắng).
http://www.thugmed.com/home/wp-content/uploads/2008/11/bad-slide.jpg
Một ví dụ về chọn màu nền (mây) và màu chữ không thích hợp


2. Vấn đề chọn kiểu chữ (font). Kiểu chữ có ảnh hưởng đến khả năng tiếp thu và tốc độ đọc. Nhiều diễn giả không chú ý đến font chữ khi soạn slide, nên gây khó khăn cho khán giả. Có hai loại kiểu chữ chính: kiểu chữ có chân và kiểu chữ không có chân (sans serif). Kiểu chữ có chân tiêu biểu là Time, Times New Roman, Cambria. Kiểu chữ không có chân là Arial, Verdata, Calibri. Nhiều người Việt thích chọn kiểu chữ có chân vì họ nghĩ đó là kiểu chữ đẹp. Đẹp thì đúng, nhưng là một sai lầm trong PPT, vì có nhiều nghiên cứu chỉ ra rằng kiểu chữ có chân làm người ta tốn thì giờ đọc hơn là kiểu chữ không có chân. Đó cũng chính là lí do tại sao các “đại gia” internet như Yahoo! và Google dùng chữ không có chân trên các trang web của họ.
Có diễn giả thích “trang trí” chữ bằng cách làm bóng (shadow) cho chữ. Đây là một kĩ thuật chẳng những mất thì giờ, mà còn phản tác dụng, vì rất khó đọc và nhức mắt. Tuyệt đối không “trang trí” chữ bằng bóng!
3. Khổ chữ. Không gì khó chịu hơn khi diễn giả trình bày slide mà khán giả không đọc được vì khổ chữ quá nhỏ. Nhưng trong thực tế thì vấn đề này xảy ra rất nhiều lần, mà diễn giả thì có vẻ rất vô tư, không quan tâm đến khán giả. Kinh nghiệm của tôi cho thấy nên chọn cỡ chữ từ 18 đến 30. Nếu chọn kiểu chữ Arial thì khổ chữ 18 hay 20 là hợp lí; nếu chọn kiểu chữ Calibri thì kích thước phải cỡ 25 hay 30 mới dễ đọc. Mỗi slide nên có tựa đề, và tựa đề nên có kích thước 35 đến 45.   Nếu có ghi chú (footnote) thì có thể dùng kích thước 12.
4. Quá nhiều chữ trong slide. Một trong những sai lầm phổ biến nhất là diễn giả trình bày quá nhiều chữ trong một slide. Có nhiều slide, tôi không phân biệt được là một đoạn văn hay là một power point. Thật vậy, có nhiều người vì lí do nào đó (có thể là lười biếng) nên cắt từ Word và dán vào slide. Cũng có người có thể do sợ không thuộc bài, nên viết hết những câu văn trên slide như là một văn bản. Đây là một sai lầm tai hại, vì khán giả sẽ không theo dõi được. Nghiên cứu tâm lí chỉ ra rằng, một người bình thường chỉ có thể lĩnh hội nội dung slide trong vòng 20-30 giây; nếu qua thời gian đó mà không lĩnh hội được thì họ sẽ bỏ, và diễn giả đã thất bại trong việc truyền đạt thông tin.
Để khắc phục vấn đề này, cần phải biết “qui ước n x n”. Theo qui ước này, nếu slide có n dòng, thì mỗi dòng chỉ nên có n chữ. Chẳng hạn như nếu slide có 5 dòng thì mỗi dòng nên có 5 chữ. Một slide có 6 dòng trở nên là quá nhiều. Số dòng lí tưởng là 3-5.
5. Viết slide như viết văn bản. Người thiếu kinh nghiệm thường soạn slide như họ viết văn bản, tức là câu cú có chủ từ, động từ, theo đúng văn phạm. Dĩ nhiên, không có gì sai trong cách làm như thế, nhưng đó là cách làm thiếu tính chuyên nghiệp. Người có kinh nghiệm soạn slide theo công thức telegraphic, tức viết giống như viết điện tín ngày xưa, hay như cách phóng viên viết tiêu đề bài báo. Cách viết telegraphic có hiệu quả giảm số chữ trong mỗi slide, và giúp diễn giả tập trung vào cách diễn giải vấn đề hơn là đọc. Một cách phân biệt cách viết theo kiểu văn bản và telegraphic như sau:
  • Văn bản: Loãng xương là một bệnh với đặc điểm mật độ xương suy giảm dẫn đến gia tăng nguy cơ gãy xương.
  • Telegraphic: Loãng xương – mật độ xương giảm à nguy cơ gãy xương tăng.
Tất cả slide, ngoại trừ những trích dẫn nguyên văn, nên được viết theo kiểu điện tín.
 
Những vấn đề liên quan đến nội dung
6. Không có thông điệp chính. Có nhiều hội nghị mà chúng ta khi nghe xong một bài thuyết trình nhưng chẳng biết diễn giả muốn nói gì, hay mình đã tiếp thu thông tin gì. Vấn đề ở đây là diễn giả đã thất bại cung cấp một thông điệp chính. Mỗi một bài thuyết trình phải có một thông điệp chính. Thông điệp chính cần phải trình bày trong một slide mà tiếng Anh gọi là money slide, hiểu nôm na là một “slide ăn tiền”. Nếu thông điệp chính không có trong bài thuyết trình thì khán giả cảm thấy mất thì giờ đến nghe vì chẳng có tiếp thu được thông tin gì xứng đáng. Do đó, trước khi soạn bài nói chuyện, diễn giả cần phải suy nghĩ cẩn thận cái money slide là gì, trước khi soạn những slide khác.
7. Chất lượng thông tin nghèo nàn. Nhiều bài thuyết trình mà trong đó diễn giả trình bày những thông tin nghèo nàn, thiếu tính liên đới đến chủ đề chính, và hệ quả là khán giả không nắm lấy vấn đề một cách logic. Làm một bài thuyết trình bằng powerpoint không phải là một thử nghiệm về kĩ năng viết, mà là kĩ năng chọn thông tin và thể hiện thông tin. Thông tin phải chính xác, đáng tin cậy, và được thể hiện một cách thích hợp. Chẳng hạn như trong khoa học, những cách thể hiện dữ liệu bằng biểu đồ bánh (pie chart) là vô dụng nhất, thiếu tính chuyên nghiệp nhất, và nhàm chán nhất.
8. Dùng hoạt hình quá nhiều. Nhiều người thích dùng hoạt hình (animation) trong bài thuyết trình. Đây là một sai lầm nghiêm trọng. Giới khoa học nói chung tương đối bảo thủ, hiểu theo nghĩa không thích đùa như trẻ con. Hoạt hình được xem là một hình thức khoe kĩ thuật của trẻ con. Hoạt hình còn làm cho khán giả phân tâm, thay vì tập trung vào thông tin thì họ lại chú ý đến những hình ảnh hay những con chữ nhảy nhót một cách … vô duyên. Cần tránh hoạt hình trong các báo cáo khoa học.
9. Dùng clipart quá nhiều. Ngoài hoạt hình, một số diễn giả có xu hướng dùng clipart một cách thái quá. Có thể dùng để minh hoạ cho một vài ý tưởng qua clipart, nhưng nếu dùng quá nhiều thì sẽ gây phản tác dụng, vì sẽ giảm sự tập trung của khán giả.
Những vấn đề liên quan đến phong cách trình bày
10. Đọc slide. Có quá nhiều diễn giả trong các hội nghị ở Việt Nam đọc slide, và đó là một “đại kị”. Khi diễn giả đọc slide, khán giả sẽ nghĩ diễn giả chỉ là một cái máy nói, không am hiểu vấn đề, và thụ động. Đọc slide làm cho diễn giả quay lưng lại với khán giả, trong khi “nhiệm vụ” của diễn giả là nói chuyện với khán giả chứ không phải nói với … slide. Đọc slide còn gây một ấn tượng phản cảm, vì khán giả nghĩ rằng diễn giả chỉ nói những gì ai đó đã soạn cho để nói (trong thực tế cũng có vấn đề này).
 
11. Nói chuyện không dính dáng gì đến slide. Ngược lại với đọc slide là những diễn giả nói chuyện chẳng liên quan gì đến slide đang trình chiếu. Dĩ nhiên, đây là một tín hiệu cho thấy diễn giả đang lạc đề hoặc không có tập dượt trước, nhưng cũng có thể là dấu hiệu cho thấy diễn giả không nắm vững vấn đề. Vì không nắm vững vấn đề bắt đầu … lan man. Tình trạng này xảy ra rất nhiều khi diễn giả không phải là người soạn slide (mà ai đó soạn cho).
Nên nhớ rằng khi thuyết trình khoa học, diễn giả cần phải có tạo niềm tin bằng cách trình bày những nghiên cứu hay tác phẩm của mình. Nếu trong một bài nói chuyện mà diễn giả chẳng có cái gì của mình, toàn là dữ liệu của người khác, hoặc do người khác soạn, thì khán giả sẽ nghĩ rằng diễn giả chỉ là một cái "máy nói", một con rối.
12. Không dùng laser pointer. Một trong những “bệnh” khá phổ biến ở các diễn giả Việt Nam là không dùng laser pointer. Một bài thuyết trình khoa học có nội dung không phải dễ theo dõi, nhất là có những giản đồ phức tạp minh hoạ cho một qui trình khoa học, do đó diễn giả cần phải dẫn dắt khán giả bằng cách dùng laser pointer để chỉ đến những chỗ đang nói. Không có laser pointer, khán giả sẽ rất khó theo dõi, và họ sẽ bỏ cuộc nếu sau 30 giây mà không hiểu diễn giả muốn nói gì.
Nhưng cũng nên sử dụng pointer thích hợp. Một thói quen ngược lại không dùng pointer là dùng tuỳ tiện, quơ pointer ở những vị trí chẳng liên quan gì đến slide. Có người do vô ý hay hồi hộp cứ quơ laser pointer trên trần nhà làm khán giả cứ theo dõi và buổi trình bày trở nên hài hước.
13. Nói quá giờ. Một “bệnh” cực kì phổ biến ở các diễn giả Việt Nam là nói quá giờ. Nói quá giờ cho phép là một sự bất lịch sự đối với diễn gỉa kế tiếp (có người nói nặng nề hơn là “ăn cắp” thì giờ). Nói quá giờ còn gây rối loạn đến chương trình và gây khó khăn cho ban tổ chức. Cố gắng nói đúng giờ cho phép. Một ước tính quan trọng là mỗi slide trung bình tốn 1 phút. Do đó, nếu bài báo cáo 15 phút thì diễn giả chỉ nên có 15 slides, hay tối đa là 20 slides (kể cả tựa đề, phần cảm tạ, và conflict of interest).
14. Điệu bộ khi trình bày. Tuy không phổ biến lắm, nhưng thỉnh thoảng tôi vẫn thấy những diễn giả có những điệu bộ không thân thiện với khán giả. Những điệu bộ này có thể kể đến như bỏ tay vào túi quần, dùng ngón tay trỏ chỉ vào khán giả, khoanh tay ngang ngực, v.v. Những động thái như thế gây ấn tượng hống hách, xem thường khán giả, nên rất phản cảm. Cần phải tuyệt đối tránh!
15. Làm chủ toạ theo kiểu dạy đời. Ngoài những “bệnh” trên, còn có một bệnh khác tôi hay thấy trong các hội nghị ở Việt Nam là vai trò của chủ toạ. Rất thường xuyên tôi thấy chủ toạ đóng vai trò tóm lược và phê bình báo cáo của diễn giả. Có chủ toạ còn lên lớp cho diễn giả. Đó là một việc làm hết sức mất lịch sự, vô lễ, vô văn hoá khoa học,và phản cảm. Có nhiều trường hợp sự việc xảy ra một cách hài hước, vì người chủ toạ nói sai (do không có cùng chuyên môn, hay chuyên môn chưa vững). Trong thực tế, chủ toạ các phiên họp khoa học có nhiệm vụ giới thiệu bài nói chuyện, điều khiển buổi họp sao cho đúng giờ, và nếu không có ai đặt câu hỏi thì chủ toạ đóng vai trò “khơi mào” câu hỏi cho diễn giả. Nên nhớ rằng người chủ toạ không có chức năng tóm lược và phê bình bài báo của diễn giả.
***
Trên đây là một số vấn đề (nhưng cũng có thể xem là “sai lầm”) trong báo cáo khoa học bằng powerpoint. Những sai lầm này đặc biệt phổ biến trong các hội nghị ở Việt Nam mà người viết bài này từng trải nghiệm trong thời gian trên dưới 10 năm qua. Sai lầm không phải là vấn đề (vì ai cũng phạm phải); vấn đề là học hỏi từ sai lầm. Học hỏi từ người đi trước là có hiệu quả nhất và nhanh nhất. Trong bài này, tôi đã trình bày một số lời khuyên để khắc phục cho mỗi sai lầm. Tôi đã từng học hỏi từ những sai lầm như thế này. Nhiều đồng nghiệp và nghiên cứu sinh của tôi đã học từ những lời khuyên này và họ đã thành công. Do đó, tôi hi vọng rằng những lời khuyên trong bài này sẽ giúp ích cho các bạn thành công trong lần báo cáo sắp tới.

June 28, 2012

Lỗi khi import dữ liệu từ Excel sang SQL Server

Hôm rồi dự án cần import dữ liệu từ excel sang SQL Server nhưng gặp lỗi khi cố import cột dữ liệu kiểu nvarchar.
There was an error with output column "XYZ" (30) on output "Excel Source Output" (9). The column status returned was: "Text was truncated or one or more characters had no match in the target code page.".
 (SQL Server Import and Export Wizard)

Đã thử tick tùy chọn Ignore Error với vì tưởng là nó sẽ bỏ qua lỗi này khi convert. BS thay nó vẫn cứ trơ gan cùng tuế nguyệt. Biện pháp bất đắc dĩ là ignore column này luôn, nhưng cũng vẫn không được. Làm mình mất toi buổi tối chỉ để ngồi ăn chè và cháo đậu xanh.

Nhờ Gu gồ chỉ điểm, biết được là do cơ chế đọc nguồn từ excel để lấy kiểu dữ liệu. Vấn đề là Import Wizard thực hiện kiểm tra theo cơ chế sampling: quyết định maxlengh cho cột dữ liệu cần import dựa vào dòng có maxlength lớn nhất trong  8 dòng đầu của excel source. Do đó những thằng sau nếu dài hơn là đi cu tèo.

Vậy trick ở đây là nhập dummy data ở dòng đầu tiên sao cho thỏa mãn data type maxlength ở sql source.
Sau khi import xong thì xóa đi hoặc trả lại dữ liệu ban đầu cho nó.

Tạm thời thủ công vậy. Có cách khác "tự động hóa" một chút nhưng chưa kiểm tra được độ tin cậy.

Tham khảo issue được thảo luận ở đây


June 3, 2012

Bạn đã sẵn sàng để thành công ?

Trong một thời đại cạnh tranh khắc nghiệt như hiện nay, thì việc giữ được vị trí công việc hiện tại cũng như tiến cao hơn trong nấc thang sự nghiệp đòi hỏi bạn phải chuẩn bị rất nhiều điều. Dưới đây là 5 điều trong số đó. Nếu muốn thành công nhanh hơn, bạn hãy bắt tay vào làm việc và thử nghiệm nhiều điều hơn nữa.


Chấp nhận rủi ro

Nếu muốn thành công nhanh hơn, bạn hãy bắt tay vào làm việc và thử nghiệm nhiều điều hơn nữa. Hãy hành động nhiều hơn và để mình bận rộn hơn. Hãy bắt đầu ngày mới sớm hơn, làm việc chăm chỉ hơn và ở lại công ty muộn hơn một chút. Hãy dám đương đầu với những may rủi. May mắn là điều hoàn toàn có thể đoán biết. Nếu muốn mình may mắn hơn, bạn hãy đón nhận nhiều cơ hội hơn. Hãy chủ động hơn. Hãy để mình xuất hiện nhiều hơn.

Tom Peters, tác giả của cuốn sách Tìm kiếm thành đạt và nhiều cuốn sách hướng dẫn kinh doanh khác cho rằng, có một phẩm chất căn cốt trong tính cách của các giám đốc điều hành là luôn “thiên về hành động”. Câu thần chú của họ dường như luôn là “sẵn sàng, ngắm và bắn”. Quan điểm của họ đối với việc kinh doanh có thể tóm tắt trong những từ như “Làm, sửa và thử nghiệm”. Họ hiểu rằng, tương lai thuộc về những người có xu hướng hành động, những người dám chấp nhận rủi ro.

Thống tướng Douglas MacArthur từng cho rằng, “Ở đời không có sự đảm bảo, chỉ có cơ hội”. Và có một sự thật thú vị là, nếu bạn tìm kiếm cơ hội, bạn sẽ đạt tới sự đảm bảo mong muốn. Tuy nhiên, nếu bạn tìm kiếm sự bảo đảm, rốt cuộc, bạn không có cả cơ hội lẫn sự bảo đảm đó. Ta có thể thấy rõ điều này từ thực tế quanh mình. Những cuộc giảm biên chế và tái cấu trúc các công ty đã đẩy hàng nghìn người vào tình trạng thất nghiệp lâu dài.


Tự giác

Nếu bạn đã có một mục tiêu để hướng tới và một kế hoạch thực hiện, hãy bắt tay vào thực hiện ngay. Và khi đã xác định được mục tiêu, đừng dừng lại mà kiên trì làm để tiến gần hơn tới mục tiêu. Đừng để quy mô của mục tiêu cũng như khoảng thời gian khổng lồ cần có để hoàn thành nó làm bạn nản lòng.

Trong quá trình lên kế hoạch thực hiện, hãy chia nhỏ mục tiêu lớn thành những nhiệm vụ và hoạt động nhỏ hơn mà bạn có thể đảm đương được. Bạn không nhất thiết phải làm nhiều, nhưng mỗi ngày, mỗi tuần, mỗi tháng, bạn cần phải chứng tỏ sự tiến bộ bằng việc hoàn thành những nhiệm vụ đã đặt ra. Từ đó hướng tới những mục tiêu đã được xác định rõ ràng.

Và đây mới là vấn đề then chốt: Phẩm chất quan trọng nhất để đạt được thành công là tính tự giác. Đó là khả năng bạn bắt mình phải làm những việc cần làm vào đúng thời gian yêu cầu, bất kể việc đó có thích hay không.


Chuẩn bị cho tương lai

Diễn giả nổi tiếng của Mỹ là Earl Nightingale từng nói, nếu ai đó không chuẩn bị cho thành công thì khi cơ hội tới, nó chỉ khiến anh ta trở nên lố bịch thôi. Và hẳn bạn cũng đã nghe nói tới câu danh ngôn, may mắn là cái sẽ chỉ xuất hiện khi sự chuẩn bị kỹ lưỡng gặp được cơ hội. Chỉ khi nào bạn đã trả giá xứng đáng để có thể sẵn sàng cho thành công, bạn mới tận dụng được hết những cơ hội khi chúng tới.

Có vô số điều bạn có thể làm để có thể sẵn sàng cho thành công. Tất cả những hoạt động đó đều đòi hỏi thái độ tự giác và tin tưởng. Chúng cần sự tự giác vì thực tế là mọi người thường có thói quen làm việc mà không hề chuẩn bị. Thay vì dành thời gian và cố gắng chuẩn bị mọi thứ trong khi chờ cơ hội, họ chỉ rong chơi, nghe đài, xem ti vi và vội vàng thử sức khi có cơ hội vì tin rằng mình đã chuẩn bị rất tốt.


Ăn uống hợp lý

Đây cũng là một cách quan trọng để bạn chuẩn bị cho thành công. Bên cạnh những loại thức ăn giàu dinh dưỡng, mang lại nguồn năng lượng dồi dào, cũng có những loại thực phẩm bạn thường dùng chỉ vì thói quen mà không hề biết, chúng có hại cho hệ thống tiêu hóa. Những loại thức ăn này sẽ khiến bạn trì trệ và mỏi mệt vào buổi sáng hay buổi chiều.

Quá trình tiêu hóa là hoạt động cơ thể tiêu tốn nhiều năng lượng hơn cả. Do đó, khi ăn những loại thực phẩm khó tiêu, cơ thể bạn sẽ phải đẩy máu từ những khu vực khác tới cơ quan tiêu hóa để giúp chúng làm việc. Và như thế, việc tiêu hóa sẽ “ngốn” hết lượng máu đáng lẽ cần phải cung cấp dồi dào cho não và cơ bắp. Đây chính là lý do vì sao sau những bữa ăn quá “no nê”, bạn thường cảm thấy nặng nề, khó chịu.
Để giải quyết vấn đề này, hãy ăn những thực phẩm lành mạnh và nhẹ nhàng. Ăn nhiều rau và hoa quả, cộng thêm những loại ngũ cốc nguyên hạt.


Biết chuẩn bị

Trong mọi việc bạn làm, sự chuẩn bị là yếu tố mấu chốt. Nếu đã sẵn sàng để thành công, bạn phải gieo hạt thật tốt trước mùa vụ bạn mong được bội thu. Mọi thứ đều có 2 mặt của nó. Tất cả những việc bạn làm hoặc đưa bạn tới những mục tiêu đặt ra, hoặc sẽ đưa bạn đi chệch khỏi nó. Chúng có thể giúp bạn mà cũng có thể hại bạn.

Có chàng trai trẻ hỏi xin lời khuyên một doanh nhân thành công về việc làm thế nào anh có thể thành công nhanh hơn. Vị doanh nhân bảo, mấu chốt để thành công là anh ta phải giỏi công việc đang làm. Nghe nói thế, chàng trai bảo, “Nhưng tôi đã giỏi trong công việc của mình rồi”. Doanh nhân bèn nói, “Vậy thì hãy giỏi hơn nữa!”. Chàng trai trẻ, phần nào đó có vẻ tự đắc nói, “Vâng, tôi đã giỏi hơn hầu như tất cả mọi người rồi”. Lúc này, vị doanh nhân bèn nói tiếp, “Vậy thì anh hãy trở thành người giỏi nhất”.

Đó cũng chính là những lời khuyên tốt nhất bạn nên suy nghĩ: Hãy trở nên giỏi giang, giỏi hơn nữa và trở thành người giỏi nhất.

Bạn hãy nhớ rằng, chúng ta đang sống trong một xã hội tri thức, cứ sau chừng 7 năm, kiến thức trong bất cứ lĩnh vực nào cũng tăng thêm gần gấp đôi. Điều này cũng có nghĩa, cứ 7 năm trôi qua, bạn sẽ phải tự tích lũy thêm gấp đôi kiến thức trong lĩnh vực nghề nghiệp của mình nếu muốn tồn tại. Có thể bạn đã thực sự thành thạo với các kỹ năng và kiến thức tại thời điểm hiện tại. Có thể bạn đã đạt tới đỉnh ca o nghề nghiệp với những năng lực ở hiện tại. Nhưng nếu bạn muốn đi xa hơn và nhanh hơn, bạn hãy tiếp tục làm việc vàchuẩn bị cho mình trước những tầm cao mới. Hãy gạt bỏ những báo chí rườm rà, hãy tắt ti vi, hãy chối từ lịch sự với những cuộc tụ tập vô bổ để trở về với công việc cần thiết của mình.

Đỗ Dương
Theo Jlmandassociates

April 2, 2012

Không khóc là vĩ đại?


Người Nhật đang phải đương đầu với hệ lụy của một trận sóng thần và động đất lớn. Cũng như nhiều người khác, tôi thán phục cho sự bình tĩnh và kỉ luật của người Nhật trong cơn hoạn nạn. Có người nghĩ rằng người Nhật không biết khóc và cho rằng đó là sự vĩ đại. Tôi nghĩ khác …

“Hãy gạt tất cả nước mắt dưới mái hiên nhà, và sự chịu đựng sẽ là người bạn tốt của bạn”. Người ta cho rằng đó là câu châm ngôn của người Nhật. Người ta ca ngợi câu châm ngôn đó, như là một minh chứng cho tính vĩ đại của người Nhật. Người ta còn dùng nhiều từ ngữ có thể nói là xa xỉ để ca ngợi tính can trường của người Nhật. Nhưng tôi không nghĩ chỉ vì họ ức chế được cảm xúc (như không khóc, không biểu hiện cảm tính trước thảm nạn) là thái độ đáng ca ngợi, hay đáng để chúng ta học. Hoàn toàn không.

Đứng trên quan điểm y khoa, ức chế cảm xúc chắc chắn không phải là “người bạn tốt”.  Rất nhiều nghiên cứu y khoa cho thấy những người ức chế cảm xúc là những người có nhiều vấn đề về sức khỏe, kể cả nguy cơ mắc bệnh viêm kết tràng, nhức đầu, và những bệnh thuộc loại “psychosomatic” cao hơn những người hay khóc.  Về mặt tâm lí, người ức chế cảm xúc và không khóc cũng thường gặp trở ngại khi đối phó với các tình huống căng thẳng.  Những quan sát này cũng phù hợp với nhiều nghiên cứu cho thấy những phụ nữ số kiềm hãm cảm xúc có nguy cơ mắc bệnh tim mạch cao hơn những phụ nữ cùng tuổi nhưng sẵn sàng biểu lộ xúc cảm. Ngược lại, những người hay khóc thường có sức khỏe tốt. Nước mắt còn có thể là liều thuốc chữa những vết thương ngoại nữa.

Hơn 50 năm về trước, có người đã chứng minh sự liên quan giữa số lần khóc và tốc độ phục hồi cơn bệnh; người hay khóc có thời gian lành bệnh thường nhanh hơn người không hay khóc. Nói tóm lại, sự phiền muộn, vui mừng hay căng thẳng là một tín hiệu của cơ thể báo cho con người biết rằng "Hey, có vấn đề," và con người cần phải giải quyết vấn đề này.

Khóc là một trong những phương cách giải quyết vấn đề. Thật là kì diệu khi cơ thể con người có một bộ máy giải mã tự động như thế!  Con người là phải biết đau, đau về thể xác và đau về tinh thần.  Không biết đau là bất bình thường chứ không phải vĩ đại.  Thật vậy, trong y khoa cổ điển những người với hội chứng không biết đau (thậm chí đổ nước sôi họ vẫn không thấy đau) là những người hay chết sớm. Không biết đau tinh thần hay biết đau mà không thể hiện cũng là một điều bất bình thường.

 Khóc là một trong những đặc điểm làm cho con người khác với thú vật vốn không biết khóc. Cố nhiên, chúng ta phải phân biệt hai loại nước mắt là tôi tạm gọi là "trần lệ" và "cảm lệ."  Trần lệ là loại nước mắt tiết ra do sự khuấy nhiễu của bụi bặm hay các vi vật (tiếng Anh gọi là reflective tears).  Cảm lệ là loại nước mắt tiết ra do tác động bởi cảm tính (emotional tears).

Là con người, ai cũng có cảm xúc. Chúng ta khóc khi người thân trong gia đình qua đời, khi bạn chúng ta lâm nạn.  Khóc là thể hiện lòng thương cảm. Người khóc hoàn toàn không có nghĩa rằng người đó yếu đuối.  Khóc là hành vi bình thường, rất bình thường. Có khi bác sĩ sẵn sàng để cho bạn khóc, và dành không gian để bạn khóc.

Người Nhật rất đáng phục và ngưỡng mộ về tính kỉ luật và văn hóa của họ.  Nhưng khả năng ức chế cảm xúc của một số người trong lúc hoạn nạn không bao giờ làm cho họ vĩ đại.

 Nguyễn Văn Tuấn
 Link: http://nguyenvantuan.net/misc/9-misc/1223-khong-khoc-la-vi-dai

November 15, 2011

Tản mạn cuối tuần

Hôm tuần rồi TS Alan Phan có tổ chức một video conference với khách mời tự do mà mình tham dự hụt. May thay, đoán thế nào website của chú cũng đăng lại, còn kèm theo một bài viết mới toanh nữa. Nội dung xoay quanh tình hình kinh tế năm 2012, xu hướng đầu tư, kênh đầu tư nào là hiệu quả. Đọc bài chú viết thấy hơi bi quan, dù trong phần hỏi đáp không thấy thế. Tựu chung lại chứng khoán, ngân hàng, bất động sản có nhiều biến động và thay đổi. Ngành IT không có gì sáng sủa. Nhưng dù sao cũng có được những thông tin phân tích thú vị. Vấn đề là mỗi người sẽ xây dựng kế hoạch cho mình như thế nào cho năm tới thôi.

Mấy hôm nay khắp nơi nói chuyện bầu chọn Vịnh Hạ Long. Trên mặt báo truyền hình và các chương trình chính thống thì ra sức kêu gọi, vận động. Báo mạng, blog,...thì đưa nhiều cảm xúc trái ngược nhau.
Đưa ra những nhận định cảm tính thì nhiều, nhưng rất ít người đưa ra những con số, phân tích. Mình thấy ở đây có một vài số liệu. Tuy nhiên cách phân tích này lại hơi hướng chủ quan. Ví dụ nó cho rằng new7wonders chỉ là một tổ chức tư nhân và ông chủ tổ chức ấy là một tay "lừa đảo" (?). Tư nhân thì đâu ảnh hưởng gì vì Forbes cũng như thế. Còn nói ông này là tay "lừa đảo" thì chắc Interpol sẽ lo rồi. Ngược lại, bên nhà mình thì hô hào bầu chọn lại rất "phong trào" kiểu ngày xưa. Có nơi bằng cách này cách kia còn "ép buộc" người ta phải bầu chọn, trông rất phản cảm.

tuan chua bau ha long 1

Mình nghĩ hưởng ứng, bầu chọn là cơ hội tốt để quảng bá hình ảnh của đất nước. Nhưng nếu vẫn còn với kiểu tư duy phong trào "viết thư", "tìm hiểu",...rất hình thức như thời đi học trước kia (không rõ giờ còn không) thì chỉ có thể chơi với ao cá làng ta.

Có một tin vui là Đại học đầu tiên tại VN phát hành giáo trình e-book. Một thời học sách photo nhem nhuốc đã qua. Có thể nói kỉ nguyên sách số đã đến. Mình cũng ấn tượng với trang web Alezaa gần đây đã làm được một "quầy sách" online giá rẻ như thế. Dù không là mới, nhưng dần dần sẽ thay đổi suy nghĩ tư duy mua-đọc sách của người Việt mình. Cũng như sách, việc kinh doanh âm nhạc trực tuyến có thể cũng sẽ mở ra nếu các trang đi theo cách mà iTunes đã làm.

"Chúng tôi tin rằng 80% những người đi ăn cắp (nhạc) đều ở thế cực chẳng đã, chỉ vì chẳng có phương pháp nào thay thế hợp pháp cả. Ta hãy tạo một phương án thay thế hợp pháp cho nó, tất cả mọi người đều được lợi, các công ty nhạc đều được lợi, các nghệ sĩ được lợi, Apple được lợi. Và người sử dụng được lợi vì anh ta nhận được dịch vụ tốt hơn và không phải sắm vai một thằng ăn cắp nữa." - trích trong cuốn Steve Jobs của Walter Isaacson.



October 12, 2011

Designing C# Software With Interfaces

24 August 2011


The best way to understand how interfaces improve software design  is to see a familiar problem solved using interfaces. First, take a tightly-coupled system design without  interfaces, spot its deficiencies and then walk-through a solution of the problem with a design using interfaces.

As systems grow in size and complexity, software design must increasingly achieve the separation of concerns, adaptability for future changes and loose coupling. To do this, it is essential to design applications using interfaces. Interfaces are one of the most powerful concepts in modern object orientated languages such as C#, VB.NET or Java. Through the use of interfaces, developers can clearly define the relationship between different modules within a system. This allows a better definition of the boundaries of responsibility between different modules. The result of this is that individual modules are loosely coupled from each other, making the entire system more adaptable to change.

While most C# developers are familiar with the syntax and concept of interfaces, fewer have mastered their use sufficiently to design software around interfaces. Introductory texts on C# provide the basic syntax and a few simple examples, but do not have enough detail and depth to help the reader understand how powerful interfaces are, and where they should best be used. Books on design patterns catalog a vast array of patterns, many focused around interfaces, but often seem overwhelming to those developers who are making their first foray into software design. Consequently, too many developers reach a plateau in their abilities and their careers, and are unable to take the next steps into working with, and designing, more complex software systems.

I believe that many developers can benefit from learning to design with interfaces, and that the best way to learn about how to design with interfaces is to see an example of a practical, familiar problem solved using interfaces. First, I am going to show a system design without using interfaces and discuss some of the deficiencies that can result from this tightly coupled design. Then I am going to re-solve the problem with a design using interfaces, walking the reader through step by step of what decisions I am making and why I am making them. In understanding this solution, the reader will see how this is a more flexible, more adaptable design. Finally, it is hoped the reader will then be able to take these same techniques and apply them to other aspects of system design they may be dealing with.

The High Cost of Tightly Coupled Systems

Every university computer science student knows that hardcoding values in a program is bad design practice. By writing code with modules that are tightly coupled together, you are in just about as bad of shape. What do we mean by tightly coupled? Imagine we have two modules in our system, module A and module B. If module A depends on module B, then module A and B are said to be tightly coupled. If you make a change to module B, whether a change in a method signature, class layout or any other change, you are going to also have to change module A. Module A has significant knowledge of how module B works, so any changes on module B are going to cascade up to module A.
Module A and Module B
At this point you are saying, “Of course module A has to know about module B. My classes in module A need to use my classes in module B”. That is a fair statement, and there has to be some amount of coupling for a system work. Otherwise none of the modules or layers in a system could talk to any of the other modules or layers of the system. Where we run into trouble though is when we are tightly coupled to a module that can change. The following example will demonstrate this point.

Almost every application needs to perform some sort of application logging. Several high quality logging frameworks are freely available, including log4net from the Apache Foundation and Enterprise Library from Microsoft. In addition, many companies may have developed their own internal logging frameworks. Let us imagine for a moment that we have developed a typical n-tier system for managing widgets. As part of this system, we have separate projects for each of the major layers of the system—user interface, business logic, domain objects and data access. As part of our design, we have decided to use the log4net framework for logging. The diagram below shows the major components of this system and their dependencies (the arrow points in the direction of the dependency).
Dependencies diagram
We feel as we have done everything right in our design. We have separated out the layers of our system, put our business logic in a separate layer and separated out our data access. Yet, all of our modules in this system remain tightly coupled to each other. For the purposes of this example, we are going to focus on the logging module. Consider the following two scenarios:

  • A new CIO just started at our company, and he wants to standardize on Enterprise Library. All projects need to convert to using the logging framework in Enterprise Library within the next three months. In this case, we need to not just change out the reference to log4net with Enterprise Library, but we need to track down all of the logging statements in all of our code and replace them with their Enterprise Library equivalents.
  • Our widget application is wildly successful. Another team wants to integrate widget information into their Intranet web application. But this team uses their own, home grown logging framework. So using our widget libraries, we will either be writing log messages using two different frameworks (and hence multiple files) or we need to either convert our libraries to use their logging framework or adapt their application to use log4net.
In both of these cases, we are faced with unpalatable options. Instead of spending time adding features to our system that our business users want, we are ripping out one set of plumbing and replacing it with another. The fundamental problem here is that our system is tightly coupled to a specific logging implementation. Changing from one implementation (log4net) to another (Enterprise Library) represents a significant change to our code. The second example is even worse. Do we change our application to use the homegrown logging system of the other group, or do we try to convince them to use our chosen logging solution (log4net). Another alternative would be to maintain two sets of the widget libraries, one for each logging framework in use. This is clearly unsatisfactory though, because the two libraries will immediately start to grow apart. Finally, they could choose just to go and write their own widget library rather than use ours. But once again, our company is now maintaining two sets of source code to perform the same tasks.

What we are lacking here is any sort of interchangeability with regards to our logging system. By being tightly integrated to one solution to the problem (in this case, log4net), we have sacrificed any sort of flexibility to change to a different solution. If we want to proceed with this change, it comes at a very high cost—namely rewriting and recompiling significant portions of our system.

A Better Way – Designing with Interfaces

Our goal in the above system is to design an intermediate layer which will allow us to easily switch out logging subsystems for whatever is needed. In doing so, we also want to allow flexibility so that a new logging framework could easily be plugged in at a later date. All of this should be accomplished so that any changes to the logging sub-system do not require us to make any changes to our existing application code. Interfaces provide a simple yet elegant solution to precisely this problem.

First, an enum will be defined in our common logging library. The value of the enum will represent the different levels at which log messages can be written out. Log levels are used to filter what messages are actually written to the log in a log system. Generally, levels such as FATAL and ERROR will always be configured to be included in the log system. Levels such as INFO and VERBOSE are only included in development systems or when attempting to debug a problem. Our common interface will define the log levels shown below. The level FATAL is considered most important and VERBOSE the least important. Each message that is written to the log will be assigned one of these levels.
    ///

    /// Enum defining log levels to use in the common logging interface
    ///

    public enum LogLevel
    {
        FATAL = 0,
        ERROR = 1,
        WARN = 2,
        INFO = 3,
        VERBOSE =4
    }
The next step in our refactored design is create an interface that defines how any other code we write will talk to the logging sub-system.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesigningWithInterfaces.LoggingInterface
{

    ///

    /// Defines the common logging interface specification
    ///

    public interface ILogger
    {
        ///

        /// Writes a message to the log
        ///

        /// A String of the category to write to
        /// A LogLevel value of the level of this message
        /// A String of the message to write to the log
        void WriteMessage(string category, LogLevel level, string message);

    }
}
Of all of the code in this article, this interface is the most important. It defines how the rest of the modules in our application or any application are going to talk to the logging subsystem. Any piece of code that wants to put a message in a log will have to do it according the specification defined above. Furthermore, any backend logging system we want to plugin and use must adhere to this specification. The interface defined above is the bridge between the two subsystems. On one side you have the module that wants to write messages to a log. On the other is the concrete logging module (like log4net or Enterprise Library) that will perform the actual details of writing the message out . This interface serves as an agreement about how those two modules will communicate.

The problem we face now is that we have the interface we defined above, but none of our actual concrete logging systems implement the above interface. That is, there is no class in log4net, Enterprise Library or any other logging system out there that directly implements this interface. In fact, they all do logging a little bit differently. What is required is a class that will adapt our logging interface to an actual implementation of a logging framework. This class will fulfill our interface defined above and effectively translate those calls that are defined in our interface into method calls that work with the logging implementation that we have chosen. Such a class is shown below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DesigningWithInterfaces.LoggingInterface;
using log4net;

namespace DesigningWithInterfaces.Log4Net
{
    /// 


    /// Driver class to adapts calls from ILogger to work with a log4net backend
    /// 

    internal class Log4NetLogger : ILogger
    {

        public Log4NetLogger()
        {
            // Configures log4net by using log4net's XMLConfigurator class
            log4net.Config.XmlConfigurator.Configure();
        }

        ///


        /// Writes messages to the log4net backend.
        ///

        /// 
        /// This method is responsible for converting the WriteMessage call of
        /// the interface into something log4net can understand.  It does this
        /// by doing a switch/case on the log level and then calling the
        /// appropriate log method
        /// 
        ///  A string of the category to log to
        ///  A LogLevel value of the level of the log
        ///  A String of the message to write to the log
        public void WriteMessage(string category, LogLevel level, string message)
        {
            // Get the Log we are going to write this message to           
            ILog log = LogManager.GetLogger(category);

            switch (level)
            {
                case LogLevel.FATAL:
                    if (log.IsFatalEnabled) log.Fatal(message);
                    break;
                case LogLevel.ERROR:
                    if (log.IsErrorEnabled) log.Error(message);
                    break;
                case LogLevel.WARN:
                    if (log.IsWarnEnabled) log.Warn(message);
                    break;
                case LogLevel.INFO:
                    if (log.IsInfoEnabled) log.Info(message);
                    break;
                case LogLevel.VERBOSE:
                    if (log.IsDebugEnabled) log.Debug(message);
                    break;
            }
        }

The comments in the code above speak for themselves. The above class translates our common interface to something that log4net can understand. This is the way that we can write the rest of our system to work against our common interface, but yet still use a high quality, full featured logging system like log4net to take care of the actual work of writing our logging messages out to a file or a database or whatever we desire.

The real beauty though is that we can define multiple classes that implement the interface, in this case, each class serving as an adapter to a different logging backend. We can write a second class which implements the ILoggerinterface to support an Enterprise Library backend. All of the application code that uses logging is the same. It is programmed against our ILogger interface. To change which logging backend we use, we only have to substitute a different adapter class to be used by the system. Furthermore, if a new logging backend comes along at some point in the future, all we have to do to use it is to write a new adapter class that fulfills our interface and plug in to the new framework. This is a huge win because we can switch to something in the future we don’t even know about yet without rewriting our system. In fact, we can switch to a new framework without modifying any of our application or library code at all, just by writing one simple adapter class. Such a class is shown below.

    /// 


    /// Adapter class to use Enterprise Library logging with the common
    /// logging interface
    /// 

    internal class EnterpriseLibraryLogger : ILogger
    {

        public void  WriteMessage(string category, LogLevel level, string message)
        {
            // First thing we need to do is translate our generic log level enum value
            // into a priority for Enterprise Library.  Along the way, we will also
            // assign a TraceEventType value
            TraceEventType eventSeverity = TraceEventType.Information;
            int priority = -1;
            switch (level)
            {
                case LogLevel.FATAL:
                    eventSeverity = TraceEventType.Critical;
                    priority = 10;
                    break;
                case LogLevel.ERROR:
                    eventSeverity = TraceEventType.Error;
                    priority = 8;
                    break;
                case LogLevel.WARN:
                    eventSeverity = TraceEventType.Warning;
                    priority = 6;
                    break;
                case LogLevel.INFO:
                    eventSeverity = TraceEventType.Information;
                    priority = 4;
                    break;
                case LogLevel.VERBOSE:
                    eventSeverity = TraceEventType.Verbose;
                    priority = 2;
                    break;            
            }

            // This creates an object to specify the log entry and assigns
            // values to the appropriate properties
               LogEntry entry = new LogEntry();
            entry.Categories.Add(category);
            entry.Message = message;
            entry.Priority = priority;
            entry.Severity = eventSeverity;
           
            // This line actually writes the entry to the log(s)
            Logger.Write(entry);
        }
    }

The final problem that must solved is how to we select which one of our adapter classes to use. Somewhere in our code we need to locate the correct adapter and create an actual instance class of our adapter to talk to our backend logging framework. At first blush, one might think of writing a code snippet like the following:

        public static ILogger GetLogger()
        {
            string logger_key = ConfigurationManager.AppSettings["LoggerKey"];
            if (logger_key.Equals("log4net"))
            {
                return new Log4NetLogger();
            }
            else if (logger_key.Equals("EnterpriseLibrary"))
            {
                return new EnterpriseLibraryLogger();
            }
            else
            {
                throw ApplicationException("Unknown Logger");
            }           
        }

One major problem this code suffers from is that it needs to know about all of the available logging implementations up front, when we write this code. A second problem is that the ILogger interface, all of the adapter classes that implement ILogger and the above piece of code all tend to end up in a single project in order to avoid circular dependencies. Further, each adapter class will have a reference to its individual backend logging assemblies, which will all come along for the ride when we compile the above code. This heavyweight, tightly coupled project is exactly what we were trying to avoid in the first place. In this case, we have used an interface, but we really have not gained very much.

What we really desire is a solution that is truly decoupled and interchangeable, interchangeable to the point that at any time in the future we can substitute in a completely new adapter class and new logging backend. By utilizing the Reflection API in .NET, we can accomplish just that. The Reflection API allows us to dynamically instantiate an object of a class. That is, we can create an object of a class without calling new() on the class, but by providing the name of the class and assembly to the Reflection API. The following code shows how to do this.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Reflection;

namespace DesigningWithInterfaces.LoggingInterface
{

    /// 


    /// Factory class to get the appropriate ILogger based on what is specified in
    /// the App.Config file
    /// 

    public class LoggerFactory
    {

        #region Member Variables

        // reference to the ILogger object.  Get a reference the first time then keep it
        private static ILogger logger;

        // This variable is used as a lock for thread safety
       private static object lockObject = new object();

        #endregion


        public static ILogger GetLogger()
        {
            lock (lockObject)
            {
                if (logger == null)
                {
                    string asm_name =ConfigurationManager.AppSettings["Logger.AssemblyName"];
                    string class_name =ConfigurationManager.AppSettings["Logger.ClassName"];

                    if (String.IsNullOrEmpty(asm_name) ||String.IsNullOrEmpty(class_name))
                        throw new ApplicationException("Missing config data for Logger");

                    Assembly assembly = Assembly.LoadFrom(asm_name);
                    logger = assembly.CreateInstance(class_name) as ILogger;

                    if (logger == null)
                        throw new ApplicationException(
                            string.Format("Unable to instantiate ILogger class {0}/{1}",
                            asm_name, class_name));
                }
                return logger;
            }
        }
    }
}

This is a factory class. To get a reference to the appropriate ILogger object, we don’t call new() in our application code, we call the static method LoggerFactory.GetLogger(). The first time this method is called, it will look into the app.config file and get the assembly and class name of the adapter class for the logging system we want to use. It then uses the reflection API to load that assembly into the .NET Runtime and then get an instance of the class. It then keeps a reference to this ILogger object to use on subsequent calls to this method. Finally, all of this logic is wrapped in a lock statement to assure thread safety.

The last paragraph may seem complex, but when you boil it down, what is really happening is that we are creating the appropriate ILogger to use based on two entries in the app.config file. Now, we can change what logging system is being used by our application simply by changing entries in the config file. We do not have to make any code changes or recompile any code, simply to change the values in the config file. The .NET runtime still has to be able to locate and load the DLL with the adapter class in it (and in turn, locate and load the logging framework DLL’s you intend to use). But our system is truly decoupled now. Our application code is programmed against an interface such that any backend logging system can be used. If we want to support some new logging backend that hasn’t been invented yet, we simply have to write a new adapter class, compile it, copy the DLL to where our application can find it along with the new logging system DLL’s and change the config file. We have achieved true interchangeability within our system, so now different logging frameworks are merely plugins, and we can select whichever one suits our needs best.

Putting It All Together

Here is what the new design looks like in terms of a UML diagram:
UML Diagram
The classes Log4NetLogger and EnterpriseLibraryLogger both implement a common interface, ILogger. Log4NetLogger and EnterpriseLibraryLogger both serve as adapter classes, adapting the common logging interface we defined in ILogger to specific implementations for their respective backend logging frameworks. The class LoggerFactory is a factory class. It contains just one static method, GetLogger(), which will figure out the appropriate implementation of ILogger we are using, create the appropriate adapter class via reflection (Log4NetLogger or EnterpriseLibraryLogger) and return it to us.

From the perspective of any application, the application only knows about three types: the enum LogLevel since it defines the logging levels, LoggerFactory which is used to get a reference to ILogger and ILogger itself. Any code that uses logging has no knowledge of whether Log4Net, Enterprise Library or another system is being used. That is the purpose of this design. The application is programmed against an interface (in this case ILogger), but has no knowledge of what specific implementation (log4net or Enterprise Library) is being used. The design is now said to be loosely coupled.

Every design has tradeoffs, and this design is no exception. By programming to a common specification (the interface), we have gained the ability to easily switch out different logging frameworks without any impact to our application code. What we have given up though is the capability to use any advanced or unique features of an individual logging system. By programming to an interface, we can only make use of the features exposed by that interface, not any of the other capabilities that underlying implementation may possess. For example, Enterprise Library contains a number of additional features not in our logging interface:

  • The ability to specify a title as well as a message for each log entry
  • The ability to specify multiple categories for a log message, thereby potentially directing it to multiple destinations
  • The ability to define more granular levels through the use of the priority field in addition to the event severity
  • The ability to specify an Event ID value to further categorize event messages
Of course, I have purposely left the logging interface very generic and simplistic for the purposes of this article. But this list of sacrificed features still serves to illustrate an important point. To program to an interface, you will most likely give up access to any unique features and advanced capabilities that a particular implementation provides. In this case, if we merely want to perform general purpose logging, we can accept this tradeoff because our desire to achieve flexibility an interchangeability outweighs our need for the unique features above. However, if those unique features were determined to be essential requirements, we would be faced with two choices. First, we could forgo the use of an interface and program directly against our target implementation. If those features are that important to us, this may be an acceptable tradeoff. Second, we could refactor our interface to take additional parameters that could be passed on to our adapter class and ultimately our target framework. In this case though, every adapter class must be modified to fulfill the interface. For example, let’s say that having the ability to specify an event id was a required feature for our logging interface. We would have to modify ILogger to accept event id in itsWriteMessage() event, and both Log4NetLogger and EnterpriseLibraryLogger. Since log4net doesn’t have a concept of event id, we have to figure out something to do with the event id passed in. We could throw the value away, but more likely, we may add the value into the message in some formatted fashion. In this case, the tradeoff is additional complexity. To include a feature that is unique to Enterprise Library, we have to add some logic and therefore complexity to the Log4netLogger. Any system design will include such tradeoffs. What is important is to evaluate what is most important in each particular design and make the right tradeoffs for the system being implemented.

Design Patterns

The design above is what is known as the Bridge design pattern. This pattern is also sometimes known as the plugin pattern because each specific implementation can be easily “plugged in” to a program. The concept of the bridge pattern is that as long as an implementation fulfills the defined interface, implementations can be freely substituted for each other. Since the application is programmed against the interface, it is unaffected by switching to a new implementation.

The bridge pattern is very commonly used with regards to database drivers. ADO.NET, OLE DB and ODBC are all standard data access technologies for which Microsoft publishes a written specification. Other database vendors then take these specification and develop database drivers for their specific database management system. As long as those drivers adhere to the published specification, they can be easily used by any application without the application needing to know what specific database backend is used. An example of this is Microsoft Excel. Excel knows how to query data from ODBC. Excel doesn’t know if your backend database is SQL Server, Oracle, MySQL or even a text file. Excel just knows that it is talking to ODBC, and there is a driver that implements the ODBC specification. As long as you have an ODBC driver for your data source, Excel can get data from it. This is a classic example of the bridge pattern and the power of programming against an implementation rather than a specific interface.

The second design pattern present is the Adapter pattern. Both Log4NetLogger and EnterpriseLibraryLoggerserve are examples of the adapter pattern in action, effectively translating the ILogger interface methods into something that each backend logging framework can understand. Without the adapter classes in the middle,ILogger and the logging frameworks would be incompatible. With the adapter in the middle, the two are able to work together.

The third and final design pattern here is the factory pattern. The factory pattern is a design pattern that encapsulates the details of how to get an instance of an object within the factory. In this example, we do not want code in other modules to use new() to create a new ILogger instance. Doing so would defeat the whole purpose of putting using an interface in the first place, because then some code somewhere would still be bound to a specific implementation. Therefore, we have created the LoggerFactory class to act as a factory that handles the details of obtaining an instance of the correct object. In this case, these details involve looking in the app.config file for the name of the appropriate class and using the reflection API to obtain an instance. All of this code is encapsulated in the factory class, so other modules can, with ease, obtain a reference to the correct Logger object without knowing all of these details.

Design patterns have become a hot topic in the .NET community over the last few years, with literally hundreds of books, articles and screencasts to explain the details of all of the various patterns available. What is more important than being able to rattle off the intricacies of each and every pattern at the drop of a name is to understand the design concepts that are involved. The focus in software design should be on good design principles like clean separation of modules, separating the interface from implementation and decoupling different parts of the system. Design patterns offer established solutions to common problems in software development. However, you shouldn’t become a slave to patterns or force fit patterns into your design. Follow the principles above, and the places where a pattern can effectively help solve a problem will naturally emerge.

When Should You Design with Interfaces

The last step in learning how to successfully design with interfaces is being able to recognize when using an interface will result in a superior design. The following are some classic examples of when designing with and coding to an interface is appropriate and generally results in a better design.

  • Whenever a third party component or service is used. Unfortunately, libraries change, companies merge and acquire new products and stop supporting old ones. If you are able to distill out the important operations that a component or service performs into an interface, you are generally in a much better position if you use the design outlined above and call the component or service via an interface. This way, if you want to switch to a competitor’s product in the future, you have the flexibility to do so simply by writing a new adapter class. Secondly, if the component or service ever changes or is upgraded, it will now be much easier to test, because you are testing that the new implementation fulfills the interface. As long as the new implementation fulfills the interface, you can have high confidence the entire system will still work without having to test each and every feature in the system as a whole.
  • Another classic example is to hide your data access code behind an interface or series of interfaces. In some cases this is done so you can have vendor specific implementations of the data access layer—that is, one data access implementation for SQL Server, one for Oracle, one for DB2, etc. In this way, each data access implementation can utilize vendor specific features (example, identity columns in SQL Server, sequences in Oracle) but the rest of the application does not need to know about these details
  • Application settings can be loaded from different places, including the app.config file, a database, an XML file on a network share or the Windows registry. It would be very straightforward to abstract the operation of getting an application setting to an interface, and then provide a specific implementation to read the settings from each location. This technique could be useful if for example, today application settings are stored in the Windows registry for legacy reasons, but in the future, you are planning to transition these settings to a different location, like an XML file in the user’s application settings directory. Programming to an interface allows you to provide one implementation for legacy compatibility (the Windows registry) and a second implementation for your desired state (a custom XML file). The power of using an interface though is that when you make the switch, you simply have to update a configuration setting somewhere, rather than rewrite or even recompile code.
When designing with interfaces, there are some design guidelines you should follow. One of the most important is to keep your interfaces focused on the problem you are trying to solve. Interfaces that perform multiple unrelated tasks tend to be very difficult to implement in a class. A class may only want to implement part of the interface because that is all that is needed, but is required to implement the entire interface. An interface should clearly and concisely communicate what purpose it serves and what functionality it provides. This makes it clear to implementers what is expected and clear to users of the interface what functions the module can perform. When an interface starts trying to perform too many tasks, it is too easy for the original purpose of the interface to become lost, defeating much of the value of having an interface in the first place.

A second guideline is to make sure the interface does not contain too many methods. Too many methods makes implementing the interface difficult as the implementing class has to provide for each and every method in the interface. At best, this is tedious. At worst, the implementer may be tempted to “stub out” methods that they don’t consider important by providing an empty or underdeveloped implementation. In this case, while the class provides a method for each method in the interface, it does not truly fulfill the interface. This becomes a problem if you have application code expecting certain functionality of an interface since a method is provided, but the implementation is but a stub. By keeping the number of methods in an interface reasonable and keeping those methods focused on the functionality that the interface is supposed to provide, it is much more likely the interface will be used and correctly implemented.

A third guideline to remember is to not allow implementation specific functionality creep up into the interface. Too often, when a development team has an existing module from which they are trying to extract an interface, they will include functionality in the interface that is very specific to the current implementation that exists. This becomes a problem when you want to write a different class that implements the interface. This then limits the usefulness of the interface, because the interface itself is really tied to a specific implementation, which is not the point. An interface should define the common functionality that the module or subsystem will perform. Any implementation specific logic must be contained inside of an implementing class, not exposed as a method on the interface itself. The interface is a definition of what functionality the module provides, not a constraint on how an implementing class must provide that functionality.

A fourth and final guideline is to keep in mind is that while some level of abstraction is positive, too many levels of abstraction lead to code that is over-complex and difficult to maintain. In this article, I have focused on the use of interfaces to provide a level of abstraction between different subsystems of an overall application. In this case, providing a level of abstraction between the logging system and the application code has a clear purpose and helps to provide a level of separation between the logging component and the rest of the application. Including additional levels of abstraction through would probably only serve to make the design more difficult to understand. Using an interface should help more clearly define what the role of a module or unit of code is, and therefore lead to a design that is clearer to understand, not more complex. When in doubt, ask a colleague to review the design and explain it back to you. If the design is correct, they should be able to provide an explanation of the purpose of each interface in the system. If they struggle to understand the purpose of a particular interface, you may want to rethink what you were trying to accomplish with that interface in the first place and whether the code reflects your intentions.

Conclusion

Designing with interfaces will result in cleaner separation of responsibilities between different subsystems within an application. By programming to an interface, applications become much more flexible because different subsystems can be easily switched out if the need arises. Furthermore, if a subsystem does have to be switched out, the burden of testing is reduced, because now you can focus most of your testing efforts on insuring that the new implementation properly fulfills the interface rather than testing the entire system as a whole.

This article covered an example of how interface design could be applied to the problem of application logging frameworks. I hope that, by understanding the example given in this article, more developers will come to recognize the power and flexibility that interfaces bring and will start using interfaces to design more flexible software systems.