Thursday, December 06, 2007

TeamCity 3.0 is released with a FREE version

These days continuous integration (CI) becomes popular in software development 'cause it aims to support software developers to produce higher quality products. To apply CI in your project, usually, you need to use a CI server. There are many CI severs you can found: CruiseControl, Hudson, Luntbuild, Parabuild,... and most of them are free.

If you've ever heard about IntelliJ IDEA - the most intelligent Java IDE - is from JetBrains, you should know that they also have a CI server which has many innovative features, TeamCity. And today, JetBrains releases TeamCity 3.0, especially there is a free version.

For more information about TeamCity 3.0, you can find here:

Try it out and have fun :-)

Saturday, December 01, 2007

The weekly bag - Dec 1

What will the new features in Diana?

With Diana (a.k.a. IntelliJ IDEA 8) will appear in Q4 2008, it's time to think about the new features. As my experience with JetBrains and IntelliJ IDEA, I don't think they will provide support for other frameworks but they will have more support for team work. Even IDEA can do some tasks for team work in conjunction with Team City and IDETalk, but they're not too many. So here the main feature list I think they will provide in Diana:

  • A Task-Focused user interface, like Eclipse's Mylyn and even better

  • Improvement in supporting Spring, Hibernate, Seam, Facelet, Flex

  • Improvement in integration between Hibernate and Spring

  • Improvement in Ruby and JetGroovy plugin

Even I want to see UML support in IDEA (support for popular diagrams, generate source code from UML, reverse engineering from source code, synchronize between diagrams and source code,...) but I don't think it will appear in Diana.

OK, now wait and see, in a few weeks later, they will post the road map for Diana.

Update: Added Facetlet, Flex

Tuesday, November 27, 2007

How to restore a tab which has just closed in Firefox?

Just closed a Firefox's tab unfortunately? There is a solution for it, you can use Ctrl + Shift + T to restore the tab.

And even more suprise, if your text box contains text, it will not be lost :-)

Monday, November 19, 2007

How to call EasyMock.verify() when you expect an exception in TestNG

I have this test which is written in JUnit
public void testConvertWithUnknownCurrency()
throws UnknownCurrencyException {
).andThrow(new UnknownCurrencyException());


try {
converter.convert(10.0, "EUR", "-UNKNOWN-");
fail("an unknown currency exception was expected");
} catch (UnknownCurrencyException e) {
// do nothing, was expected


I converted it to use TestNG as below
@Test(expectedExceptions = {UnknownCurrencyException.class})
public void testConvertWithUnknownCurrency() {
).andThrow(new UnknownCurrencyException());


converter.convert(10.0, "EUR", "-UNKNOWN-");


then found that EasyMock.verify(exchangeRateService) will never be called 'cause converter.convert(10.0, "EUR", "-UNKNOWN-") throws UnknownCurrencyException. So how to make the test works as same as JUnit version?

Spend more time to read TestNG document and search in TestNG forum, I found that I can use @Test's dependsOnMethods attribute. But note that TestNG supports 2 kinds of dependencies: hard and soft. And here is explaination from TestNG document:

* Hard dependencies. All the methods you depend on must have run and succeeded for you to run. If at least one failure occurred in your dependencies, you will not be invoked and marked as a SKIP in the report.
* Soft dependencies. You will always be run after the methods you depend on, even if some of them have failed. This is useful when you just want to make sure that your test methods are run in a certain order but their success doesn't really depend on the success of others. A soft dependency is obtained by adding "alwaysRun=true" in your @Test annotation.

Now I have a clear understanding about dependsOnMethods, what I need is a soft dependency. And here is TestNG version of above test.
@Test(expectedExceptions = {UnknownCurrencyException.class})
public void testConvertWithUnknownCurrency() {
).andThrow(new UnknownCurrencyException());


converter.convert(10.0, "EUR", "-UNKNOWN-");

@Test(alwaysRun = true,
dependsOnMethods = "testConvertWithUnknownCurrency")
public void verifyAfterTestConvertWithUnknownCurrency() {

The test works as expected. Smile :-)

Updated: Re-think about my TestNG test version, I will remove alwaysRun = true from verifyAfterTestConvertWithUnknownCurrency(). Why? 'Cause if testConvertWithUnknownCurrency() fails, it means the test fail, don't need to waste my time to verify something it was failed.

One reason to use dependent methods 'cause it makes the test clearly. I know exactly where the test fails, 'cause it doesn't throw exception or 'cause EasyMock.verify() fails.

Sunday, November 18, 2007

Thursday, November 15, 2007

Custom or Standard?

Modern languages like Java, C#,... provide powerful APIs with many libraries which are ready to use. But sometimes I consider I should use the "standard" class or create my own custom class. Spending more time to think about it, I realize that it depends.

Assumes that I want to have a list of members, if I use Java, I can use List<Member> or create my own MemberList to store all members. If I want to have more features than the standard List<Member> provides, of course, I need to create my own MemberList, which bases on List<Member>. But what will I do if I only need a read-only list? A List<Member> cannot do it. To have a read-only list, I need to use Collections.unmodifiableList(myMemberList) or create MemberList which supports read-only only.

Now consider that I only need to use the read-only list inside my application, which solution can I choose? One of two but maybe one of three. I also can use List<Member> and forget about its "edit" methods.

To have a clearer design, using MemberList will be the best solution but it needs time to implement. To be lazy, using Collections.unmodifiableList(myMemberList) or List<Member> without using its "edit" methods is an acceptable answer.

Wednesday, November 14, 2007

The rest books

Today, I received the last 2 books for my order from Amazon. They came earlier than the estimation 3 days :-)

