Code refactoring là hoạt động chỉnh sửa khiến source code dễ đọc hơn, được tổ chức khoa học hơn, và (có thể) có kiến trúc / cấu trúc tốt hơn nhưng không làm thay đổi hành vi của hệ thống về mặt chức năng.

Việc này giống như chúng ta sắp đặt lại hệ thống điện trong nhà theo một cách khoa học hơn nhưng vẫn đảm giữ nguyên vị trí và chức năng của những công tắc, ổ cắm trên tường. Tôi muốn lấy ví dụ này để bạn hiểu rằng, những gì nhóm phát triển làm với code refactoring hoàn toàn “nằm trong bức tường”, nơi mà khách hàng hoàn toàn không nhìn hay cảm nhận được; nhưng lại rất quan trọng, đặc biệt trong dự án thực hành Agile. “Tôi muốn có một ổ cắm điện ở vị trí này”, sau 10 lần hoàn thành yêu cầu đó từ khách hàng, hệ thống dây điện chắc chắn sẽ chứa nhiều bất cập và không dễ bảo trì. Việc sắp đặt lại những dây điện này một cách hợp lý nhưng vẫn đảm bảo được chức năng hiện có giúp chúng ta sẵn sàng cho yêu cầu về một ổ cắm điện thứ 11. Và thật may là code refactoring thì thường không “tốn kém” và phức tạp như việc đục các bức tường để sắp đặt lại hệ thống dây điện. Vì vậy, chúng ta cũng có thể (và nên)  làm việc này thường xuyên.

Thực hiện code refactoring như thế nào? Vấn đề này thậm chí là quá nhiều cho cả một cuốn sách. Những cách thức đơn giản nhất bạn có thể tham khảo tại http://refactoring.com của huyền thoại Martin Fowler. Tại đây bạn có thể tham khảo những kỹ thuật đơn giản nhất và dấu hiệu nhận biết một đoạn code có thể được refactor; từ chuyện đơn giản nhất như chuyển 2 đoạn code giống nhau thành một hàm đến sự liên kết giữa các đối tượng nhằm đảm bảo tính hướng đối tượng của chương trình. Trang web này thực sự hữu ích với những hệ thống thiết kế theo tư tưởng hướng đối tượng (phù hợp với đa số những mã nguồn hiện giờ), nhưng cũng rất tốt với những tư tưởng lập trình khác. Một chú ý hay là, đôi khi bạn thấy hướng dẫn refactor một đoạn code từ A sang B và nơi khác lại hướng dẫn refactor đoạn code từ B sang A. Điều này không mâu thuẫn, bởi “A hay B tốt hơn?” thì chỉ chính bạn mới có câu trả lời xác đáng trong ngữ cảnh của source code hiện tại. Tuy vậy, vẫn sẽ có những chuẩn chung để một đoạn code được coi là “tốt” hay “dở”; ví dụ, đặt tên biến là a là điều không chấp nhận được trong phát triển phần mềm (nơi duy nhât tôi thấy cách đặt tên biến này phát huy tác dụng là trong những cuộc thi lập trình với source code ngắn và thời gian ganh đua tính bằng mili giây). Và hãy nhớ rằng, code refactoring không làm thay đổi hành vi của chức năng hay hệ thống; do đó, kết quả của việc kiểm thử phải không đổi.

Khi nào thực hiện code refactoring? Về lý thuyết, hãy thực hiện code refactoring bất cứ khi nào có thể. Trước khi commit, mỗi lập trình viên cần đọc lại những đoạn code mình đã viết và xem có thể cải tiến được không. Sau một thời gian, nhóm phát triển cần cùng nhau nhìn lại xem có thể cải tiến ở những điểm nào và cùng thực hiện code refactoring. Tuy nhiên, vấn đề không đơn giản như vậy.

