Thứ Sáu, 30 tháng 10, 2015

SOLID là gì – Áp dụng các nguyên lý SOLID để trở thành lập trình viên code “cứng”

Trong quá trình học, hầu như các bạn sinh viên đều được học một số khái niệm OOP cơ bản như sau:
  • Abstraction (Tính trừu tượng)
  • Encapsulation (Tính bao đóng)
  • Inheritance (Tính kế thừa)
  • Polymophirsm (Tính đa hình)
Những khái niệm này đã được dạy khá rõ ràng, và hầu như những buổi phỏng vấn nào cũng có những câu hỏi liên quan đến khái niệm này. Vì 4 khái niệm này khá cơ bản, bạn nào chưa vũng có thể google để tìm hiểu thêm.
Những nguyên lý mình giới thiệu hôm nay là những nguyên lý thiết kế trong OOP. Đây là những nguyên lý được đúc kết bởi máu xương vô số developer, rút ra từ hàng ngàn dự án thành công và thất bại. Một project áp dụng những nguyên lý này sẽ có code dễ đọc, dễ test, rõ ràng hơn. Và việc quan trọng nhất là việc maintainace code sẽ dễ hơn rất nhiều (Ai có kinh nghiệm trong ngành IT đều biết thời gian code chỉ chiếm 20-40%, còn lại là thời gian để maintainance: thêm bớt chức năng và sửa lỗi). Nắm vững những nguyên lý này, đồng thời áp dụng chúng trong việc thiết kế + viết code sẽ giúp bạn tiến thêm 1 bước trên con đường thành senior nhé (1 ông senior bên FPT Software từng bảo mình thế).

Ok, 10 phút quảng cáo đã qua, bây giờ đến phần giới thiệu. SOLID tức là "cứng", áp dụng nhiều thì bạn sẽ code "cứng". Đùa thôi, nó là tập hợp 5 nguyên tắc sau đây:
  1. Single responsibility principle
  2. Open/closed principle
  3. Liskov substitution principle
  4. Interface segregation principle
  5. Dependency inversion principle
Trong nội dung bài viết này, mình chỉ giới thiệu tổng quát để các bạn có cái nhìn tổng quan về các nguyên lý này.

1. Single responsibility principle


Nguyên lý đầu tiên, tương ứng với chữ S trong SOLID. Nội dung nguyên lý:
Một class chnên giữ 1 trách nhim duy nht (Chcó thsa đổi
class vi 1 lý do duy nht)
Để hiểu nguyên lý này, ta hãy lấy ví dụ với 1 class vi phạm nguyên lý. Ta có 1 class như sau
public class ReportManager()
{
   public void ReadDataFromDB();
   public void ProcessData();
   public void PrintReport();
}
Class này giữ tới 3 trách nhiệm: Đọc dữ liệu từ DB, xử lý dữ liệu, in kết quả. Do đó, chỉ cần ta thay đổi DB, thay đổi cách xuất kết quả, … ta sẽ phải sửa đổi class này. Càng về sau class sẽ càng phình to ra. Theo đúng nguyên lý, ta phải tách class này ra làm 3 class riêng. Tuy số lượng class nhiều hơn những việc sửa chữa sẽ đơn giản hơn, class ngắn hơn nên cũng ít bug hơn.

2. Open/closed principle


Nguyên lý thứ hai, tương ứng với chữ O trong SOLID. Nội dung nguyên lý:
Có thể thoái mái mở rộng 1 class, nhưng không được sửa đổi
bên trong class đó (open for extension but closed for modification).
Theo nguyên lý này, mỗi khi ta muốn thêm chức năng,.. cho chương trình, chúng ta nên viết class mới mở rộng class cũ ( bằng cách kế thừa hoặc sở hữu class cũ) không nên sửa đổi class cũ.

3. Liskov Substitution Principle


Nguyên lý thứ ba, tương ứng với chữ L trong SOLID. Nội dung nguyên lý:
Trong mt chương trình, các object ca class con có thể
thay thế class cha mà không làm thay đổi
tính đúng đắn ca chương trình
Hơi khó hiểu? Không sao, lúc mới đọc mình cũng vậy. Hãy tưởng tượng bạn có 1 class cha tên Vịt. Các class VịtBầu, VịtXiêm có thể kế thừa class này, chương trình chạy bình thường. Tuy nhiên nếu ta viết class VịtChạyPin,cần pin mới chạy được. Khi class này kế thừa class Vịt, vì không có pin không chạy được, sẽ gây lỗi. Đó là 1 trường hợp vi phạm nguyên lý này.