Too many books to read, too much works to do :-)

Tuesday, November 13, 2007

Monday, November 12, 2007

The first delivery

Even though I chose to pack all items in one package but Amazon delivered my order in 2 separate ones. And I've just received the first package, it contains 3 books

Amazon estimated my first package will be delivered from Nov 12 to Nov 20. And today, I received it. Their service works exactly :-)

The second one will be here from Nov 17 to Nov 30. Then I will spend more time for reading about testing.

FYI: Spring 2.5 supports to test by TestNG (and JUnit 4)

Sunday, November 11, 2007

The weekly bag - Nov. 11

Monday, November 05, 2007

Monday, October 29, 2007

Friday, October 26, 2007

No Java 6 in Leopard - I quit

In the past, I thought I would buy a Mac Book Pro to replace my old 3 years Dell Inspiron. That time I heard "MacOS is a comprehensive Java development environment". Also in the point of view of an end user, GUI in MacOS it's more beautiful than the one in Linux and it has many more popular (and better) applications than Linux (You must know that when I used Ubuntu, even I could listen to the music, Skype's voice feature stopped to work without any errors)

But now there is no Java 6 in Leopard (MacOS X 10.5), so I quit. I think you too if you're a Java developer.

Thursday, October 25, 2007

Stubs, Fakes, and Mocks

Funny descriptions about stubs, fakes and mocks, they help me easily to distinguish stubs, fakes and mocks.

Stubs - Looks like a duck but it's not a duck
Fakes - Looks like a duck, walks like a duck but it's not a real duck
Mocks - It's a mechanical duck

TestNG's @DataProvider versus JUnit 4's Parameterized

In "Test Driven - Practical TDD and Acceptance TDD for Java Developers", Koskela used JUnit 4 as unit testing framework but I want to use TestNG so I need to "translate" from JUnit 4 to TestNG. I think it's a good opportunity to know about both of these unit testing frameworks.

In chapter 4, Koskela described about test patterns and one of them is Parameterized Test. To apply this pattern, we need to follow the rule to write the test class as below:

+ The test class must be annotated by @RunWith(Parameterized.class),
+ Supply a static method, is annotated by @Parameters and returns a Collection<Object[]> or its subclass,
+ And we need to write a constructor which has parameters for expected value and input values.