Điều gì ngăn cản code refactoring? Đây là một câu hỏi rất thú vị. Tôi đã gặp rất nhiều nhóm thực hành Agile nhưng không bao giờ thực hiện code refactoring, với những lý do chính như sau:

  • Trình độ kém. Khi nhóm phát triển không có hiểu biết sâu sắc về OOP thì đương nhiên những đoạn code ban đầu viết ra sẽ rất “dở”, nhưng quan trọng là họ hoàn toàn không biết rằng nó “dở”. Việc này càng nguy hại nếu không thực hiện code refactoring bởi nhóm sẽ mãi duy trì năng lực hiện có.
  • Chấp nhận. Sau một thời gian dài, nhóm phát triển nhận ra có rất nhiều đoạn code “dở” nhưng nhóm vẫn chấp nhận bởi số lượng code “dở” là quá nhiều và có tư tưởng chấp nhận “sống chung với lũ”, hoặc nghĩ tới việc viết lại toàn bộ hệ thống.
  • Không có thời gian. Đây là lý do khá xác đáng; bởi như tôi nói ở trên, khách hàng hoàn toàn không nhận được lợi ích trực tiếp từ code refactoring, nên khó thuyết phục họ trả tiền cho nhóm phát triển thực hiện code refactoring. Tuy vậy, việc lắp ổ điện thứ 11 mất 10 giờ, thay vì 2 giờ cho ổ điện thứ 1, thì cũng là tiền của khách hàng mà thôi (và điều này có thể nảy sinh nghi ngờ từ khách hàng rằng năng lực hoặc thái độ làm việc của nhóm đã kém đi).

Tuy vậy, những lý do này sẽ đẩy cả nhóm phát triển vào một vòng luẩn quẩn không hồi kết: trình độ kémsức ép thời gian đưa ra những đoạn code “dở”, không thực hiện code refactoring khiến trình độ không được cải thiện, sau một thời gian đành chấp nhận, khiến sức ép thời gian càng lớn, không thể thực hiện code refactoring, và trình độ không được cải thiện… Và dự án, từ đam mê bỗng thành gánh nặng với nhóm phát triển, khiến động lực làm việc không còn đúng.

Vậy giải pháp là gì? Từ góc độ một lập trình viên, tôi cho rằng việc không thực hiện code refactoring là trách nhiệm của lập trình viên; do họ không đủ đam mê và trách nhiệm cần thiết với “đứa con tinh thần” của mình; không khác một nhà văn viết ra những tác phẩm rẻ tiền. Tuy vậy, người “lãnh đạo” trong dự án Agile cũng phải có trách nhiệm tạo ra những “khoảng lặng” về những chức năng cần bổ sung để nhóm phát triển thực hiện code refactoring. Việc này diễn ra càng đều đặn, trình độ và năng suất của lập trình viên càng cao bởi code refactoring chính là một cách nâng cao tay nghề và hiểu biết sâu sắc dựa trên những best practice cải tiến họ tốt hơn. 1 ngày dành cho code refactoring hôm nay có thể giảm bớt 10 ngày phát triển buồn tẻ sau này.

Giải pháp cho source code đã quá “cũ”? Khi chúng ta “động đâu cũng thấy vấn đề” trong source code, chấp nhận hoặc làm lại từ đầu thường là giải pháp; tuy vậy, cả 2 giải pháp này đều rất tốn kém. Code refactoring có thể là một giải pháp:

  • Sử dụng công cụ phân tích source code (tôi sẽ đề cập ở những bài viết sau) để tìm ra những đoạn code “dở”
  • Nhóm phát triển cùng quét nhanh qua mã nguồn để đánh giá và tìm thêm những vấn đề
  • Ước lượng tổng thời gian cần cho code refactoring
  • Định nghĩa và lên kế hoạch việc kiểm thử. Việc này rất quan trọng vì code refactoring phải đảm bảo không thay đổi hành vi của chức năng và hệ thống. Lúc này automation test được ưu tiên bởi khối lượng kiểm thử nhiều. Không nên (thậm chí là nghiêm cấm) thực hiện code refactoring nếu không có kế hoạch kiểm thử tốt.
  • Lên kế hoạch và thực hiện dần, từng phần. Thật tuyệt vời nếu chúng ta có toàn bộ thời gian để thực hiện; nếu không, hãy thực hiện từng phần song song với quá trình phát triển tiếp. Và hãy kiên nhẫn, chúng ta không thể thấy kết quả chỉ sau 1 vài ngày.

Thât ra, code refactoring là công việc rất đơn giản, đến mức người ta dễ dàng bỏ qua code refactoring để nghĩ tới architect refactoring hay structure refactoring. Nhưng theo tôi, khi thực hiện code refactoring tốt, những design pattern sẽ dần được hình thành và từ đó kiến trúc mới cũng sẽ được hình thành. Rất ít khi chúng ta cần tới architect refactoring; và tôi cũng không tham vọng giới thiệu những điều này sớm.