4. Interface Segregation Principle


Nguyên lý thứ tư, tương ứng với chữ I trong SOLID. Nội dung nguyên lý:
Thay vì dùng 1 interface ln, ta nên tách thành nhiều
interface nhỏ, vi nhiều mc đích cth
Nguyên lý này khá dễ hiểu. Hãy tưởng tượng chúng ta có 1 interface lớn, khoảng 100 methods. Việc implements sẽ khá cực khổ, ngoài ra còn có thể dư thừa vì 1 class không cần dùng hết 100 method. Khi tách interface ra thành nhiều interface nhỏ, gồm các method liên quan tới nhau, việc implement + quản lý sẽ dễ hơn.

5. Dependency inversion principle


Nguyên lý cuối cùng, tương ứng với chữ D trong SOLID. Nội dung nguyên lý:
1. Các module cấp cao không nên phụ thuộc vào các modules cấp thấp.
   C2 nên phụ thuộc vào abstraction.
2. Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại. (Các class giao tiếp vi nhau thông qua interface,
không phi thông qua implementation.)
Nguyên lý này khá lắt léo, mình sẽ lấy ví dụ thực tế. Chúng ta đều biết 2 loại đèn: đèn tròn và đèn huỳnh quang. Chúng cùng có đuôi tròn, do đó ta có thể thay thế đèn tròn bằng đèn huỳnh quanh cho nhau 1 cách dễ dàng.

Ở đây, interface chính là đuôi tròn, implementation là bóng đèn tròn và **bóng đèn huỳnh quang. **Ta có thể swap dễ dàng giữa 2 loại bóng vì ổ điện chỉ quan tâm tới interface (đuôi tròn), không quan tâm tới implementation.
Trong code cũng vậy, khi áp dụng Dependency Inverse, ta chỉ cần quan tâm tới interface. Để kết nối tới database, ta chỉ cần gọi hàm Get, Save … của Interface IDataAccess. Khi thay database, ta chỉ cần thay implementation của interface này.
Mình nói khá kĩ về nguyên lí này vì nó khá quan trọng. Về sau mình sẽ viết 1 bài riêng về Dependency Injection ( Dependency Injection chỉ là 1 trong những pattern để hiện thực Dependency Inversion, Dependency Injection != Dependency Inversion nhé các bạn), cùng với 1 số Dependency Injection Framework cơ bản.
Bài viết khá dài, xin có lời khen với các bạn đã kiên nhẫn đọc hết. Ở những bài viết sau mình sẽ giải thích rõ hơn về từng nguyên lý SOLID này, cùng với code mình họa + cách áp dụng nguyên lí vào quá trình code.

Read More »

Thứ Hai, 26 tháng 10, 2015

Tài liệu Beginning Android 4 Application tiếng anh + tiếng việt

Đây là tài liệu Beginning Android 4 Application bản gốc tiếng anh và bản dịch tiếng việt. Download tại đây:
https://drive.google.com/file/d/0Bw8lb9dGe37dbmMtdUVTcXh5bkk/view?usp=sharing


Read More »

Thứ Sáu, 23 tháng 10, 2015

Cách restore file database backup thành một database mới

Bạn đã có một database vngreen được restore từ một file bkup_vngreen_0208_alter.bak . Và giờ bạn muốn restore file backup này thành một database khác minhanh. Đây là cách thực hiện:
- Đầu tiên hãy xem tên file vật lý mdf và ldf của file backup. Trong sql server sử dụng lệnh :

EXEC sp_helpdb 'vngreen'


Bạn có thể thấy VNGreen VNGreen_log chính là tên file của file mdf và ldf.

- Tiếp theo là restore database mới. Sử dụng lệnh:

USE [master]
RESTORE DATABASE [minhanh] FROM  DISK = N'E:\laptrinh\mvc\vngreen\bkup_vngreen_0208_alter.bak' 
WITH  FILE = 1,
MOVE N'VNGreen' TO N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\minhanh.mdf',
MOVE N'VNGreen_log' TO N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\minhanh_log.ldf',  
NOUNLOAD,  STATS = 5

GO

Vậy là bạn đã restore xong! Chúc vui!
Read More »

Thứ Năm, 22 tháng 10, 2015

CKFinder - Cách khắc phục lỗi upload ảnh bị lỗi trên hosting