public class ParameterizedTest {
// Provide parameterized data
public static Collection<Object[]> parameters() {
Object[][] data = new Object[][] {
{ 0, 0, 0 }, { 1, 1, 0 },
{ 2, 1, 1 }, { 3, 2, 1 },
{ 4, 3, 1 }, { 5, 5, 0 },
{ 6, 8, -2 } };
return Arrays.asList(data);

public int expected, input1, input2;

// Data is bound through constructor
public ParameterizedTest(int expected, int input1,
int input2) {
this.expected = expected;
this.input1 = input1;
this.input2 = input2;

//Test method invoked once for each data set
public void executeParameterizedTest() throws Exception {
assertEquals(expected, new Calculator().add(input1,

It looks very complicated, huh? Now, I will "convert" it to TestNG.

After awhile, I found that TestNG's @DataProvider can do the same thing. And here is the rule to write test class with TestNG following Parameterized Test pattern:

+ Supply a method (don't need to be static) is annotated by @DataProvider(name = "dataProviderName") and returns Object[][],
+ Test method is annotated by @Test(dataProvider = "dataProviderName") and has parameters as same as the Object[]'s elements in data is supplied from data provider

The above source code after was "converted":
public class ParameterizedTest {
@DataProvider(name = "data")
public Object[][] parameters() {
return new Object[][] {
{ 0, 0, 0 }, { 1, 1, 0 },
{ 2, 1, 1 }, { 3, 2, 1 },
{ 4, 3, 1 }, { 5, 5, 0 },
{ 6, 8, -2 } };

@Test(dataProvider = "data")
public void executeParameterizedTest(int expected,
int input1,
int input2)
throws Exception {
assert (expected == new Calculator().add(input1,

The test class is written with TestNG is much simpler also you can have many data providers as you want. And what will happen if you want to test the Calculator for substraction? If you use JUnit 4 as unit testing framework, seems you need to write another test class.

Wednesday, October 24, 2007

TDD - The hardest thing

These days I spend my spare time to read "Test Driven - Practical TDD and Acceptance TDD for Java Developers". I've just finished chapter 2 and started to bump in chapter 3 but I found out that "Test Driven" is an interesting book (more interesting than "Agile Java: Crafting Code with Test-Driven Development")

In chapter 2 and 3, the author teaches me how to start TDD (test-driven development) with a template parser step by step. IMO, the hardest thing when we start TDD is find out the tests from the requirements or user stories. In simple application, it's easy to find them out. But in more complicated one, it's very hard to find.

In template parser application, I can easy to find out some tests:

+ Test for empty template
+ Test for replacing a variable in the template with its value
+ Test for replacing multiple variables with their values respectively

but in case of an employee management application, how can I find the tests? This question is not easy to answer.

Update: Fix typo

Wednesday, October 17, 2007

Tip: How to get an IntelliJ IDEA license for free

A few minutes ago I received an email from JetBrains, and do you know what did it say? It said "Hey guy, it's an IntelliJ IDEA license, it's for you, and it's FREE", just kidding :-) Here is a part of email from JetBrains


We appreciate your participation in development of IntelliJ IDEA 7.0, and we hope you will continue using IntelliJ IDEA with even more pleasure with the attached below personal license.

Be prepared to receive another gift from JetBrains this week :-)

-The JetBrains Team-

I greatly appreciate JetBrains' kindness when they give me this present, a 249$ present. But more than the cost, actually they give me a FREE super weapon to work with, to play with and to have fun with.

And now it's the tip: Please download, use and report the bugs you would found in EAP versions of IntelliJ IDEA, you will have a chance to get an IntelliJ IDEA license for free.

Again, thanks JetBrains. Now it's the time to develop with "FREE" pleasure ;-)

Update: After reading the email more carefully, I found that JetBrains will have another gift for me this week. Waiting for another big surprise... :-)

Update: JetBrains gave me a big surprise one more time, I've just received an Gift Certificate. Again, I want to say thanks to JetBrains, you gave me surprise time after time :-)

Tuesday, October 16, 2007

IntelliJ IDEA 7.0 reaches to final

Early this morning JetBrains released IntelliJ IDEA 7.0. This new version provides many new and interesting features and also it supplies many improvement (include performance) to support the developers to develop the software with pleasure. You can find the complete list of new features here. And the news about it also was published on several sites: here, here and here.

IMO, these features are the ones I love:

+ Support for Spring
+ Support for Hibernate
+ Integration between Spring and Hibernate
+ Improvement in Change View
+ Support for Groovy

Congratulations, JetBrains! It's the time to develop with more pleasure :-)

Monday, October 15, 2007

Dilbert & IntelliJ

Check it out. It's really funny :-)

(Thanks Alex for providing it)

Saturday, August 18, 2007

Vì sao bạn bị mất việc?

Nhân đọc bài báo "Vì sao bạn bị mất việc?” và cũng là tranh thủ trước khi qua nhà bạn chơi, tôi thử tự đặt mình vào hoàn cảnh mà nhà tuyển dụng hỏi tôi câu hỏi đó. Tôi sẽ trả lời như sau (tất nhiên đây là câu trả lời trung thực):

"Trước tiên tôi có thể khẳng định với ngài rằng, tôi không bị mất việc. Tôi nghỉ việc ở công ty đó. Và nếu câu hỏi được chuyển thành "Vì sao bạn nghỉ việc?" thì tôi có thể trả lời ngài thế này. Tôi nghỉ việc ở công ty đó vì tôi muốn tự tìm kiếm cho mình một môi trường làm việc tốt hơn, năng động hơn, cạnh tranh hơn, phù hợp với nhu cầu, khả năng cũng như mong muốn tiếp thu những kiến thức và kinh nghiệm mới cho bản thân."

Bạn nghĩ thế nào về câu trả lời như vậy? Và nếu bạn ở trong trường hợp đó, bạn có trả lời như tôi không?

Sunday, July 08, 2007

FYI - First stable version of JetGroovy

JetBrains released first stable of JetGroovy in silence. It's a good plugin for Goorvy. Also many thanks to JetBrains for nice contribution to Groovy.

You can get first stable version of JetGroovy here.

Thanks Graeme for this information.

Update: JetBrains has just updated JetGroovy. You can get the latest version at above link. But note that it requires Selena build 7038 or later. And they also blog about it. JetGroovy looks very nice :-)

One more information, seems IntelliJ IDEA 7.0 will be delayed to early 2008.

Update: JetGroovy 0.1 now is available on IntelliJ IDEA's plugin repository server and you can install it via Plugin Manager.

Thursday, June 28, 2007

Came back from Kuk Ki Won

I'm tired now, yes, very tired. But I had a lot of fun, yes, a lot. KOIVA organized an workshop for foreign high-tech professionals at Kuk Ki Won and I attended it.

I played Taekwondo, it's the first time. I enjoyed it very much although my actions are very basic. I met Martin - an Irish guy, Dung - a Vietnamese guy I knew before, Tien - a Vietnamese girl she live in Hochiminh City and has worked here for 3 years, and many people. I listened a Chinese girl sang "Big big girl" (actually she's a small girl, not big ;-). I watched a Yoga show which was performed by an Indian Yoga instructor and he made me say "WOW" and clapped many times. I took some pictures (I will post them later if possible). I had a new Romanson watch. And over of all I had a lot of fun :-)

The workshop was very interesting and I will attend it next time (this workshop is organized every year)

Work hard and play much when you can. Enjoy your life!

Monday, June 25, 2007

Are there any places to use contructors of an abstract class with public or default access modifier?

As we already knew, we cannot create instances of an abstract class. So there are only 2 places to access constructors of an abstract class:

+ From the internal of that class (we can use private access modifier for this situation, it's enough), and
+ From its subclasses (we can use protected access modifier for this situation and it also satisfies the above situation)

And for other reasons, if we need to use instances of an abstract class, we will provide factory method(s) to create them (actually, at this time, we will return an instance of a "DEFAULT" subclass). So I don't see any reasons to declare constructors of an abstract class with public or default access modifiers.

Can you give me the reasons why I "need" to do it? Thank you.

Sunday, June 24, 2007

Sorry Firefox, you don't understand "polymorphism"

While I was typing for my previous post, I found that Firefox displayed a red-dot-underline line under "polymorphism". It means Firefox doesn't recognize "polymorphism" as a valid word in English. Or it means Firefox doesn't understand "polymorphism".

Hey Firefox, you should learn more. And please start from here.

Interface - Where and When?

I understand that if I use interface, my application can a high flexible construction. I can easily extend class to add more function, and also make use of strong point of polymorphism and dynamic binding. But I'm wondering that where and when I should use interface.

At this time I'm developing a small application it contains a Tourist class and I can't imagine that when I need to create some more specific kinds of Tourist. Even I need to extend Tourist, I can re-factor Tourist to be a abstract class (or keep it unchanged) and then create subclasses of Tourist. Where is the place I need to consider to use interface here?

As I told you, I'm developing a small application and I know it still keep in small level, hardly to become bigger. So what is the matter I need to use interface here? That is WHEN question.

What do you think about the WHERE and WHEN?

Saturday, June 23, 2007

Lack of something

I spent a little of time to think about my work, my knowledge and my experience. And I found that I'm lack of knowledge, MUCH.

I'm a techno guy. I love new technologies, really love. And I always try to catch the trend of new technologies by collecting every little amount of information about them. I cannot remember how many times I said "WOW" when I found something interesting. But when I knew about it (a little, again, sadly) I threw it away to catch a new one.

Till now, about 6 years from the time I graduated university. I knew Spring, I knew Hibernate, I knew JSF, Struts, Wicket... and many things but I'd just knew, NOT UNDERSTAND. Even I can use them but I don't know how they works, how they make this or that interesting.

Of course, you cannot UNDERSTAND everything, but you should understand SOMETHING, something that can make you love, are interested in, something can make you fun and of course, it can help you to earn money. And here is my list, something I want to understand:

+ Algorithms
+ OOP (and how to apply it CORRECTLY)
+ Design Patterns
+ Software Development Process (I choose ICONIX to start)
+ Swing
+ Servlet
+ Spring
+ Hibernate
+ Struts
+ Wicket
(the list will be continued...)

Thursday, June 21, 2007

JetGroovy - Groovy plugin for IntelliJ IDEA

Michal already figured out how to build JetGroovy from source. (Thanks Michal!) But if you're lazy, you can get JetGroovy here.

Installation: Download and extract it to IDEA_HOME/plugins, then start IDEA to fight ;-)

Note: This JetGroovy build ONLY works with IDEA 7 EAP build 7020. I'm not sure that it will work with other EAP builds (and of course it doesn't work with IDEA 6 or earlier)

If you have problem in downloading, please replace "us.share" in "" by "www". Sorry for inconvenience. (Yahoo suck!)

Update: I've just updated to IDEA build 7027 and JetGroovy doesn't work anymore. IDEA hangs while loading JetGroovy and there is no exception in log file.

Monday, May 14, 2007

Keep your wallet tight

Last weekend, after came back company from camp with my colleagues, I suddenly found that I lost my wallet. I asked my colleagues to help me to contact the driver who drived the car we used to go 'cause I think I dropped it on the car. A few hours later, I had the answer that he could not found it. This afternoon he contacted us and informed that he found the wallet(!). And now I have it here. "Thanks the driver!"

But I still lost 20.000 wons and 5 dollars while I'm sure that my wallet contains at least 40.000 wons and 5 dollars. Luckily, I moved all money from my check card to another bank account. I don't want to imagine what will happen then if somebody will use it and I will loose all money. And actually, I have something more than the money inside the wallet.

Loosing 20.000 wons (about 20 dollars) and 5 dollars is very cheap. A lesson I should keep in my mind: Keep my wallet tight.

Wednesday, May 02, 2007

Cái chết

Vừa rồi Tr thông báo anh N mới mất. Bần thần cả người. Mới vừa hôm nọ anh em còn nhậu...

Cuộc sống chẳng thể lường trước điều gì sẽ xảy ra. Hôm nay còn mà mai đã thành cát bụi. Nhìn lại bản thân thấy mình chưa làm được gì, cũng chẳng có gì. Buồn thật. Để rồi đến lúc mình thành cát bụi, phỏng mình có chi đây?

Xin chia buồn với gia đình anh N :-(

Friday, April 06, 2007

Something I hate in Netbeans

Everybody usually complains about missing this feature or that feature in Netbeans, but not me. I only work in "tic toe" programs so Spring, Hibernate, blah blah... they're not my concern.

+ Loading at startup is more slow: These days Netbeans 6 needs to spend more time to load. I only installed Ruby and Maven plugins but 45 seconds for loading is not acceptable (JDK, libraries and project are already cached, my laptop is 1.66Ghz and has 1GB RAM).

+ Expanding node is very very slow: When I expand Source Packages node in Project pane, it takes 3-4 seconds to display all packages. God, I only have 6 packages and only 2 of them contain over 20 classes.

+ Expanding code templates uses inappropriate shortcut key: Netbeans 5.x uses Space by default and Netbeans 6 uses Tab. I think it is stupid 'cause if I enter "psvn" then delete "n" and enter "m", at that time press Space/Tab and expanding doesn't work. ("psvm" + expand code template shortcut key should generate main()). But Netbeans supports to change shortcut key for expanding code template and I need to change to Shift + Space.

+ Popup intellisense list is slow too: If you press Ctrl + Shift + Space inside the editor, Netbeans will show a "Please wait..." list and you need to wait a little before the intellisense list appears. While in IntelliJ IDEA, the intellisense list appears immediately. This problem also happens even you entered some characters and the intellisense list is very short (only a few elements).

+ Missing inspections: Using Netbeans, I really miss the inspections in IntelliJ IDEA. AFAIK, at this time Netbeans 6 only has inspection to generate javadoc and remove unused import.

+ Templates are stored in Netbeans folder: If I uninstall Netbeans, I will lost my templates. It should be kept in user's folder.

+ Doesn't show error description in status bar: Netbeans can parse the source code and highlight the errors but I cannot see error description until I move the mouse over the error indicator.

Update: If I enter "nout" then move the cursor back, delete "n", add "s", move the cursor to the end of "sout" and press Shift + Space (I configured to use Shift + Space to expand code template), expanding code template doesn't work too.

Generating javadoc comment should generate closed comment: When I enter "/**" and press Enter, Netbeans should generate "*/" for me.

Update: Do not force me to use quick search: When I want to generate a constructor with several fields, I press Space to select a field then Netbeans display quick seach text box so I need to press Esc to hide that text box.

Formatting for switch statement is not correct: When I enter "case 1:" then press Enter (or Ctrl + Shift + F to format code), Netbeans does auto un-indent "case 1:" so it has same indent level with "switch (n)"

Update: Should detect JDK home automatically: You can see description here: And if they bundle up the JDK, Netbeans will have same size with IntelliJ IDEA.

Note: All the problems here I met in Netbeans 6 (latest test daily build)

Coming home

Left Vietnam about 2 years ago, now it is the time I need to come back. Even I will only come back Vietnam in a few weeks but I think it's a good time to see what is happening in my country. These days I heard that there are many investors they're investing in Vietnam, I heard about stock market,... Vietnam is changing.

But more important, I want to spend my time with my family. I want to meet my friends. I want to ride my motorbike and graze on the roads. And if possible, I will spend my time to go across my country. Also I want to have time to live and think for myself.

I'm really enthusiastic for coming back Vietnam. I will meet you, Vietnam, tomorrow.

Monday, February 26, 2007

Came back from Taiwan

Yesterday night, I came back Seoul from Taiwan. After a hard working year, I had an interesting vacation for Lunar New Year.

People who know about Taiwan knew that it named "Formosa", means "a beautiful island". Actually Taiwan is nice island, there are a lot of trees and the air is very fresh.

In Taiwan, I went to Allishan, a mountain in the middle of Taiwan, it's a popular visited area. I visited Taipei Zoo, the largest animal zoo in the world. I visited Chiang Kai-shek Memorial Hall. I went around Quanghoa computer market. I went out with my friends and had some parties...

Taipei is a little more modern than Hanoi (my home town) but in Taoyuan where I stayed it looks like Hanoi but without animation and traffic jam. I really like it. The weather is good, it's not too cold like Seoul these days, sometimes it has rain but not heavy.

Taiwanese government still accepts people can play craker while this one does not accept in Vietnam about 10 years. When hearing cracker, sometimes I remember about my childhood and my home...

Some tips for you if you have plan to visit Taiwan:

+ Do not try to bring fruit to Taiwan, it does not accept
+ Have a friend who can speak Chinese or a map (it's hard to find a person who understands English when you lost the way)
+ Prepare enough coins to go by bus (you cannot get returned money from drivers, actually they cannot return you even they want to do it)
+ When go by bus inside the city, keep your ticket and return it to driver when you take out. Otherwise, you need to pay money for ticket one more time.

Sun's rising on Allishan

Allishan's jungle

Chiang Kai-shek Memorial Hall

Thursday, February 15, 2007

How can I remove value "2"?

In Groovy, you can remove an object from a list by using remove(int index) or remove(object obj). But if I have a list of ints, how can I remove an object by "value" rather than the index?

def list = [2, 1, 3]

assert list == [1, 3] // throws AssertionError, 'cause list = [2, 1]

Sunday, January 28, 2007

Sự phá sản của một ý tưởng

Cách đây vài tháng tôi đã có một ý tưởng về việc phát triển một hệ thống gọi là SSRSS (Synchronized System for RSS). Hệ thống này nhằm cung cấp một server cho phép người dùng sử dụng đồng thời nhiều máy tính có thể đồng bộ hóa newsfeed của họ một cách dễ dàng. Ví dụ, tôi có 2 máy tính, một ở nhà và một ở công ty. Tôi có thể sử dụng 2 feed reader khác nhau ở 2 máy nhưng đều được đăng ký các feed như nhau. Chẳng hạn tôi đã đọc tin A ở công ty, nó đã được đánh dấu đã đọc. Nhưng khi về nhà, feed reader ở máy tính tại nhà lại không thể biết rằng tôi đã đọc tin A và nó hiển thị tin A như là một tin mới. Việc đồng bộ hóa sẽ cho phép tôi khi về nhà, bật feed reader lên và tin A sẽ được đánh dấu đã đọc.

Để có thể giải quyết được vấn đề này, điều quan trọng nhất, theo tôi, đó là làm thế nào để blog server biết được rằng người dùng đã đọc tin. Khi đó server có thể đánh dấu các tin (đã được cache). Nhưng điều này chỉ có thể thực hiện được nếu feed reader implement API riêng biệt nào đó có nhiệm vụ tương tác với blog server (điều mà trước đây tôi đã ảo tưởng có cách vượt qua), giải pháp này đã được Bloglines sử dụng. Nhìn vào đó chắc hẳn các bạn đã thấy được hạn chế của nó: Nếu feed reader không sử dụng API của tôi nghĩa là không thể synchronize (thông qua server của tôi).

Cũng có một giải pháp khác, đó là feed reader hỗ trợ cache. Nghĩa là feed reader sẽ lưu trữ thông tin về các tin và upload lên một server mà các máy tính của người dùng có thể truy cập đến. Dựa trên các thông tin này, feed reader sẽ đồng bộ hóa các tin để xác định nó được đọc hay chưa. Giải pháp này đã được một số feed reader sử dụng (ví dụ RssBandit).

Trong khi đó thị trường feed reader, theo tôi, đã bão hòa với quá nhiều sản phẩm có các tính năng hấp dẫn. Việc tôi phát triển một feed reader để phục vụ cho SSRSS là hoàn toàn không thực tế.

Chính vì các lý do trên, tôi quyết định dừng việc phát triển SSRSS. Hy vọng rằng trong tương lai gần tôi sẽ có một ý tưởng mới hay ho, hấp dẫn và thực tế hơn.

Groovy syntax file for EmEditor

Yesterday, while waiting for the football match between Manchester United and Portsmouth in round 4 of FA Cup, I created a Groovy syntax file for EmEditor. This syntax file can help to highlight Groovy's keywords, class name in Groovy library and functions name.

You can get it here then import it into EmEditor.

Cheers to develop with Groovy!

Friday, January 26, 2007 is back

Hey blog buddies,

Now you can visit my blog via And of course via if you want.



Wednesday, January 10, 2007

2 questions for iBATIS developers

I've just started to play with iBATIS in Action and I have 2 questions for iBATIS developers about configuration files.

- Why doesn't have <property> inside of <properties>?
My concern: Sometimes user wants to keep these properties inside of SqlMapConfig.xml rather than outside

- Why doesn't have 'file' or 'resource' attribute in <select>, <update>, <delete>,... which points to a .SQL file?
My concern: If it exists, DBA only needs to distribute SQL script files to developer and developer just needs to change a little of content rather than copy&paste