1,984 total views, 1 views today

Problem

After a long time in-door researched, Hung found a good approach to attract a girl and he named it “Girl attracting law by Fibonacci approach” that means the number of presents Hung gives to her is increased by Fibonacci sequence. But don’t stop, he extended to version 2 with some customisation by:

T(n+2) = T(n+1) * T(n+1) + T(n)

with T(n) is a number of presents at the nth dating.

Hung of course has a lot of money but wants to trust a girl, so he should give her 0 present at the first and 1 present at the second dating. And following his theory, 5 presents should be given in the 5th dating as explanation below:

1st number  = 0

2nd number = 1

3rd number = 12 + 0 = 1

4th number = 12 + 1 = 2

5th number = 22 + 1 = 5

Hung said that he has meet her 13 times and today he wants to know how many present he should give. Could you help Hung?

Solution

It seems very easy because the Fibonacci is a basic problem we usually do in learning programming. But, please aware that the number in this sequence increase too fast and need a wide range of positive number. In C# or Java, you could use BigInteger type.

 

453 total views, 1 views today

Following my Code Challenge problem Cute girl decoder, here is the solution:

Solution

It seems very easy to solve this problem by replacing the substring such as j by gi, dz by d, k by khong.

But, there is a trick at “With words, she usually use”, that means k should be replace by khong only if it’s a word that is normally separated by these characters: [space] , . ; ? !

You could find an implementation below in Objective-C, my thank to Nghia Luong for the code contribution.

It looks good but in my opinion, we could make it better with the open design.

Better design

Let see my implementation below as I think it could be better design to extend the implementation in the future. But please try to find some area we can improve 🙂

And the decoded message would be:

chan qua. em mun an nhieu ga quay cho doi gio duoc khong day? Anh co phai la nguoi iu cua em khong day, neu a la nguoi ieu cua em thi phai dua em di an ga quay chu, anh ma hem dua em di em gian a lien doa. The gio anh mun nhu the nao? ket qua ha? ok, neu ma anh khong dua iem di an ga ran thi nguoi dung den gap em lam gii nua, em khong yeu anh nua dau, iu gi ma co moi viec dua di an ga quay cung khong duoc thi yeu lam gi day, chan anh vagi dan ra ay. Ngay hom sau em noi gi a, em van noi la: chan qua. em mun an nhieu ga quay cho doi gio duoc khong day? Anh co phai la nguoi iu cua em khong day, neu a la nguoi ieu cua em thi phai dua em di an ga quay chu, anh ma hem dua em di em gian a lien doa. The gio anh mun nhu the nao? ket qua ha? ok, neu ma anh khong dua iem di an ga ran thi nguoi dung den gap em lam gii nua, em khong yeu anh nua dau, iu gi ma co moi viec dua di an ga quay cung khong duoc thi yeu lam gi day, chan anh vagi dan ra ay. Ngay hom sau nua em noi gi a, em noi day ne: chan qua. em mun an nhieu ga quay cho doi gio duoc khong day? Anh co phai la nguoi iu cua em khong day, neu a la nguoi ieu cua em thi phai dua em di an ga quay chu, anh ma hem dua em di em gian a lien doa. The gio anh mun nhu the nao? ket qua ha? ok, neu ma anh khong dua iem di an ga ran thi nguoi dung den gap em lam gii nua, em khong yeu anh nua dau, iu gi ma co moi viec dua di an ga quay cung khong duoc thi yeu lam gi day, chan anh vagi dan ra ay.

Go further

The idea of Skype plugin just came to make this problem more fun. But do you want to make it go live? I didn’t build it yet, but if you like this idea, I would like to code and share in the next post.

Do you want to see the new Skype plugin? Throw me at least 50 likes 🙂

555 total views, 3 views today

Long had a new girl friend, congrats to him. He feels very happy by chatting with her everyday although it’s not an easy work. As a 9x cute girl, she uses a lot of teenage chatting words and it usually takes Long more time to read and understand. And of course, it takes him a lot of his brain’s energy :).

To make it easy, Long plans to build a Skype plugin that can translate her sentences to the normal ones. He found that it’s so easy to replace the cute words by the following rules:

  • With words, she usually use
    • k for khong
    • ko for khong
    • ng for nguoi
    • n for nhieu
    • dc for duoc
    • hok for khong
    • ntn for nhu the nao
    • kq for ket qua
  • She also use these characters
    • j for gi
    • w for qu
    • f for ph
    • dz for d
    • z for d