Bạn phát triển website, sử dụng ckfinder để upload ảnh. Mọi thứ chạy trên localhost rất perfect, nhưng khi bạn deploy chạy trên hosting thì lại không thể upload được ảnh. Bạn nhận được lỗi: "Lỗi khi tải tệp tin".
Lỗi này là do Permision hosting của bạn, khắc phục rất đơn giản. Bạn vào hosting, đến hosting setting và tích vào checkbox "Additional write/modify permissions" -> Save.Vậy là xong :)

Read More »

Thứ Bảy, 10 tháng 10, 2015

Phong cách nhà ưa thích

Ngôi nhà là nơi nghỉ ngơi cuối tuần của đôi vợ chồng doanh nhân tại TPHCM, nhỏ nhưng sang trọng và hết sức tiện nghi.


Chủ nhà muốn ngôi nhà phải đơn giản nhưng ấn tượng, tận dụng mọi không gian. Ánh sáng và thông gió được KTS Phạm Thanh Truyền tính toán kỹ lưỡng. Vì vậy, căn nhà ba tầng một lửng rất nhỏ nhưng thoáng đãng và tràn ngập ánh sáng. Tầng 1 được dành toàn bộ cho không gian phòng khách


Khu bếp, bàn ăn được đặt tại tầng lửng. Toàn bộ trang thiết bị khu bếp cũng được đầu tư cao cấp, sang trọng.


Vì diện tích nhà rất bé, chiều ngang chỉ 3 m nên việc bố trí luôn được cân nhắc kỹ từ chất liệu đến vật dụng


Phòng thư giãn tuy nhỏ và không đầu tư quá nhiều đồ nhưng các thiết bị đều được lựa chọn cẩn thận


Tất cả vật dụng nội thất đều được làm riêng theo kích thước nhỏ hẹp của ngôi nhà.


Vay mượn không gian luôn là thủ pháp được kiến trúc sư sử dụng, nhất là những ngôi nhà bé như thế này.


Đá hoa cương cầu thang được chọn màu sắc trang nhã hài hòa, nguyên khối.


Giải pháp vách ngăn bằng kính cho khu vệ sinh giúp ngôi nhà thoáng rộng hơn kích thước thật. 


Một góc nhỏ tiểu cảnh đặt dưới cầu thang tầng một. "Không gian nhỏ nhưng có sự bố trí chặt chẽ, đầu tư về vật liệu và trang thiết bị là điểm nổi bật của ngôi nhà", KTS Phạm Thanh Truyền chia sẻ.


Phòng vệ sinh nhỏ nhưng đầy đủ trang thiết bị và sử dụng màu sáng, đem lại cảm giác rộng và sạch sẽ.



Sân thượng là nơi cả gia đình thường xuyên quây quần vào cuối tuần.
Read More »

Thứ Năm, 8 tháng 10, 2015

Các cách khai báo function jquery

Introduction

Choosing which way to declare a JavaScript function can be confusing for beginners as there are several different ways to declare functions using JavaScript/jQuery. I’ll try to explain the benefits of each one and how and why you might use them when writing your awesome jQuery code.

1. The basic JavaScript function

This is the simplest way to declare a function in JavaScript. Say for example, we want to write a simple function called multiply(x,y) which simply takes in two parameters x and y, does a simple x times y and returns the value. Here are a few ways you might go about doing exactly this.
function multiply(x,y) {
     return (x * y);
}
console.log(multiply(2,2));
//output: 4
If you wanted a quick function to test something then maybe that’s the only occasion you would use this. It’s not good coding and doesn’t promote code reuse.

2. JavaScript functions for get/set

If you need a private utility for getting/setting/deleting model values then you can declare a function as a variable like this. This could be useful for assigning a variable upon declaration calculated by a function.
var multiply = function(x,y) {
     return (x * y);
}
console.log(multiply(2,2));
//output: 4

//The same function but with a self execution to set the value of the variable:
var multiply = function(x,y) {
     return (x * y);
}(2,2);
console.log(multiply);
//output: 4

3. Create your own jQuery function

This is an awesome way to declare functions that can be used just like your regular jQuery functions, on your DOM elements! Rememeber jQuery.fn is just an alias for jQuery.prototype (which just saves us time when coding such jQuery.fn.init.prototype = jQuery.fn = $.fn as such).
jQuery.fn.extend({
    zigzag: function () {
        var text = $(this).text();
        var zigzagText = '';
        var toggle = true; //lower/uppper toggle
   $.each(text, function(i, nome) {
    zigzagText += (toggle) ? nome.toUpperCase() : nome.toLowerCase();
    toggle = (toggle) ? false : true;
   });
 return zigzagText;
    }
});