So if she says “chan wa. em mun an n ga way cho doi jo dc hok dzay?“, it is “chan qua. em muon an nhieu ga quay cho doi gio duoc khong day?

Could you help Long to write this plugin. After that, please try to translate her recent message:

chan wa. em mun an n ga way cho doi jo dc hok dzay? Anh co phai la ng iu cua em k zay, neu a la ng ieu cua em thi fai dua em di an ga way chu, anh ma hem dua em di em jan a lien doa. The gio anh mun ntn? kq ha? ok, neu ma anh hok dua iem di an ga ran thi ng dung den gap em lam ji nua, em k yeu anh nua dau, iu j ma co moi viec dua di an ga way cung ko duoc thi yeu lam j dzay, chan anh vaj dan ra ay. Ngay hom sau em noi j a, em van noi la: chan wa. em mun an n ga way cho doi jo dc hok dzay? Anh co phai la ng iu cua em k zay, neu a la ng ieu cua em thi fai dua em di an ga way chu, anh ma hem dua em di em jan a lien doa. The gio anh mun ntn? kq ha? ok, neu ma anh hok dua iem di an ga ran thi ng dung den gap em lam ji nua, em k yeu anh nua dau, iu j ma co moi viec dua di an ga way cung ko duoc thi yeu lam j dzay, chan anh vaj dan ra ay. Ngay hom sau nua em noi j a, em noi dzay ne: chan wa. em mun an n ga way cho doi jo dc hok dzay? Anh co phai la ng iu cua em k zay, neu a la ng ieu cua em thi fai dua em di an ga way chu, anh ma hem dua em di em jan a lien doa. The gio anh mun ntn? kq ha? ok, neu ma anh hok dua iem di an ga ran thi ng dung den gap em lam ji nua, em k yeu anh nua dau, iu j ma co moi viec dua di an ga way cung ko duoc thi yeu lam j dzay, chan anh vaj dan ra ay.

The solution will be updated in 3 days.

421 total views, 1 views today

Following my problem in the first post of Code Challenge series, it’s a solution.

Problem

A motor bike plate number is in the format [AB-CD EFG.HI]. Its value is defined by: AB x C + EFG x HI, if C is a letter, its value is its ASCII code. A plate number is called NICE one if its EFG contains its HI, then its value is doubled than normal. Give you a list of place numbers, find the biggest value.

For example: A plate 29-C1 320.12 has value 5783 (= 29*67+320*12)

What is the biggest value of

28-A1 493.68

83-Y3 453.83

17-Z7 439.48

29-C1 292.29

Solution

It seems easy where we can compute the value of a specific plate number and find a biggest value afterward.

But, please aware that there is a trick at if C is a letter, its value is its ASCII code. So C can be a digit or letter. Only if it is not a digit, we need to get its value by ASCII code.

Here is my solution in C#

Here is the solution in Objective-C, credit to Nghia Luong to share.

No code

Yes, at least we can solve it by Excel as can compute a plate number value by this function

Note: 

My full input is in attachment, not just a simple input above as it’s easy to solve manually.

[wpba-attachment-list]

437 total views, 1 views today

Do you remember my post about the interview question? It’s one of my problems in our Code Challenge that I would like to share in this post.

Code Challenge is one of our exciting activities last year where we can learn from each other by solving the problems in a contest. I also published the tool on Github for who wants to host this kind of event, please don’t hesitate to contact me if you want to use or need any support.

Purpose

It makes sense, everybody always needs to improve as every organisation needs to go forward. And learning is a good way to keep us improved and motivated. We have thought about the contest that allows every developers join to learn and measure their coding skill, and we held the Code Challenge last year that was involved by all our developers as contestants.

Joining the contest with our colleagues is very fun thing as we can learn from others and see how good we are right now. But it’s not easy for the host because there are various specific platforms or technologies in one organisation or teams, then the contest should target on a shared knowledge or skills in the whole team. To be fair, we should remove all the dependencies that relate to the language or platform uses and back to the basic of software development: programming.

Follow my experience, the ACM ICPC is very good format that focus on the programming but it seems still complex and has language limitation. Project Euler suits us better but it should have the time constraint to identify the winner.

Format

Our Code Challenge is mostly like the Project Euler format with time limitation as ACM ICPC. It was being held bi-weekly in 5 rounds, each round run from 13:00 to 17:00. In 4 hours, the contestants try to solve about 5 or 6 problems by following rules:

  • Solve problems in order. The contestant needs to solve a problem before taking the next one. So the problems should be arranged by their difficulties.
  • Result comparison. It doesn’t matter with the contestants’ solution as they can solve the problem by any programming language (or sometimes by non-programming as by Excel skill). A problem just shows the issue with a specific input data and compare the result with correct solution.
  • Multiple submissions. Contestant can try submit his solution many times as he wants to get the problem solved. The time spend for a problem is that the time he starts the contest to the first attempt of accepted solution.
  • Faster is better, careful is good. The contestants are ranked by these criteria in order:
    • Number of solved problems. The more number of solved problems are, the higher rank of contestant is.
    • Number of submission. If some contestants have the same number of solved problems, the number of submission should be counted. The contestant get higher rank by fewer attempts.
    • Time spend. The time spend should be the last criteria as its precision was counted to millisecond :). It is the total time spend of all solved problems.

Experiences

As our experience, there are some good things we could have from Code Challenge:

  • Fun. It could come from various sources such as a story in problem or the solution. In the 3rd round, we all surprised by a problem can be solved in 3 minutes as it normally takes at least 15 minutes for programming. But it’s so easy to calculate and submit the possible results manually. Yes, he’s so smart.
  • Share and learn. After the contest, we always sit together to share our different solutions of those problems, so we can learn from others and see what was the best way to solve them.
  • Improve. We of course had a good chance to learn from others or from practice during the contest preparation for getting improved.
  • Motivate. Beside the award for winner, there were some secondary awards such as the best newbie, first solved problem, last accepted attempt…etc for our guys trying to get.

And there are a lot of good things you would see as I think you should host at least one Code Challenge in your team.

Issues

Yes, there are various good things we had but in another hand, some minor issues came.

You could see that our format and tool were designed to target the purpose: removing the technology dependencies where contestant can solve the problem by any language (or by non-programming). But the issue is moved to the problem set as we should design them as free-language algorithm – it’s usually not easy. A lot of problems can be solved quickly by Java, C# but much slower in C++ by coding time but versa in running time.

Another issue is that somebody is very good at basic programming and algorithm but someone isn’t. I truly believe that a good developer should be good at algorithm but it seems not work today as the technology goes so far and developer can build the very good products with a normal algorithm background. He of course cannot be bad but doesn’t need to be very strong in algorithm to be a good developer as some years ago because the high-level technologies support us too much. For example, 10 years ago, every good developer needs to know what best sorting algorithm in his case in C++ but today a normal developer doesn’t care about this, just call Sort() method in C# and it would do in the best way. And of course, the results are mostly the same no matter he knows the Sort() method would run by any algorithm. It’s proved in our Code Challenge last year as there was only 1 winner for all rounds. He is very talent and strong in algorithm but isn’t a top guy in product development.

They are just the minor issues we would face in any contest that targets to wide range of developers. The problem content is the best way to resolve these issues but it usually takes much time to create a good problem like that. Contest is not fair but we should keep it as good as possible 🙂

I will share our problems that were used in our Code Challenge last year in some next posts and hope that you can find some interesting things.

And here is the system we have used: https://github.com/hiennvn/code-challenge. It may have some bugs because it just was the first MVP and one of my 24-coding-hours projects. But it worked fine for us last year.

Keep calm and love code.

Don’t want to wait for my next post? Try this problem:

A motor bike plate number is in the format [AB-CD EFG.HI]. Its value is defined by: AB x C + EFG x HI, if C is a letter, its value is its ASCII code. A plate number is called NICE one if its EFG contains its HI, then its value is doubled than normal. Give you a list of place numbers, find the biggest value.

For example: A plate 29-C1 320.12 has value 5783 (= 29*67+320*12)

What is the biggest value of

28-A1 493.68

83-Y3 453.83

17-Z7 439.48

29-C1 292.29

558 total views, 5 views today

Bài viết đăng trên Tạp Chí Lập Trình

Array có mặt trong hầu hết các ngôn ngữ lập trình, là một cấu trúc dữ liệu cho phép lưu trữ và truy xuất các phần tử ngẫu nhiên dựa trên vị trí. Trong Javascript, Array có gì khác?

Một lớp