console.log($('#tagline').zigzag());
//output: #1 jQuErY BlOg fOr yOuR DaIlY NeWs, PlUgInS, tUtS/TiPs & cOdE SnIpPeTs.

//chained example
console.log($('#tagline').zigzag().toLowerCase());
//output: #1 jquery blog for your daily news, plugins, tuts/tips & code snippets.
Don’t forget to return the element so that you can chain jQuery functions together.

4. Extend Existing jQuery Functions

(or which either extend existing jQuery functions with extra functionality or creating your own functions that can be called using the jQuery namespace (usually, we use the $ sign to represent the jQuery namespace). In this example the $.fn.each function has been modified with custom behaviour.
(function($){

// maintain a to the existing function
var oldEachFn = $.fn.each;

$.fn.each = function() {

    // original behavior - use function.apply to preserve context
    var ret = oldEachFn.apply(this, arguments);
 
 // add custom behaviour
 try {
  // change background colour
  $(this).css({'background-color':'orange'});
  
  // add a message
  var msg = 'Danger high voltage!';
  $(this).prepend(msg);
 }
 catch(e) 
 {
  console.log(e);
 }
 
    // preserve return value (probably the jQuery object...)
    return ret;
}
})(jQuery);

5. Functions in custom namespaces

If your writing functions in a custom namespace you must declare them in this way. Extra functions can be added to the namespace you just need to add a comma after each one (except the last one!). If your unsure about namespacing see jQuery Function Namespacing in Plain English
JQUERY4U = {
 multiply: function(x,y) {
  return (x * y);
 }
}
//function call
JQUERY4U.multiply(2,2);

Conclusion

Knowing when and how to declare different types of JavaScript/jQuery functions is definitely something any good js developer should know inside out.
Read More »

Thứ Tư, 7 tháng 10, 2015

Solution when Like sql does not work

Example, you have query using Like operation, everything seem to be good, but you can not receive any row even you have a row in table tbl_Article which have Title column = 'Thật hài hước quá' .

DECLARE @Keyword NVARCHAR(2000) = N'hài hước'

SELECT  *
FROM dbo.tbl_Article a
WHERE a.Title LIKE N'%' + @Keyword + '%'

This's happen because there is a newline at the end of the label, so 

this is solution:

SELECT  *
FROM dbo.tbl_Article a
WHERE REPLACE(REPLACE(a.Title, CHAR(10), ''), CHAR(13), '') LIKE N'%' + @Keyword + '%'

Or you can update Title column:

UPDATE [page] Set [label] = REPLACE(REPLACE([Title], CHAR(10), ''), CHAR(13), '')


Read More »

Thứ Hai, 5 tháng 10, 2015

Error message when use Compare Attribute MVC

  1. Create a new MVC 5 project with Individual User Accounts.
  2. Look at the ErrorMessage specified in RegisterViewModel for the ConfirmPassword property. It is "The password and confirmation password do not match.".
  3. Build and run the application, and try to register with non-matching passwords. I'll se the error message "'Confirm password' and 'Password' do not match.", instead of the one specified in the model.
It seems like a custom ErrorMessage property on the Compare attribute isn't working. Even if I specify a ErrorMessage, the validation still shows some sort of default message instead.
This work with System.Web.Mvc.CompareAttribute, but this is now deprecated and you should instead use System.ComponentModel.DataAnnotations.CompareAttribute, which shows this problem.
I add the Compare attribute to a property and specify the ErrorMessage as follows:
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match. I'll even add some random text!")]
public string ConfirmPassword { get; set; }
the expected result would be (but this isn't what I get):
Expected result with custom ErrorMessage
Instead, I get this "default" error message:
Actual result with standard ErrorMessage
You have 2 options to solve this bug:
--Option 1
Change:
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
to
[System.Web.Mvc.Compare("Password", ErrorMessage = "Your custom error message")]
--Option 2 (I recommend this one)
We need to update our ASP.NET MVC 5. In your Visual Studio go to the Package Manager Console and type:
PM> update-package
You migh get an error in the:
public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }
That error is caused by the update in the internal structure of MVC 5. To solve that error do this:http://stackoverflow.com/a/23090099/2958543
Read More »