Và do đó, chúng ta có thể tạo một đối tượng Array để lưu trữ các phần tử. Có 2 cách thường dùng để khởi tạo 1 đối tượng Array:

hoặc:

sẽ khởi tạo 1 đối tượng mảng arr chứa các phần tử “Bob”, “Jobs” và “Bill”.

No-type

Như bạn đã biết, trong Javascript, nói chung các biến không cần chỉ định rõ kiểu. Do đó, chúng ta có thể chứa những phần tử có kiểu khác nhau trong cùng 1 mảng như:

Điều này rất khác so với những ngôn ngữ như C++, Java… khi khai báo mảng với int arr[10]; sẽ giới hạn mảng arr chỉ chứa các số kiểu int.

Mutable

Điều gì xảy ra nếu chúng ta thực hiện đoạn mã sau?

Sẽ chẳng có lỗi OutOfRange nào như chúng ta mong đợi. Đơn giản vì Javascript tự điều chỉnh kích thước của mảng cho phù hợp, hay khả năng “co giãn”, còn gọi là mutable. Có lẽ Array mang hình ảnh của List?

Và..

Ngoài việc lưu trữ những phần tử có kiểu khác nhau, đối tượng Array còn cho phép dùng nhiều kiểu dữ liệu khác nhau làm “key”.

Hãy thử đoạn mã sau:

Đến đây chắc bạn cũng nhận ra, đối tượng Array không giống như mảng thông thường, chỉ cho phép truy xuất qua chỉ số là số nguyên, mà còn cho phép truy xuất qua chỉ số là một đối tượng bất kỳ. Thực ra, Javascript lưu trữ các đối tượng dưới dạng key-value-based, tức là mỗi đối tượng key (khoá) sẽ tương ứng (ánh xạ) với một đối tượng value (giá trị) theo cặp. Cấu trúc dữ liệu nào lưu trữ dưới dạng key-value-based? Có lẽ là Map.

Ngoài ra..

Hãy để ý các phương thức có sẵn của đối tượng Array, có lẽ bạn sẽ ấn tượng với 2 phương thức hay được sử dụng nhất: pop() và push().

Cấu trúc dữ liệu nào sở hữu những phương thức này? Stack và Queue. Vậy đối tuợng Array mang hình ảnh của Stack hay Queue? Cách kiểm chứng đơn giản nhất là dựa trên cơ chế của 2 kiểu cấu trúc dữ liệu này: Stack hoạt động theo phương thức LIFO (Last In First Out – Vào sau ra trước), Queue thì ngược lại LILO (Last In Last Out – Vào sau ra sau) (Có người thích gọi cơ chế hoạt động của Stack là: FILO và Queue là: FIFO). Hãy đưa một phần tử vào một Array đã có dữ liệu qua phương thức push(), tiếp đó, lấy phần tử trong Array qua phương thức pop(). Nếu hai phần tử này giống nhau, chắc chắn Array hoạt động theo phương thức LIFO tức là Stack, ngược lại Array hoạt động theo phương thức LILO hay Queue.

OK, hãy thử đoạn mã sau:

Chắc bạn đã có câu trả lời.

Tiếp theo…

Làm sao có thể biến cấu trúc dữ liệu của đối tượng Array từ Stack sang Queue và ngược lại? Hãy thử sức.

Gợi ý: Sử dụng phương thức reverse() cho phép đảo ngược các phần tử trong đối tượng Array hoặc phương thức shift() cho phép lấy ra khỏi mảng phần tử đứng đầu.

Lời kết

Giờ đây chắc bạn đã thấy sức mạnh của đối tượng Array trong Javascript, nó có thể biến đổi uyển chuyển giữa những cấu trúc dữ liệu phức tạp khác nhau như List, Map, Stack hay Queue.

Một thông tin đáng mừng là Javascript chỉ là một đại diện cho một lớp những scripting language (ngôn ngữ kịch bản, như PHP, Python…), trong đó đối tượng Array được sử dụng như cấu trúc dữ liệu chính và thể hiện rất nhiều hình ảnh khác nhau như trong Javascript.

Hãy tiếp tục tìm hiểu xem Array có thể mô tả cấu trúc dữ liệu nào khác và cùng update vào bài viết.

477 total views, 1 views today

Bài viết đã đăng trên Tạp Chí Lập Trình

Thế nào là lập trình an toàn?

Có lẽ nên bắt đầu với khái niệm một hệ thống “an toàn” hay “bảo mật” (security). Một hệ thống được coi là “an toàn” khi nó đảm bảo được ba yếu tố chính (thường được gọi là tam giác CIA) bao gồm: Confidentiality (tuyệt mật), Integrity (toàn vẹn) và Availability (sẵn sàng). Để hệ thống an toàn đòi hỏi rất nhiều công sức trong tất cả giai đoạn phát triển phần mềm, trong phạm vi bài viết này tôi chỉ đề cập đến khái niệm an toàn trong giai đoạn lập trình.

Tôi chỉ cố gắng đưa ra một số sai lầm thường gặp nhất trong việc lập trình gây ảnh hưởng tới tính an toàn của hệ thống, đây cũng là những chỉ dẫn đơn giản giúp bạn hiểu về một công việc cần làm để có “good code”.

HTTP method

Form là công cụ hay dùng nhất để client gửi dữ liệu tới server thông qua một trong hai phương thức: GET hoặc POST. Điểm khác nhau cơ bản là GET gửi dữ liệu qua URL, POST thì không.

Điều gì xảy ra nếu chúng ta dùng GET? Một người đứng phía sau có thể nhìn thấy thông tin tài khoản của người dùng khi họ login như:

Vậy tại sao chúng ta vẫn dùng GET? Vì tiện. Các lập trình viên thường có xu hướng dùng GET khi lập trình để tiện thay đổi thông tin cho việc test, nhằm tăng năng suất. Vấn đề là họ thường quên điều chỉnh khi release sản phẩm.

Giải pháp: Luôn sử dụng POST với những thông tin nhạy cảm, và hãy luôn nhớ kiểm tra phương thức HTTP trong các form trước khi đóng gói sản phẩm.

Vi phạm: Tính tuyệt mật

SQL injection

Đây là lỗi kinh điển nhưng có lẽ bạn đã và  vẫn đang mắc phải. Giả sử, hệ thống cho phép đăng nhập qua usernamepassword, tôi nghĩ đây là cách bạn đang làm:

  • Nhận dữ liệu và lưu vào 2 biến, giả sử usr và pwd
  • Tạo câu lệnh

(với tableusernamepassword là bảng và các trường trong DB)

  • Thực thi câu lệnh, nếu (giả sử) ResultSet trả về có nhiều hơn 0 bản ghi, người dùng được coi là nhập đúng thông tin và đăng nhập thành công.

OK? Điều gì xảy ra nếu người dùng nhập:

  • usr: admin
  • pwd: ’ OR ‘1’ = ‘1

Khi đó, câu lệnh SQL trở thành:

Và thường thì sẽ có nhiều hơn 0 bản ghi (chính xác là toàn bộ bản ghi trong bảng table) được trả về, người dùng đăng nhập thành công.

Và khi pwd là: ’ OR ‘1’ = ‘1’; UPDATE users SET password = ‘123’ WHERE username = ‘admin’;

Câu lệnh SQL trở thành:

Hai câu lệnh SQL được thực thi và password của tài khoản admin được đặt lại thành ‘123’.

Lỗi này đặc biệt nghiêm trọng trong những hệ thống mã nguồn mở hoặc trên các diễn đàn, vì tên đăng nhập của người dùng và cấu trúc DB thường được biết trước.

Giải pháp: Chắc bạn cũng thấy, SQL injection lợi dụng những ký tự đặc biệt ‘ trong chuỗi giá trị nhập vào nên giải pháp đơn giản là hãy luôn loại bỏ chúng trước khi chuyển thành câu lệnh SQL. Do đây là một lỗi phổ biến nên hầu hết ngôn ngữ hiện đại đều cung cấp khả năng xử lý. Trong Java, khi làm việc với JDBC, thay vì dùng Statement, hãy sử dụng PreparedStatement hoặc CallableStatement. (http://docs.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html)

Tham khảo thêm tại: https://www.guru99.com/learn-sql-injection-with-practical-example.html

Vi phạm: Tính tuyệt mật, toàn vẹn

Exception

Ai cũng biết, và có lẽ dù có nhắc đến lỗi này cả triệu lần nữa thì chúng ta vẫn có thể mắc phải. Đơn giản vì chúng ta thường lập trình rất nhanh để sớm đưa ra sản phẩm và hay bỏ qua việc tung (throw) và bắt (catch) exception.

Chúng ta xây dựng một chương trình bảng tính tuyệt vời với rất nhiều chức năng và khi người dùng nhập phép toán 1/0, toàn bộ chương trình ngừng hoạt động; tất cả dữ liệu trước đó bị mất do không bắt exception. Các IDE ngày nay rất thông minh, nếu chúng ta viết câu lệnh a = 1/0; Netbeans chắc chắn sẽ bắt chúng ta phải catch exception. Vì vậy, các lập trình viên thường khá chủ quan. Nhưng IDE sẽ bất lực nếu chúng ta viết a = b / c; với c = 0. Đôi khi cả hệ thống sụp đổ chỉ do 1 sự bất cẩn nhỏ trong lập trình. Điều này còn nguy hại hơn nếu bạn xây dựng 1 ứng dụng web server, khi hàng ngàn request có thể không được xử lý chỉ do lỗi của 1 request. Ứng dụng như vậy không được coi là có khả năng chịu lỗi (failure tolerant), ảnh hưởng tới tính sẵn sàng. Nguy hiểm hơn, một số người có thể đọc được lỗi và khai thác lỗ hổng (vulnerability) của hệ thống.

Giải pháp: Hãy luôn bắt exception với bất kỳ thao tác nào có khả năng xảy ra lỗi như: Các phép toán (chia 0, tràn số (c = a * b với a, b có kiểu int có thể vượt ngoài khoảng kiểu int của c là sai), phép trừ ra số âm…), đọc hay ghi dữ liệu vào file (file có thể không tồn tại, không có quyền đọc/ghi), truyền dữ liệu qua mạng (không có kết nối…), sử dụng object chưa được khởi tạo (null pointer exception – lỗi rất phổ biến)…

Đồng thời, hãy luôn tung exception trong các phương thức có khả năng gây lỗi do mình tự viết.

Hãy nhớ rằng, chúng ta không đủ thời gian để kiểm thử (test) tất cả trường hợp và thường chọn trường hợp “rất đẹp” trên những bộ dữ liệu “rất đẹp” khi chào hàng phần mềm. Thực tế, người dùng lại luôn “ngớ ngẩn” và luôn gây lỗi, đừng để một hệ thống hoành tráng bị sụp đổ bởi sự vô trách nhiệm nhỏ.

Vi phạm: Tính tuyệt mật, tính toàn vẹn, tính sẵn sàng.

Duyệt file

Một ứng dụng có thiết kế tốt cũng có thể hay mắc phải lỗi này. Chúng ta tạo ra một template và hiển thị nội dung file theo ngữ cảnh người dùng. Ví dụ, khi người dùng vào trang đăng nhập, bạn sẽ sử dụng URL: http://myweb.com?view=login.html, nhận biết trang cần hiển thị qua parameter view, đọc file login.html và trả về client. Điều gì xảy ra nếu người dùng nhập URL: http://myweb.com?view=../../data/document.doc? Nếu không được phân quyền tốt, có thể bạn sẽ trả về file document.doc nằm trong thư mục data trên ổ cứng.

Giải pháp: Phân quyền cho thư mục và thực hiện rewrite URL là cách tốt nhất, song việc này thường được thực hiện tại bước triển khai. Và nếu bạn không chắc việc triển khai chính xác, hãy luôn kiểm tra tính hợp lệ của các file được trả về.

Vi phạm: Tính tuyệt mật, tính toàn vẹn, tính sẵn sàng.

Và?

Đến đây, có thể bạn đã nhận thấy ba yếu tố trong tam giác CIA nói chung không thể cùng đạt điểm tối đa. Đơn giản vì từng yếu tố này vốn tự mâu thuẫn lẫn nhau. Ví dụ, để tăng cường tính tuyệt mật, hệ thống ngân hàng yêu cầu chúng ta nhập mật mã (được gửi qua SMS) mỗi khi chuyển tiền; gây ảnh hưởng tới tính sẵn sàng của hệ thống do những người quên điện thoại sẽ không thực hiện được giao dịch. Vậy đâu là mức phù hợp cho từng tiêu chí của hệ thống?

Trên đây chỉ là một số rất nhỏ những sai lầm có thể gặp phải trong việc lập trình gây ảnh hưởng tới tính an toàn của hệ thống. Bạn có thể tìm hiểu thêm về những sai lầm thường gặp khác, hoặc tôi sẽ đề cập tiếp nội dung này trong một lần thích hợp.

241 total views, 1 views today