Home Blog Page 108

Dynamic Sharding – Nghệ thuật của locator

Dynamic Sharding – Nghệ thuật của locator

Bài viết được sự cho phép của tác giả Kiên Nguyễn

Tìm hiểu về Scalable Web, App hay bất cứ nội dung nào khác liên quan tới database tất nhiên không thể bỏ qua khái niệm về Dynamic Sharding.

Vậy Dynamic Sharding là gì?. Điều gì làm nên sức mạnh của nó?. Điểm mạnh, điểm yếu.

Tất cả sẽ được phân tích cụ thể qua bài viết dưới đây. Bắt đầu ngay thôi nào!.

  Kết nối Database động với PHP, Dynamic Database Connection!
  Kiểm thử tĩnh vs kiểm thử động (Static vs Dynamic testing)

1. Dynamic Sharing là gì?

Đầu tiên, nhắc tới Sharing là nhắc tới kỹ thuật Scaling. Thường sử dụng cho các hệ thống được thiết kế để scalable (có thể mở rộng một cách nhanh chóng).

Vậy Sharding là gì?

Sharding involves breaking up one’s data into two or more smaller chunks, called logical shards. The logical shards are then distributed across separate database nodes, referred to as physical shards, which can hold multiple logical shards. Despite this, the data held within all the shards collectively represent an entire logical dataset.

Shadring là kỹ thuật sử dụng để phân chia data thành 2 hoặc nhiều hơn các khối nhỏ (chunks), cũng được gọi là logical shards. Các khối logical shards này được phân chia và thuộc về các node database nhỏ. Giống như các khối vật lý, có thể được tồn tại trong đó các khối vật lý. Mặc dù vậy, dữ liệu được giữ trong tất cả các shards đại diện chung cho toàn bộ tập dữ liệu logic.

Má, định nghĩa tiếng việt viết ra khéo đọc không ai hiểu. Tốt nhất là anh em nên đọc tiếng anh. Túm cái váy lại thì với Dynamic Sharding, có 2 loại phổ biến nhất là Horizontal Scaling và Vertical Scaling. Đã được đề cập đầy đủ và chi tiết ở bài viết Toàn tập về thiết kế Scalable Web Application II

Hai kiểu Scaling chính (Horizontal và Vertical Scaling). Nguồn ảnh/ Source: digitalocean.com

2. Locator trong Dynamic Sharding

Dynamic Sharding lại gồm 2 từ. Dynamic và Sharding, từ Sharding thì đã nhắc tới ở phía trên. Còn Dynamic?. Nhắc tới Dynamic phải nhớ tới Locator.

Nếu không có Locator thì không có Dynamic. Nói thì hơi khó hiểu, xem thử ví dụ sau:

Giả sử ta có 3 Shards, mỗi Shards lại nắm một đoạn dữ liệu trong DB (tổng là 100). Thằng A thì giữ từ 1-30, thằng B thì giữ từ 30-60, thằng C thì giữ từ 60-100. Trường hợp client muốn request 35. Làm sao client biết để request tới B (vốn là thằng đang giữ từ 30-60).

Đấy là lúc thằng locator ra tay!

Dynamic ShardingLocator sẽ phán định cho biết DB nào sẽ xử lý request tới từ Client.

Chính vì thằng Locator chịu trách nhiệm “điều đào”, ấy lộn “điều request” nên ta mới có cái chữ Dynamic trong khái niệm. Bất kì request nào từ phía client đều đi qua Locator, được Locator xem xét, phán định nên đi về “chốn nào”.

Dùng một đại ca như Locator anh em thấy có ưu nhược điểm gì không?. Quyền lực quá đôi khi cũng là một cái hại.

3. Điểm yếu, điểm mạnh của locator

Thành phần quan trọng nhất của Dynamic Sharding là locator. Locator như là “chị đại” trong giới giang hồ. Do tất cả các client request đến đều thông qua locator. Tất nhiên, luôn có điểm mạnh và điểm yếu của kiến trúc này.

Nói về điểm mạnh thì locator cho phép client request tới chính xác DB có chưa nội dung đang cần. Client A sẽ không đi lệch tới DB B để tìm nội dung mà nó cần. Với cách truy xuất này, thời gian để client A tới DB B được giảm đi đáng kể.

Vấn đề này đã được đề cập tới trong bài viết Load Balancers II – Determine which servers processes a request. Lựa chọn server nào cho request nào. Đây là điểm mạnh đầu tiên của Dynamic Sharding

Tuy nhiên, do tất cả đều thông qua chị đại. Không tránh khỏi trường hợp chị đại “tèo” thì client cũng ra đi. Anh em giang hồ theo chân chị đại là DB cũng không người dẫn đầu. Như “rắn mất đầu”.

Dynamic Sharding locatorLuôn cần tới một Locator backup trong trường hợp locator chính gặp vấn đề.

Lúc này ta cần tới một Locator backup. Locator này cần đồng bộ với locator chính. Tuy nhiên trong các trường hợp Create hay Update ở DB. Locator này lại chưa đáp ứng được, lúc Locator chính sống lại cần synchronous lại ngay.

4. Khi nào thì nên sử dụng Dynamic Sharding

Do tính chất linh động khi sử dụng kiến trúc Dữ liệu phân tán (Distributed Database). Dynamic Sharding được sử dụng cho các kiến trúc lớn như Google Drive, Mega File. Mỗi file được chia thành các phần nhỏ và lưu trữ ở nhiều nơi.

Khi client yêu cầu nội dung file. Dynamic Sharding có thể phán định chính xác các phần nhỏ của file đang ở đâu, sau đó thực hiện nối ghép các file. Đem đến cho người dùng nội dung hoàn chỉnh.

5. Tham khảo

Cảm ơn vì đã đọc bài – Have a great week – Happy Coding!

Bài viết gốc được đăng tải tại kieblog.vn

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Cách viết thông báo lỗi phù hợp để cải thiện trải nghiệm người dùng

viết thông báo lỗi
Cách viết thông báo lỗi phù hợp để cải thiện trải nghiệm người dùng

Tác giả: Andrico Karoulla

Đã qua rồi cái thời những thông báo lỗi xuất hiện một cách chung chung và gần như vô ích. Nếu bạn quan tâm đến việc làm ra các sản phẩm hướng tới người dùng và giúp cho trải nghiệm của người dùng trở nên thú vị nhất có thể, thì đây chính là bài viết dành cho bạn. Như đã biết, thông báo lỗi đóng một vai trò quan trọng trong số những tác nhân ảnh hưởng đến trải nghiệm người dùng. Những thông báo lỗi dễ nhận diện và có ích chắc chắn sẽ giúp ích rất nhiều cho việc cải thiện những gì mà người dùng tiếp cận.

viết thông báo lỗi
Viết thông báo lỗi như thế nào để tối ưu trải nghiệm người dùng?

1. Trạng thái hiện tại của thông báo lỗi

Trong một thế giới gọi là hoàn hảo, các thông báo lỗi sẽ là thứ dư thừa và người dùng có thể sử dụng bất kỳ thứ gì bạn đã xây dựng một cách dễ dàng. Nhưng, đáng tiếc là không có một thế giới hoàn hảo như thế, lỗi sẽ xảy ra và người dùng cuối chắc chắn sẽ đối mặt với chúng.

Những lỗi này có thể bắt nguồn từ:

  • Xác thực không thành công
  • Lỗi phía máy chủ
  • Giới hạn tỷ lệ

Và khi có sự cố, thông báo lỗi trên giao diện người dùng thường xuất hiện theo một trong hai cách:

Các lỗi chung chung không có thông tin có ý nghĩa, ví dụ: Something went wrong, please try again later

Thông báo quá cụ thể từ dấu vết ngăn xếp được gửi bởi máy chủ, ví dụ: Error 10x29183: line 26: error mapping Object -> Int32

Cả hai dạng thông báo này đều không hữu ích cho người dùng cuối. Đối với users, lỗi chung có thể tạo ra cảm giác bất lực và thất vọng. Nếu họ nhận được thông báo như vậy, họ hoàn toàn không thể làm gì và không có cách nào để biết tại sao lỗi lại xảy ra và làm thế nào (hoặc nếu) họ có thể giải quyết nó. Điều này có thể khiến website hoặc app của bạn mất lòng tin của người dùng cuối, mất khách hàng hoặc bị đánh giá một sao.

Mặt khác, thông báo lỗi quá cụ thể sẽ bị xem là một lỗ hổng về kỹ thuật của công ty bạn và người dùng cuối đương nhiên không nên nhìn thấy. Thứ hai, cũng là điểm đặc biệt, nếu lĩnh vực hoạt động của công ty bạn liên quan nhiều đến các trải nghiệm người dùng thì thông báo lỗi của phải mang tính con người và hướng đến dịch vụ nhiều hơn.

  Laravel 5.6 thêm Collision Package cho CLI Error Report
  3 lỗi javascript thường mắc phải làm ảnh hưởng perfomance

2. Tại sao nên build các thông báo lỗi có tính hỗ trợ cao hơn?

2.1. Giúp các developers làm việc dễ dàng hơn

Kiểm tra nhật ký người dùng mỗi ngày là việc làm khá tẻ nhạt. Nếu người dùng cuối báo cáo lỗi, điều quan trọng là họ phải cung cấp cho chúng ta nhiều thông tin hữu ích nhất có thể.

Một báo cáo từ một người dùng cho biết với mẫu như thế này:

Hi, I was using the app sometime last night updating my profile and all of a sudden it stopped working. The error said something about a validation error, but I don't know what that means

sẽ ít hữu ích hơn nhiều so với:

Hi, I was using the app sometime last night updating my profile and all of a sudden it stopped working. The error said "We had trouble updating your details. Your address must be located within the EU" but I live in England

Điều này giúp các lập trình viên phía sau tiết kiệm được rất nhiều thời gian và cắt giảm sự nghiên cứu để tìm ra chính xác lỗi đó là gì. Một thông báo lỗi rõ ràng và cụ thể cũng có thể giúp người dùng cuối hiểu được bản thân họ đã làm gì sai và có thể cho phép họ sửa chữa lỗi của mình.

2.2. Hoạt động của hệ thống được trơn tru hơn

Đối với những người làm việc trong các công ty lớn hơn, việc sao chép/nhắn tin có thể thuộc trách nhiệm của một bộ phận hoàn toàn riêng biệt. Càng có nhiều vị trí trong mã yêu cầu thay đổi bản sao, bản sao càng dễ trở nên không đồng bộ với các nguyên tắc thương hiệu của công ty.

Ngược lại, việc lưu giữ tất cả các thông báo lỗi của bạn trong một nguồn duy nhất giúp những người sở hữu bản sao tuân thủ các nguyên tắc thương hiệu đó dễ dàng hơn nhiều. Việc khắc phục sự cố với tin nhắn của bạn khi người dùng điền sai biểu mẫu, thiếu dữ liệu hoặc không có quyền cho một hành động cụ thể có thể tác động tích cực đến quá trình làm việc của team.

Xem thêm Làm thế nào để làm theo “Hướng dẫn” một cách thông minh nhất?

2.3. Trải nghiệm của người dùng cuối được thoải mái hơn

Bằng cách cung cấp thông báo lỗi lành mạnh, mong muốn lớn nhất là để không khiến người dùng cuối cảm thấy khó khăn trong quá trình sử dụng. Như đã mô tả trước đó, thông điệp của một thông báo lỗi được xem là hữu hiệu phải hướng đến dịch vụ. Chúng nên hướng dẫn người dùng cách hoàn thành quy trình làm việc, hoặc ít nhất là cho họ biết họ có thể đến đâu và nhận trợ giúp nếu vấn đề nằm ngoài tầm kiểm soát của họ.

Thông báo lỗi đóng một vai trò quan trọng trong việc ngăn chặn điều này, vì chúng có thể hoạt động như người kiểm soát cuối cùng giúp người dùng tránh được việc bị mắc kẹt hoặc thoát khỏi ứng dụng do thất vọng.

Nếu ai đó đang sử dụng sản phẩm của bạn cho mục đích giao dịch như mua vé máy bay hoặc mua sắm trực tuyến và họ bị dừng lại trong quá trình thực hiện một nhiệm vụ mà không có cách nào để tiếp tục, thì khả năng họ rời khỏi trang web của bạn cho một nhiệm vụ khác sẽ tăng vọt. Và cứ thế, việc đánh mất khách hàng sẽ còn kéo theo rất nhiều hệ lụy đáng lo khác.

error messages

3. Thông báo thế nào được xem là thông báo tốt?

Theo cuốn Microcopy: A complete guide, một thông báo lỗi hữu ích phải đáp ứng được một trong số các tiêu chuẩn sau:

  • Giải thích rõ ràng vấn đề
  • Nếu có thể, hãy cung cấp giải pháp để người dùng có thể hoàn tất quá trình
  • Hoặc hướng dẫn người dùng đến với trang web có thể giúp đỡ họ
  • Tạo một tin nhắn dễ hiểu nhất có thể

Ví dụ đơn giản như sau:

  • Chúng tôi đã giới hạn số lần bạn có thể đặt lại mật khẩu của mình mỗi giờ. Bạn có thể thử lại sau.
  • Vui lòng đăng nhập để xem hồ sơ này
  • Chúng tôi không thể tạo hồ sơ của bạn, chỉ cư dân Vương quốc Anh mới có thể sử dụng ứng dụng của chúng tôi.

4. Build một hệ thống báo lỗi hiệu quả bằng cách nào?

Có một open source gọi là sane-error-messages. Chạy công cụ này sẽ tạo ra một repo hoàn toàn mới được thiết kế để chứa thông báo lỗi mặc định. Bạn có thể điều chỉnh các giá trị mặc định, thêm hoặc xóa tin nhắn, sau đó xuất bản nó để sử dụng trong các ứng dụng dành cho khách hàng của mình.

sane-error-messages hoạt động bằng cách tổng hợp tất cả thông điệp của bạn vào một đối tượng JavaScript duy nhất. Key là một code lỗi và value là một thông báo tương ứng. Code lỗi phải giống với code bạn nhận được từ máy chủ của mình, chẳng hạn như POSTS_NOT_FOUND hoặc CONFLICTING_USER_RECORD. Repo thông báo lỗi cho thấy một chức năng nhận thông báo lỗi từ một code bị lỗi.

Nói một cách ngắn gọn:

  • Người dùng “xem tất cả các sản phẩm”
  • Giao diện người dùng thực hiện một yêu cầu mạng
  • Yêu cầu mạng không thành công và trả về mã lỗi “USER_NOT FOUND”
  • Giao diện người dùng yêu cầu thông báo lỗi tương ứng từ error-messages của bạn
  • Giao diện người dùng áp dụng bất kỳ thông tin ngữ cảnh có liên quan nào
  • Giao diện người dùng hiển thị thông tin này cho người dùng cuối

5. Cách thiết lập thông báo lỗi

Nếu bạn gặp bất kỳ sự cố nào trong quá trình hướng dẫn, bạn có thể gửi thông tin sự cố về GitHub.

Bắt đầu bằng cách chạy

yarn global add sane-error-message

sau đó

sane-error-messages create <dirName>

để mở đầu cho project. Làm vậy sẽ tạo ra một module hoàn toàn mới để bạn tùy chỉnh với các thông báo lỗi mặc định của mình. Module mới sử dụng ẩn tsdx để xử lý tất cả các tập lệnh quản lý module, chẳng hạn như chạy, xây dựng và thử nghiệm.

Bạn có thể tìm hiểu thêm về tsdx tại đây.

Tóm lại, nội dung làm việc sẽ phát triển giống như sau:

/* errorCodes.ts: The file that defines each error code like */
const USER_NOT_ADMIN = '403_USER_NOT_ADMIN'

/* defaultErrorMessages.ts: Maps each code to a default message */
const errorCodes {
  // your codes and messages go here...
  [USER_NOT_ADMIN]: "We're afraid only administrators have access to "
}

/* ErrorMessages.ts: The class you'll use to instantiate your error messages object in the consuming project */
class ErrorMessages {
  // You can override default messages with more specific ones
  constructor: (customErrorMessages: Partial<Record<string | number, string>>): ErrorMessages;

  // Pass through an error code to get your custom message
  getErrorMessage: (code: string | number, fallbackMessage?: string): string;

  // Checks to see if the argument is a valid error code and acts as a guard for non-ErrorCode values
  isErrorCode(code: string | number): boolean;

  // Returns the errorCodes object with your custom messages
  messages: Record<ErrorCode, string>
}

type ErrorCode = ValueOf<errorCodes>

6. Cách xử lý thông báo lỗi

Nếu bạn đã tạo một repo có tên custom-error-messages và xuất bản nó lên npm, bạn có thể sử dụng nó trong các ứng dụng của mình bằng cách làm như sau:

import { ErrorMessages } from 'custom-error-messages';

const customErrorMessages = {
  '400_validation': 'Please enter the fields in your form correctly',
};

// Initialise your errorMessages object with your custom messages
const errorMessages = new ErrorMessages(customErrorMessages);

function riskyFunction() {
  try {
    // Throws an error 
    await boom();
  } catch (err) {
    // Get the error code our server sent over
    const { code } = err;
		
    // Get the code's corresponding message
    const message = errorMessages.getErrorMessage(code);
    
    // Display the message to the client
    displayNotification(message);
  }
}

Sau đó, bạn có thể lấy tất cả các code bị lỗi mà phía máy chủ trả về và áp dụng các thông báo tương ứng cho chúng. Khi đã sẵn sàng, bạn có thể xuất bản công cụ của mình lên NPM, sau đó sử dụng nó từ các ứng dụng dành cho khách hàng của bạn.

Lỗi là một trong những vấn đề thường xuyên gặp khi phát triển web, app. Biết cách cải thiện và sửa chữa vấn đề chắc chắn sẽ giúp cho công việc của bạn hoạt động trơn tru và hiệu quả hơn.

Bài viết được phỏng dịch dựa trên bài gốc tại freecodecamp.org

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Cài đặt TestNG trong Eclipse

Cài đặt TestNG trong Eclipse

Bài viết được sự cho phép của tác giả Tô Thị Vân Anh

TestNG là một nền tảng được sử dụng để giúp chúng ta thiết kế tự động test chức năng hoặc unit test trong Java. Eclipse là một trong những IDE rất phổ biến cho phát triển các test trong Java. Và để sử dụng testNG, không phải là bạn sẽ tải về và cài đặt như một cái tool, mà sẽ giống như một cái phần mềm nho nhỏ được cài đặt tích hợp trong Eclipse nha.

Ngày xưa còn chưa biết đến automation, hóng được testNG, thì cứ nghĩ nó là một cái tool độc lập phải cài vào máy mới dùng được. 😦 Giờ thì thông tin nhiều hơn rồi nên chắc không ai bị như mình ngày đấy đâu! hihi

  Hướng dẫn cách kết nối đến Database MySQL trong Eclipse
  A/B testing và những tiêu chí chính để đánh giá sự thành công của ASO

Hôm nay thì mình sẽ hướng dẫn các bạn các bước để cài đặt testNG trong Eclipse nhé!

1. Mở Eclipse IDE. Chọn Help > Install new software… -> Trên màn hình sẽ hiển thị một cửa sổ có tên Install:

Cài đặt TestNG trong Eclipse

2. Nhấn nút Add, màn hình lúc này sẽ hiển thị một popup nho nhỏ, bạn sẽ điền thông tin này vào từng trường tương ứng nhé:

  1. Name: TestNg ( Bạn có thể đặt tên tùy ý chỗ này)
  2. Location: http://beust.com/eclipse/  (Link này thì lấy chính xác nhé! :D)
  3. Nhấn OK

Cài đặt TestNG trong Eclipse

3. Check vào checkbox TestNG vừa hiển thị, sau đó nhấn Next

Cài đặt TestNG trong Eclipse

4. Check đồng ý vào điều khoản liên quan đến bản quyền

Cài đặt TestNG trong Eclipse

5. Lúc này quá trình download diễn ra, và TestNG sẽ được cài đặt sau đó

Cài đặt TestNG trong Eclipse

6. Sau khi quá trình cài đặt ở bước trên đã xong, sẽ có một cửa sổ hiển thị yêu cầu bạn sẽ khởi động lại Eclipse để cập nhật những cài đặt vừa rồi. Bạn chọn Yes để hoàn tất việc cài đặt TestNG.

Cài đặt TestNG trong Eclipse

Rất đơn giản đúng không nào!

Có một cách khác mà bạn cũng có thể sử dụng để cài đặt TestNG cho Eclipse đó là:

  1. Click Help > Eclipse Marketplace…
  2. Gõ TestNG và nhấn Go để tìm kiếm framework
  3. Nhấn Install để cài đặt
  4. Chờ cho đến khi cài đặt xong và khởi động lại TestNG là được

Cài đặt TestNG trong Eclipse

Hi vọng là với các bước đơn giản phía trên bạn có thể cài đặt TestNg một cách dễ dàng và nhanh chóng hơn.

Chúc một đầu tuần tràn đầy năng lượng nha! 😀

Bài viết gốc được đăng tải tại vananhtooo.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

RxSwift 7: Disposing và terminating

RxSwift 7: Disposing và terminating

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

Trong bài trước, chúng ta đã nghiên cứu cách tạo các observables ở những kiểu khác nhau. Ở bài chúng ta nghiên cứu phần xử lý và chấm dứt chúng.

  RxSwift 10: Làm việc với PublishSubjects
  RxSwift 2: Khái niệm cơ bản về lập trình bất đồng bộ

Hãy nhớ rằng 1 observable sẽ không làm gì cho đến khi nó nhận được đăng ký(subscription). Một đăng ký kích hoạt nó phát ra các sự kiện, cho đến khi nó tạo ra 1 sự kiện .error hoặc .completed để kết thúc. Bạn có thể đăng ký nó và chấm dứt nó. Cùng xem ví dụ sau:

example(of: "dispose") {
  // 1
  let observable = Observable.of("A", "B", "C")
  // 2
  let subscription = observable.subscribe { event in
// 3
    print(event)
  }
}
  1. Tạo 1 observable gồm các string
  2. Đăng ký vào observable, phát ra các sự kiện
  3. Hiển thị các sự kiện phát ra

Kết quả:

--- Example of: dispose ---
next(A)
next(B)
next(C)
completed

Để hủy 1 subscribe, ta thêm dispose() cho nó. Và nó ngừng phát ra sự kiện. Thêm đoạn code này vào cuối chương trình:

subscription.dispose()

Quản lý hủy đăng ký rất tẻ nhạt, cho nên RxSwift cung cấp cho chúng ta công cụ để hủy là hàm .disposed(by:), và sẽ tự động gọi dispose mỗi khi đăng ký bị hủy. Cùng xem đoạn code sau:

example(of: "DisposeBag") {
  // 1
  let disposeBag = DisposeBag()
// 2
  Observable.of("A", "B", "C")
    .subscribe { // 3
print($0) }
    .disposed(by: disposeBag)
}
  1. Tạo 1 disposeBag
  2. Tạo 1 observable
  3. Subscibe và hiển thị các sự kiện của nó
  4. Trả về giá trị cho disposeBag

Đây là mẫu mà bạn sẽ sử dụng thường xuyên nhất, tạo và đăng ký 1 observable đồng thời thêm đăng ký vào xử lý disposeBag. Khi bạn quên đăng ký disposeBag cho nó có thể gây rò rỉ bộ nhớ. Tuy nhiên đừng lo lắng, trình biên dịch sẽ cảnh báo cho bạn.

Trong các ví dụ trước, bạn quan sát các sự kiện thông qua sự kiện .next. Cùng xem ví dụ sau:

example(of: "create") {
    Observable<String>.create { observer in
      // 1
      observer.onNext("1")
      // 2
      observer.onCompleted()
    // 3
      observer.onNext("?")
    // 4
      return Disposables.create()
    }
}
  1. Thêm sự kiện .next cho observer
  2. Thêm sự kiện .completed
  3. Thêm sự kiện onNext cho Observer
  4. Trả về 1 disposable

Bạn có nghĩ phần tử onNext “?” có emmit cho subscibers không? Cùng xem ví dụ sau:

example(of: "create") {
    let disposeBag = DisposeBag()
    
    Observable<String>.create { observer in
      // 1
      observer.onNext("1")
      // 2
      observer.onCompleted()
    // 3
      observer.onNext("?")
    // 4
      return Disposables.create()
    }.subscribe(
        onNext: { print($0) },
        onError: { print($0) },
        onCompleted: { print("Completed") },
        onDisposed: { print("Disposed") }
      )
    .disposed(by: disposeBag)
}

Kết quả như sau:

--- Example of: create ---
1
Completed
Disposed

Vì sự kiện complete đã phát ra cho nên sự kiện 3 không thể phát ra nữa. Điều gì sẽ xảy ra khi bạn thêm 1 sự kiện error cho nó? Cùng thêm đoạn code sau vào đầu file:

enum MyError: Error {
  case anError
}

Và thêm đoạn code sau vào giữa .onNext và .onCompleted:

observer.onError(MyError.anError)

Kết quả như sau:

--- Example of: create ---
1
anError
Disposed

Điều gì sẽ xảy ra khi chúng ta không emit ra sự kiện onCompleted và .error cũng như không đăng ký với disposeBag? Sửa lại đoạn code như sau:

example(of: "create") {
  enum MyError: Error {
    case anError
  }
  let disposeBag = DisposeBag()
  Observable<String>.create { observer in
    // 1
    observer.onNext("1")
//    observer.onError(MyError.anError)
    // 2
//    observer.onCompleted()
// 3
    observer.onNext("?")
// 4
    return Disposables.create()
  }
  .subscribe(
    onNext: { print($0) },
    onError: { print($0) },
    onCompleted: { print("Completed") },
    onDisposed: { print("Disposed") }
)
//   .disposed(by: disposeBag)
}

Kết quả như sau:

--- Example of: create ---
1
?

Xin chúc mừng, bạn vừa tạo ra 1 leak memory! Observable sẽ không bao giờ kết thúc, dispose sẽ không bao giờ được sử dụng.

Trong bài tiếp theo chúng ta sẽ học cách tạo 1 observable factories.

Bài viết gốc được đăng tải tại codetoanbug.com

Có thể bạn quan tâm:

Xem thêm Việc làm swift hấp dẫn trên TopDev

Machine learning là gì?

Machine learning là gì?

Bài viết được sự cho phép của tác giả Khiêm Lê

Machine learning là một chủ đề được nhắc đến rất nhiều trong thời gian trở lại đây bên cạnh trí tuệ nhân tạo, nó được ứng dụng cực kỳ nhiều ở thời điểm hiện tại trong hầu hết tất cả các lĩnh vực. Trong bài viết hôm nay, chúng ta sẽ cùng tìm hiểu xem machine learning là gì, các khái niệm cơ bản và vì sao nó lại được ứng dụng rỗng rãi như vậy?

Lưu ý trước khi đọc bài: mình mới vừa tìm hiểu về machine learning không lâu nên sai sót là điều không thể tránh khỏi. Các bạn đọc bài nếu thấy sai đừng quên góp ý dưới phần comment để mình hoàn thiện bài viết tốt hơn nha!

Machine learning là gì?

Tính đến thời điểm hiện tại, có rất nhiều định nghĩa về machine learning, nếu bạn nào từng google thì hẳn các bạn sẽ biết. Mình đã đọc và tổng hợp lại sau đó rút ra khái niệm như sau:

Machine learning (ML) hay máy học là một nhánh của trí tuệ nhân tạo (AI), nó là một lĩnh vực nghiên cứu cho phép máy tính có khả năng cải thiện chính bản thân chúng dựa trên dữ liệu mẫu (training data) hoặc dựa vào kinh nghiệm (những gì đã được học). Machine learning có thể tự dự đoán hoặc đưa ra quyết định mà không cần được lập trình cụ thể.

Bài toán machine learning thường được chia làm hai loại là dự đoán (prediction) và phân loại (classification). Các bài toán dự đoán như dự đoán giá nhà, giá xe… Các bài toán phân loại như nhận diện chữ viết tay, nhận diện đồ vật…

Tham khảo thêm các vị trí tuyển dụng Machine Learning lương cao cho bạn.

Machine learning Workflow

Machine learning workflow sẽ cho bạn thấy quy trình để làm việc với machine learning như thế nào. Hãy nhìn vào sơ đồ bên dưới:

Cụ thể từng bước trong machine learning workflow như sau như sau:

  1. Data collection – thu thập dữ liệu: để máy tính có thể học được bạn cần có một bộ dữ liệu (dataset), bạn có thể tự thu thập chúng hoặc lấy các bộ dữ liệu đã được công bố trước đó. Lưu ý là bạn phải thu thập từ nguồn chính thống, có như vậy dữ liệu mới chính xác và máy có thể học một cách đúng đắng và đạt hiệu quả cao hơn.
  2. Preprocessing – tiền xử lý: bước này dùng để chuẩn hóa dữ liệu, loại bỏ các thuộc tính không cần thiết, gán nhãn dữ liệu, mã hóa một số đặc trưng, trích xuất đặc trưng, rút gọn dữ liệu nhưng vẫn đảm bảo kết quả… Bước này tốn thời gian nhất tỉ lệ thuận với số lượng dữ liệu bạn có. Bước 1 và 2 thường chiếm hơn 70% tổng thời gian thực hiện.
  3. Training model – huấn luyện mô hình: bước này là bước bạn huấn luyện cho mô hình hay chính là cho nó học trên dữ liệu bạn đã thu thập và xử lý ở hai bước đầu.
  4. Evaluating model – đánh giá mô hình: sau khi đã huấn luyện mô hình xong, chúng ta cần dùng các độ đo để đánh giá mô hình, tùy vào từng độ đo khác nhau mà mô hình cũng được đánh giá tốt hay không khác nhau. Độ chính xác của mô hình đạt trên 80% được cho là tốt.
  5. Improve – cải thiện: sau khi đã đánh giá mô hình, các mô hình đạt độ chính xác không tốt thì cần được train lại, chúng ta sẽ lặp lại từ bước 3, cho đến khi đạt độ chính xác như kỳ vọng. Tổng thời gian của 3 bước cuối rơi vào khoảng 30% tổng thời gian thực hiện.
  9 hiểu lầm "ngớ ngẩn" về machine learning
  Chia sẻ cơ bản sử dụng machine learning để giải quyết bài toán.

Phân loại Machine learning

Có rất nhiều cách phân loại machine learning, thông thường thì machine learning sẽ được phân làm hai loại chính sau:

  • Supervised learning: học có giám sát
  • Unsupervised learning: học không giám sát

Ngoài ra, machine learning còn có thể phân làm các loại sau:

  • Semi-supervised learning: học bán giám sát
  • Deep learning: học sâu (về một vấn đề nào đó)
  • Reinforce learning: học củng cố/tăng cường

Mình sẽ chỉ đề cập đến cách phân loại phổ biến nhất là phân làm hai nhóm: học có giám sát và học không giám sát.

Supervised learning

Supervised learning là việc cho máy tính học trên dữ liệu đã được gán nhãn (label), hay nói cách khác, với mỗi đầu vào Xi, chúng ta sẽ có nhãn Yi tương ứng.

Unsupervised learning

Unsupervised learning là cho máy tính học trên dữ liệu mà không được gán nhãn, các thuật toán machine learning sẽ tìm ra sự tương quan dữ liệu, mô hình hóa dữ liệu hay chính là làm cho máy tính có kiến thức, hiểu về dữ liệu, từ đó chúng có thể phân loại các dữ liệu về sau thành các nhóm, lớp (clustering) giống nhau mà chúng đã được học hoặc giảm số chiều dữ liệu (dimension reduction).

Môt số khái niệm cơ bản

Dataset (còn gọi là data corpus hay data stock): là tập dữ liệu ở dạng nguyên thủy chưa qua xử lý mà bạn đã thu thập được ở bước data collection. Một dataset sẽ bao gồm nhiều data point.

Data point: là điểm dữ liệu, mỗi điểm dữ liệu biểu diễn cho một quan sát. Mỗi data point có nhiều đặc trưng hay thuộc tính khác nhau, được chia làm hai loại: dữ liệu số (numerical) và dữ liệu không phải số (ví dụ như chuỗi) (non-numerical/categorical). Data point được biểu diễn thành dòng tương ứng, mỗi dòng có thể có 1 hoặc nhiều dữ liệu (chính là các đặc trưng).

Training data và test data: dataset thường sẽ được chia làm 2 tập này, training data dùng để huấn luyện cho mô hình, test data dùng để dự đoán kết quả và đánh giá mô hình. Có bài toán người ta sẽ cho sẵn hai tập này thì bạn không cần phải chia nữa, đối với bài toán chỉ cho mỗi dataset thôi thì phải chia ra. Thường tỷ lệ giữa tập train và test sẽ là 8/2.

Features vector: là vector đặc trưng, mỗi vector này sẽ biểu diễn cho một điểm dữ liệu trong dataset. Mỗi vector có n chiều biểu diễn các đặc trưng của điểm dữ liệu, mỗi đặc trưng là một chiều và phải là dữ liệu số. Các mô hình chỉ có thể huấn luyện được từ các vector đặc trưng này, do đó dataset cần phải chuyển về dạng một tập các vector đặc trưng (features vectors).

Model: là các mô hình được dùng để training trên một training data theo thuật toán của mô hình đó. Sau đó mô hình có thể dự đoán hoặc đưa ra các quyết định dựa trên những gì chúng đã được học.

Ứng dụng của Machine learning

Machine learning được ứng dụng cực kỳ nhiều trong đời sống hiện nay trong mọi lĩnh vực:

  • Tài chính – ngân hàng
  • Sinh học
  • Nông nghiệp
  • Tìm kiếm, trích xuất thông tin
  • Tự động hóa
  • Robotics
  • Hóa học
  • Mạng máy tính
  • Khoa học vũ trụ
  • Quảng cáo
  • Xử lý ngôn ngữ tự nhiên
  • Thị giác máy tính

Và còn rất rất nhiều lĩnh vực mà machine learning có thể được áp dụng, machine learning tỏ ra cực kỳ hiệu quả, hơn hẳn con người trong cụ thể các lĩnh vực mà chúng được áp dụng.

Ví dụ đơn giản như dự báo thời tiết, người ta sẽ dùng các phép tính và những quan sát, ghi nhận về thời tiết trong quá khứ để dự báo về thời tiết của những ngày kế tiếp. Tuy nhiên sẽ thế nào nếu như có cực kỳ nhiều quan sát được thực hiện, có thể lên đến hàng triệu, hàng tỉ quan sát, lúc đó con người không thể nào thực hiện được việc tính toán trên dữ liệu lớn như vậy. Hơn nữa, việc tính toán với dữ liệu lớn như vậy có thể gặp sai sót và dẫn đến kết quả dự đoán bị sai.

Khi này, việc áp dụng machine learning vào để cho máy tính học các quan sát được ghi nhận trong quá khứ, chúng có thể dự đoán được thời tiết trong tương lai với độ chính xác cao hơn rất nhiều so với con người dự đoán.

Chính vì sự phổ biến và hiệu quả của machine learning, việc bạn biết và học về machine learning chắc chắn là một lợi thế lớn trong thời đại công nghệ 4.0 như ngày nay.

Tổng kết

Vậy là trong bài này, mình đã cùng các bạn tìm hiểu qua về machine learning là gì, các khái niệm cơ bản và ứng dụng của nó. Nếu như bạn thấy bài viết này hay hoặc có đóng góp về bài viết, đừng quên bình luận phía bên dưới để giúp mình hoàn thiện bài viết tốt hơn nha.

Cảm ơn các bạn đã theo dõi bài viết!

Có thể bạn quan tâm:

Xem thêm IT Jobs for Developer hấp dẫn trên TopDev

Thử làm một “lập trình viên Odoo”

Thử làm một

Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng

Odoo là gì?

Ố đù tự mô tả về mình trên GitHub:

Odoo is a suite of web based open source business apps. The main Odoo Apps include an Open Source CRM, Website Builder, eCommerce, Warehouse Management, Project Management, Billing & Accounting, Point of Sale, Human Resources, Marketing, Manufacturing, Purchase Management, … Odoo Apps can be used as stand-alone applications, but they also integrate seamlessly so you get a full-featured Open Source ERP when you install several Apps.

Nó là một bộ các web app phục vụ các công việc trong kinh doanh như quản lý quan hệ khách hàng, quản lý dự án, tính tiền/kế toán, tuyển dụng… đầy đủ đến mức nó là một giải pháp “ERP” cho doanh nghiệp. Odoo là tên mới từ bản 8.0 (giờ đang là 10.0) của phần mềm OpenERP.

  Todo App ASP.NET MVC x Entity Framework
  10 nguyên tắc lập trình nền tảng mà lập trình viên nào cũng cần biết

Đó là nhìn từ phía người dùng. Còn về phía lập trình viên, Odoo là gì?

Ứng tuyển ngay các vị trí Odoo tuyển dụng lương cao trên TopDev

Kiến trúc

Odoo sử dụng kiến trúc server – client.

Mỗi chương trình (webapp), được đóng thành 1 python module (thư mục với file __init__.py), và nằm trong thư mục addons https://github.com/odoo/odoo/tree/10.0/addons

Vài phút làm lập trình viên Odoo

Lấy code về

$ git clone https://github.com/odoo/odoo.git
Cloning into 'odoo'...
remote: Counting objects: 1999445, done.
remote: Compressing objects: 100% (546/546), done.
Receiving objects:  84% (1679534/1999445), 1.47 GiB | 1.33 MiB/s
Receiving objects:  84% (1691261/1999445), 1.47 GiB | 1.27 MiB/s
remote: Total 1999445 (delta 208), reused 258 (delta 105), pack-reused 1998777
Receiving objects: 100% (1999445/1999445), 1.67 GiB | 2.29 MiB/s, done.
Resolving deltas: 100% (1660073/1660073), done.
Checking connectivity... done.
Checking out files: 100% (21097/21097), done.

Yeah, 1.67 GB

Nếu tải sourcecode bằng file zip (không có git)

$ du -h 10.0.zip
121M    10.0.zip

Giải nén file zip rồi cài.

Code Odoo không tuân theo chuẩn PEP8 nhưng khá sạch sẽ và dễ đọc. Tài liệu cho developer đầy đủ, dễ xem. http://www.odoo.com/documentation/10.0/index.html

Đứng ở góc độ của lập trình viên, việc phát triển một “module/addon” cho Odoo không có gì quá khác biệt hay cao siêu so với viết một web app bằng bất cứ framework nào (Django, Flask…), ngoài chuyện clone 1.6GB git repo.

Cài đặt và chạy thử

Code Python cài từ source có một số thư viện yêu cầu lập trình viên phải cài thêm các thư viện C (bằng apt trên Ubuntu):

  • Yêu cầu chung: python-dev
  • lxml: libxml2-dev libxslt1-dev
  • python-ldap: libsasl2-dev libldap2-dev libssl-dev
  • psycopg2: libpq-dev

Phải cài npm để cài less, xem chi tiết tại https://www.odoo.com/documentation/10.0/setup/install.html#setup-install-source

Tạo virtualenv Python2 (Odoo hỗ trợ Python 2.7+, ko hỗ trợ 3), cài các requirements:

$ pip install -r requirements.txt
...

Successfully installed Babel-2.3.4 Jinja2-2.8 Mako-1.0.4 MarkupSafe-0.23 Pillow-3.4.1 PyYAML-3.12 Python-Chart-1.39 Werkzeug-0.11.11 XlsxWriter-0.9.3 beautifulsoup4-4.6.0 decorator-4.0.10 docutils-0.12 ebaysdk-2.1.4 feedparser-5.2.1 funcsigs-1.0.2 gevent-1.1.2 greenlet-0.4.10 jcconv-0.2.3 lxml-3.5.0 mock-2.0.0 ofxparse-0.16 passlib-1.6.5 pbr-3.1.1 psutil-4.3.1 psycogreen-1.0 psycopg2-2.7.1 pyPdf-1.13 pydot-1.2.3 pyparsing-2.1.10 pyserial-3.1.1 python-dateutil-2.5.3 python-ldap-2.4.27 python-openid-2.2.5 python-stdnum-1.6 pytz-2016.7 pyusb-1.0.0 qrcode-5.3 reportlab-3.3.0 requests-2.11.1 six-1.10.0 suds-jurko-0.6 vatnumber-1.2 vobject-0.9.3 xlrd-1.0.0 xlwt-1.1.2

Mặc dù dùng qweb template engine, Odoo vẫn có vài chỗ dùng jinja2 hay Mako template engine:

[2] although it uses a few others, either for historical reasons or because they remain better fits for the use case. Odoo 9.0 still depends on Jinja and Mako.

Sau khi cài

Thử làm một "lập trình viên Odoo"

Giao diện quản lý dự án

Thử làm một "lập trình viên Odoo"

Cảm nhận chung là Odoo vẫn chậm như thời OpenERP, khá ngốn RAM, 180MB cho process Python chạy Odoo, chưa làm gì cả + một đống process chạy postgres.

# ps xau | grep odo[o]
root     26287  0.0  0.0  54104  3640 pts/1    S    11:27   0:00 su odoo
odoo     26288  0.0  0.0  24468  5524 pts/1    S    11:27   0:00 bash
odoo     26766  2.3  2.2 2387728 180068 pts/1  Sl+  11:32   2:16 python ./odoo-bin
postgres 26779  0.0  0.1 303684 12532 ?        Ss   11:33   0:00 postgres: odoo postgres [local] idle
postgres 26796  0.2  0.6 316460 56828 ?        Ss   11:33   0:15 postgres: odoo db1 [local] idle
postgres 26813  0.0  0.5 306484 41576 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26823  0.0  0.5 307428 45272 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26836  0.6  0.9 323972 73628 ?        Ss   11:34   0:37 postgres: odoo db1 [local] idle
postgres 26841  0.0  0.5 306992 42800 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26847  0.0  0.5 307052 41240 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26848  0.0  0.5 306232 41784 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26849  0.0  0.5 306536 41104 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26850  0.0  0.5 306976 43236 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26851  0.0  0.5 306528 44344 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26852  0.0  0.5 306272 41192 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle
postgres 26853  0.0  0.4 306608 39024 ?        Ss   11:34   0:00 postgres: odoo db1 [local] idle

Làm lập trình viên Odoo

Khi vận hành trang tổng hợp việc Python của PyMi, những tin tuyển lập trình viên Odoo hiện lên hàng ngày, lặp đi lặp lại, với mức lương phổ biến trong khoảng 6-10 triệu.

Các nhà tuyển dụng thì lại bắt buộc lập trình viên phải có sẵn kinh nghiệm với Odoo… NOOOOOO!

Chẳng có lập trình viên web Python nào đầu tư vào 1 framework không dùng ở đâu ngoài để phát triển chính Odoo module/addon, họ học Django, Flask. Một lập trình viên Django hay Flask có thể viết Odoo webapp chỉ sau vài tiếng chuyển đổi những kiến thức tương tự sang những thư viện của Odoo framework.

Tại sao anh đòi hỏi thứ không ai có, mà lại trả lương thấp?

Bài viết gốc được đăng tải tại pymi.vn

Có thể bạn quan tâm:

Xem thêm việc làm Developer hấp dẫn trên TopDev

JavaScript có thể làm được nhiều hơn bạn nghĩ!

làm gì với javascript
JavaScript có thể làm được nhiều hơn bạn nghĩ!

Tác giả: Abiola Farounbi

Theo như kết quả nghiên cứu của Stack Overflow trong năm 2020, JavaScript là ngôn ngữ lập trình phổ biến nhất trên thế giới, với hơn 63% các nhà phát triển đã và đang sử dụng nó. JavaScript có kho lưu trữ gói mã nguồn mở lớn nhất trên thế giới (npm) và cũng có nhiều khung và thư viện khác nhau được xây dựng cùng với nó. JavaScript rất dễ bắt đầu vì nó không yêu cầu bất kỳ cài đặt nào để bắt đầu coding.

làm gì với javascript
JavaScript có thể làm nhiều việc hơn so với những gì bạn biết

Phát triển Front-end Web

Front-end web là một hình thức phát triển giao diện người dùng liên quan mà người dùng có thể xem và tương tác được. Có 3 ngôn ngữ chính hiện nay có thể dùng để phát triển front-end: HTML, CSS và JavaScript.

HTML (Ngôn ngữ đánh dấu siêu văn bản) liên quan đến cấu trúc và nội dung của trang web, CSS (Trang tính kiểu xếp tầng) xử lý kiểu dáng.

Và cuối cùng, JavaScript làm cho trang web mang các hiệu ứng động, dễ nhìn hơn. Và điều này có thể được thực hiện theo nhiều cách khác nhau, chẳng hạn như:

Thuyết trình

Bạn có thể tạo băng chuyền và thanh trượt trên trang web một cách dễ dàng bằng cách sử dụng một số thư viện JavaScript như Reveal JS, Swiper JSOwl JS

Với các thư viện này, bạn có thể tùy chỉnh cách trình bày trang web của mình một cách nhanh chóng và không quá phiền phức.

  Sử dụng thuật toán quay lui giải bài toán phân tích số bằng JavaScript

Hình ảnh động

Một trong những cách bạn có thể làm cho trang web của mình trở nên sinh động và hấp dẫn hơn là sử dụng hình ảnh động. Bạn có thể sử dụng chúng trên một trang web theo nhiều cách khác nhau, chẳng hạn như thông qua các chuyển động, sự biến đổi của các đối tượng và rất nhiều điều tuyệt vời khác.

Có một số thư viện ảnh gif để bạn lựa chọn, chẳng hạn như Anime JS, Greensock JS, Mo JSAnimate On Scroll. Đây là tất cả các thư viện được xây dựng bằng ngôn ngữ JavaScript giúp tạo hoạt ảnh của bạn dễ dàng hơn bằng cách sử dụng các khối mã nhỏ hơn.

  10 câu hỏi javascript để nâng cao trình độ

Phát triển Back-end Web

Phát triển back-end liên quan đến phần phía sau của trang web mà người dùng không tương tác trực quan. Đây còn được gọi là phát triển ở phía máy chủ. Phát triển back-end liên quan đến việc tạo cơ sở dữ liệu, API, máy chủ tệp, dịch vụ đám mây, v.v.

Và với việc tạo ra Node.js, một công cụ thời gian chạy JavaScript, giờ đây bạn cũng có thể sử dụng JavaScript để phát triển web back-end. Các khung JavaScript khác nhau đã được xây dựng để đơn giản hóa quá trình phát triển web back-end. Một số trong số đó bao gồm:

  • Express Js: Express là một Web Application framework nổi tiếng nhất dựa trên Node.js. Nó chủ yếu được sử dụng để phát triển Web Applications và API REST.
  • Fastify: Đây là một Server-Side Web Framework tối giản, tập trung nhiều vào trải nghiệm của nhà phát triển và hiệu suất ứng dụng.
  • Koa: Đây là một framework trung gian hiện đại và mạnh mẽ cho các Web Applications và APIs.

Xem thêm việc làm javascript hấp dẫn trên TopDev

coding với javascript
JavaScript hỗ trợ đa dạng các chức năng

Phát triển game

Game là một trong những dự án thú vị nhất mà bạn có thể tạo, vì cả bạn và người dùng cuối đều có thể tận hưởng chúng. Có nhiều cách khác nhau để sáng tạo game mới với ngôn ngữ JavaScript, tùy thuộc vào độ phức tạp của trò chơi.

Bạn có thể xây dựng các trò chơi 2D đơn giản từ đầu bằng HTML, CSS và JavaScript vani. Tham khảo thêm nguồn chia sẻ về vấn đề này: Learn JavaScript by building 7 games by Ania Kubow

Để xây dựng các game có thiết kế phức tạp, cũng như các trò chơi mang tính hiệu quả hơn và nhanh hơn, bạn có thể sử dụng công cụ trò chơi JavaScript để làm cho quá trình này dễ dàng hơn. Một số engines này là Phaser Js, Blyon JsLime Js có thể giúp bạn làm việc dễ dàng hơn.

  9 lỗi JavaScript các lập trình viên hay gặp

Phát triển Mobile App

Phát triển ứng dụng dành cho thiết bị di động đề cập đến quá trình viết phần mềm hoạt động trên thiết bị di động. Nó liên quan đến việc phát triển các ứng dụng có thể được sử dụng trên thiết bị di động.

Bạn có thể sử dụng JavaScript để phát triển các mobile app. Các khung và thư viện Javascript khác nhau đã được xây dựng để tạo các ứng dụng gốc, đa nền tảng và kết hợp bằng JavaScript. Một số trong số đó là:

  • React Native: React Native là một framework mã nguồn mở có thể được sử dụng để xây dựng các cross-platform native apps – ứng dụng gốc đa nền tảng. React Native sử dụng phong cách lập trình khai báo và các thành phần có thể sử dụng lại cho giao diện người dùng.
  • NativeScript: NativeScript là một trong những framework đa nền tảng nổi tiếng nhất giúp bạn phát triển các mobile app cho các nền tảng Android và iOS. Vì nó là một khuôn khổ mã nguồn mở, các nhà phát triển có thể điều chỉnh giao diện người dùng cho nhiều màn hình và thiết bị, đồng thời cũng sử dụng các biến phụ thuộc khác nhau.
  • Ionic: Ionic là một JavaScript framework phổ biến khác để xây dựng các ứng dụng kết hợp. Đối với các nhà phát triển quen thuộc với công nghệ web và phát triển ứng dụng web, việc hiểu cấu trúc của một ứng dụng Ionic rất đơn giản.

Việc chọn JavaScript framework phù hợp cho dự án của bạn phụ thuộc vào ứng dụng bạn đang xây dựng và cũng như nền tảng mà nó dành cho. Vì vậy, hãy chắc chắn chọn một cái dựa trên trường hợp sử dụng của bạn nếu bạn có thể.

JavaScript là một ngôn ngữ đa dụng và có thể được ứng dụng trong nhiều lĩnh vực công nghệ khác nhau. Cá nhân tôi rất đề cao nó và thật sự khuyên bạn nên học JavaScript như một ngôn ngữ lập trình nếu bạn quan tâm đến bất kỳ lĩnh vực nào mà tôi đã chia sẻ ở trên.

Phỏng dịch dựa trên bài viết gốc được đăng tải tại freecodecamp.org

Tìm việc làm IT lương cao trên TopDev ngay!

Rx-MVVM(1): Cấu trúc project – lib manager

Rx-MVVM(1): Cấu trúc project – lib manager

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

Vậy là bạn đã đọc qua về phần detail của khóa học rồi đúng không? Nếu chưa hãy đọc nó tại menu lập trình IOS nhé. Dù sao, chúng ta nên nhắc lại mục đích của hàng loạt bài viết liên quan tới Rx và MVVM trước. Để chúng ta biết chúng ta sẽ đạt được gì sau khi học.

  12 Packages và Libraries của Go cực kì mạnh mẽ mà bạn cần phải biết
  67 tools, libraries và resources giúp Web developer "dễ thở" hơn
Rx-MVVM(1): Cấu trúc project – lib manager
Cây thư mục project

Hãy xem tác giả đã bố trí như nào.

  1. Thư mục Application
  2. Thư mục Common
  3. Thư mục Configs
  4. Thư mục Extensions
  5. Thư mục Managers
  6. Thư mục Models
  7. Thư mục Modules
  8. Thư mục Networking
  9. Thư mục Third Party
  10. Thư mục Resources

Vậy là có tổng 10 thư mục. Chúng ta hãy tìm hiểu lần lượt từng thư mục nhé

1. Thư mục Application

Thư mục này có 3 file:

File AppDelegate.swift:

Hãy để ý dòng code này:

 let libsManager = LibsManager.shared

Ở đây tác giả tạo 1 singleton có tên là LibsManager. Nếu ai chưa biết về singleton, thì nôm na nó là 1 lớp được khởi tạo duy nhất 1 lần, và cho dù có gọi hàm tạo đi bao lần nữa nó cũng chỉ tạo có 1 lần thôi. Người ta hay dùng singleton cho những thứ chỉ được tạo 1 lần duy nhất, như quản lý AppDelegate, loading app… Ai chưa hiểu hãy giành 30 phút để google singleton là gì?

Vậy lớp LibsManager dùng để làm gì? Chúng ta hãy vào class này xem nhé:

Để ý đoạn code này:

if UserDefaults.standard.object(forKey: Configs.UserDefaultsKeys.bannersEnabled) == nil {
            bannersEnabled.accept(true)
        }
Rx-MVVM(1): Cấu trúc project – lib manager
lúc mới chạy app lần đầu

Bạn chạy app lần đầu, hình ảnh này sẽ xuất hiện. Còn các lần tiếp theo, nó không xuất hiện nữa. Và chính dòng code trên điều khiển việc đó.

Các dòng code tiếp theo, liên quan đến Rx:

 bannersEnabled.skip(1).subscribe(onNext: { (enabled) in
            UserDefaults.standard.set(enabled, forKey: Configs.UserDefaultsKeys.bannersEnabled)
            analytics.set(.adsEnabled(value: enabled))
        }).disposed(by: rx.disposeBag)

Bắt đầu mù tịt vì đụng đến Rx rồi. Bắt đầu khó nha. Đến đây thì chúng ta bắt buộc phải đọc về Rx để hiểu nó đang làm gì. Vậy thì hãy để ý tới biến bannersEnabled. Nó được khởi tạo dạng Rx chứ không phải biến thông thường bằng câu lệnh:

let bannersEnabled = BehaviorRelay(value: UserDefaults.standard.bool(forKey: Configs.UserDefaultsKeys.bannersEnabled))

Chúng ta thấy, BehaviorRelay là 1 hàm, có value phía trong là 1 giá trị kiểu boolean. Đọc về help của Xcode như sau:

Summary
BehaviorRelay is a wrapper for BehaviorSubject.
Discussion
Unlike BehaviorSubject it can’t terminate with error or completed.

Đến đây thì đọc không hiểu mô tê gì cả. Bắt buộc chúng ta phải đọc sample ở đâu đó trên mạng. OK, vậy chúng ta cùng tìm hiểu nhé.

Đầu tiên chúng ta tải source tại đây:

https://github.com/codetoanbug/sampleRx/tree/master

Sau đó các bạn mở file RxSample.xcworkspace và xem code trong file ViewController

       let bag = DisposeBag() //0

        let bannersEnabled = BehaviorRelay<String>(value: "code")//1

        bannersEnabled.accept("toan")//2
        bannersEnabled.accept("bug")//3

        let subscriber = bannersEnabled.subscribe { (event) in
            print("event = \(event)")
        } //4

        bannersEnabled.accept("viet")//5
        bannersEnabled.accept("nam")//6

        subscriber.disposed(by: bag)//7

Giải thích từng dòng:

Dòng 1: Các bạn khởi tạo 1 biến bannersEnabled có kiểu là BehaviorRelay. Đúng ra cái này không phải biến thông thường như các bạn đã quen, là nó có giá trị kiểu số 1,2 hay là kiểu string abc.. Mà thằng này có 1 đặc điểm là biến có thẻ phát ra 1 giá trị nào đó theo thời gian thực, cụ thể mình cho nó phát ra được các giá trị string. Giá trị khởi đầu là “code”

Dòng 2, 3: Mình đang ném 2 cái giá trị string “toan” và “bug” vào biến này để nó phát ra – nó như 1 cái đài phát thanh đang nói ra 2 câu đó.

Dòng 4: Mình khởi tạo biến subscriber, biến này dùng để lắng nghe các sự kiện phát ra từ biến bannersEnabled, giống như bạn chọn đúng kênh của đài phát thanh để nghe âm thanh trên kênh. này. Và câu lệnh print để hiển thị những gì mà nó nghe được.

Dòng 5, 6: tương tự dòng 2,3 mình lại phát ra 2 câu nói “viet” và “nam”.

Dòng 7: Các bạn hiểu nôm na là quy tắc dọn dẹp bộ nhớ tự động. Nó dựa vào biến dòng số 0 để dọn dẹp lại, và nôm na nó bắt buộc luôn khi các bạn khởi tạo các subscriber thì đều phải nhờ ông bag này dọn dẹp bộ nhớ khi không dùng nữa. Hiểu thế cho đơn giản.

Kết quả như sau:

event = next(bug)
event = next(viet)
event = next(nam)

Tại sao chúng ta chỉ nghe được 3 câu trên. Đơn giản do thằng bannersEnabled nó bắt đầu nghe tính từ thời điểm cách thời điểm nó đăng ký trước đó 1 tín hiệu, nghĩa là bắt đầu nghe từ từ bug trở đi về sau.

Vậy làm sao ta chỉ muốn nghe mỗi 2 từ viet nam thôi, cách đơn giản là thêm dòng lệnh này thay thế:

let subscriber = bannersEnabled.skip(1).subscribe { (event) in
            print("event = \(event)")
        }

skip(n) ở đây nghĩa là bỏ đi n giá trị phát ra tính từ thời điểm trước đăng ký 1 sự kiện cho đến về sau. Các bạn có thể thay đổi con số để loại bỏ. Ví dụ skip(2) thì nó bỏ từ bug và từ viet, còn nghe được mỗi từ nam.

Ồ! Vậy bạn đã hiểu các biến trên làm gì chưa? Bọn nó phát ra sự kiến, xử lý sự kiện trong hàm subscribe.

Quay trở lại hàm trong dự án của chúng ta, đoạn code trên:

let bannersEnabled = BehaviorRelay(value: UserDefaults.standard.bool(forKey: Configs.UserDefaultsKeys.bannersEnabled))//0
if UserDefaults.standard.object(forKey: Configs.UserDefaultsKeys.bannersEnabled) == nil {//1
            bannersEnabled.accept(true)//2
        }

        bannersEnabled.skip(1).subscribe(onNext: { (enabled) in
            UserDefaults.standard.set(enabled, forKey: Configs.UserDefaultsKeys.bannersEnabled)//3
            analytics.set(.adsEnabled(value: enabled))//4
        }).disposed(by: rx.disposeBag)//5

Dòng 1: lệnh if nếu như kiểm tra cái bannersEnabled chưa có giá trị(app chưa được mở bao giờ) thì gán giá trị bannersEnabled.accept(true) để phát ra tín hiệu rằng nó chưa mở banner bao giờ(dòng 2).

Dòng 3: Nó đăng ký 1 subscriber và bỏ đi 1 skip để loại bỏ giá trị khởi tao ban đầu(dòng 0), chỉ bắt đầu nghe ngóng từ dòng số 2 trở đi.

Vậy khi dòng 2 phát ra sự kiện thì các dòng 3, 4 được thực thi, và nếu mình đoán không nhầm thì nó làm 2 hành động: 1 là gán giá trị để bật banner lên, và chắc chắn ở đâu đó có 1 thằng lắng nghe khi giá trị này thay đổi, để hiển thị UI như hình trên. 2 là nó bật quảng cáo lên, và cũng tương tự, ở đâu đó nhiều thằng subscriber cũng lắng nghe sự thay đổi của biến này để hiển thị UI quảng cáo(adsEnabled nghĩa là bật quảng cáo, từ ads là quảng cáo, enabled là bật lên).

Vậy chúng ta đã hiểu hết logic đống loằng ngoằng trên rồi đúng không? Các bạn bắt đầu hình dung được là Rx sẽ là công cụ giúp chúng ta phát tín hiệu và lắng nghe tín hiệu. Vậy nó có ưu điểm gì:

Ví dụ khi chúng ta bật ads lên, thì mọi UI ở khắp mọi nơi khi hiển thị cho người dùng không cần quan tâm bạn thay đổi ở màn hình nào, đều đồng bộ được giá trị. Nếu bạn làm UIKit thuần, bạn sẽ phải vất vả dùng NSNotificationCenter hay là Protocol hay là closure function để báo hiệu giá trị thay đổi cho các màn khác. Và giả sử bạn có 5 cái màn khác nhau, sub view có, parrent view có, thì câu chuyện đồng bộ hóa dữ liệu trở nên khủng khiếp biết nhường nào 🙁

OK, Rx đáng để học đúng không nào? Vậy chúng ta cùng xem các đoạn code khác nhé.

Chúng ta xem tiếp file LibsManager nhé.

Đoạn code:

func setupLibs(with window: UIWindow? = nil) {
        let libsManager = LibsManager.shared
        libsManager.setupCocoaLumberjack()
        libsManager.setupAnalytics()
        libsManager.setupAds()
        libsManager.setupTheme()
        libsManager.setupKafkaRefresh()
        libsManager.setupFLEX()
        libsManager.setupKeyboardManager()
        libsManager.setupActivityView()
        libsManager.setupDropDown()
        libsManager.setupToast()
    }

Ở đây, hàm setupLibs có các chức năng sau:

setupCocoaLumberjack – vậy nó là gì? Nó là thư viện CocoaLumberjack:

https://github.com/CocoaLumberjack/CocoaLumberjack

Như dòng giới thiệu:

CocoaLumberjack is a fast & simple, yet powerful & flexible logging framework for Mac and iOS.

Vậy nó là 1 thư viện log, chức năng là ghi lại những hoạt động của người dùng trong ứng dụng. Ví dụ người dùng bấm nút, chuyển màn hình, gõ text… bất cứ action nào trên ứng dụng của mình. Điều này nhằm cho developer đánh giá được người dùng hay xem phần nào, màn nào bị crash không, … rất nhiều thứ hay ho mà chúng ta có thể thống kê được qua thư viện này. Nhằm cải thiện app tốt hơn hay triển khai các hoạt động marketing cho app…

Còn về chi tiết, chúng ta sẽ giới thiệu ở 1 vài viết khác về CocoaLumberjack , hoặc bạn có thể tự tìm hiểu dần qua google.

setupAnalytics là gì? Ở đây chúng ta đang nói đến Firebase của Google. Nó có nhiều chức năng lắm, và cụ thể là làm server, realtime, bắn notification cho app, tracking app, quảng cáo… Rất nhiều tính năng mà Google cung cấp cho chúng ta. Và tất nhiên như thông lệ, Google vẫn hay bài cho dùng thử giới hạn, dùng quá thì phải pay 😀 Đúng là ông lớn nên biết làm kinh tế quá ha.

Cụ thể nó như nào, chúng ta sẽ nghiên cứ 1 topic sâu về Firebase sau các bạn nhé.

setupAds là gì? cái tên tiếng Anh cũng nói rằng nó là cài đặt cho phần quảng cáo trong app rồi đúng không. Và ở đây chúng ta dùng quảng cáo của Google.

setupTheme – phần này khá mới trong thời gian gần đây, khi mà các ứng dụng bắt đầu quan tâm tới thị giác của người dùng nhiều hơn. Làm sao mà họ dùng app đỡ hại mắt, và dùng trong đêm tối sẽ theo 1 chế độ màu khác với dùng ban ngày. Người ta đẻ ra dark-mode và light-mode, chính ông lớn apple cũng chơi cuộc chơi này rồi. Nếu bạn đang cầm trên tay 1 thiết bị IOS 13, bạn sẽ hiểu được vào ban đêm, nhiều ứng dụng tự nhiên chuyển màu tối, đễ đơ hại mắt hơn. Hay thậm chí facebook cũng đã bật chế độ này trên appweb của họ rồi. Nó rất nhiều thứ hay ho để học, và trong ứng dụng này chúng ta chỉ cần bấm nút switch đơn giản để chuyển qua lại giữa 2 chế độ.

setupKafkaRefresh – Cái này là gì? Thư viện ở đây:

https://github.com/OpenFeyn/KafkaRefresh

Như readme mà họ viết, thì nó đơn giản là dạng loading khi bạn vuốt xuống ở table để cập nhật data mới, hay gọi là pull to refresh mà các bạn hay thấy trên nhiều ứng dụng. Trông cũng cool ngầu đấy chứ:

một dạng loading của thư viện

setupFLEX – Nó là gì?

OKie, chúng ta lại tìm hiểu thư viện của nó nào:

https://github.com/Flipboard/FLEX

Đọc readme:

FLEX (Flipboard Explorer) is a set of in-app debugging and exploration tools for iOS development. When presented, FLEX shows a toolbar that lives in a window above your application. From this toolbar, you can view and modify nearly every piece of state in your running application.

Chi tiết, bạn đọc readme tiếng Anh, còn ai không thích tiếng anh thì mình tìm thấy 1 bài viết khá đầy đủ ở đây. Nôm na nó là thư viện cho phép xem thông tin mọi thứ của app mà ta đang làm, bao gồm view, thông số biến, hàm, log hay database…

setupKeyboardManager – nghe tên cũng biết là quản lý bàn phím rồi đúng không?

Xem detail thư viện tại:

https://github.com/hackiftekhar/IQKeyboardManager

Như readme viết, thường khi chúng ta build ứng dụng sẽ hay gặp tình trạng bàn phím che mất chữ, không nhìn thấy được. Và thư viện này giúp chúng ta giải quyết vấn đề đó mà không phải viết bất kỳ 1 dòng code nào. Nghe ra gì phết. Okie vậy chúng ta cứ dùng thôi.

setupActivityView – vào phần chi tiết chúng ta thấy 1 đối tượng NVActivityIndicatorView.

Thư viện:

https://github.com/ninjaprox/NVActivityIndicatorView


Hình ảnh thư viện

Như vậy thì chúng ta cũng biết được là nó làm gì rồi đúng không? Đó là các hiệu ứng chờ đợi trên app rất đẹp mắt và cute.

setupDropDown – control bổ sung cho IOS

Thư viện:

https://github.com/AssistoLab/DropDown


Ví dụ về dropDown

Vậy cũng dễ hình dung nó là control bổ sung do IOS mặc định không có.

setupToast – chắc chắn là các thông báo đẩy như android, control bổ sung cho IOS.

Thư viện:

https://github.com/scalessec/Toast-Swift

Rx-MVVM(1): Cấu trúc project – lib manager
Các ví dụ về thông báo đẩy Toast

Khá ok!

Vậy là chúng ta đã dạo qua 1 vòng về file LibsManager – quản lý toàn bộ library của App. Theo mình đây là cách rất thông minh để có thể tập trung lại các thư viện, dễ quản lý và dễ sửa lỗi khi cần.

2. Thư mục Managers

Chúng ta cùng nghiên cứu về cách quản lý các thư viện của tác giả ở bài viết tiếp theo.

Bài viết gốc được đăng tải tại codetoanbug.com

Có thể bạn quan tâm:

Xem thêm Tìm việc Project manager hấp dẫn trên TopDev

Kiểu Enum trong C/C++ (Code ví dụ Enumeration trong C/C++)

Kiểu Enum trong C/C++ (Code ví dụ Enumeration trong C/C++)

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Kiểu Enum trong C/C++ (Code ví dụ Enumeration trong C/C++)

(Xem thêm: Tự học lập trình C, C++ qua code ví dụ)

Enum là gì?

Trong lập trình C/C++, Enum hay Enumeration là kiểu dữ liệu cố định, chỉ cho phép biến nhận số số giá trị nhất định nào đó.

Các giá trị enum có thể coi là một hằng số. Việc sử dụng enum giúp đảm bảo giá trị các biến chỉ nhận các giá trị mong đợi.

Ví dụ: Mình định nghĩa kiểu Enum là dayOfWeek và chỉ nhận các giá trị là ngày trong tuần (từ thứ 2 đến chủ nhật). Mỗi lần có tính toán tới ngày trong tuần thì mình dùng dayOfWeek sẽ giúp tránh các giá trị nằm ngoài khoảng từ thứ hai đến chủ nhât.

  Kiểu enum trong TypeScript: làm việc như thế nào, sử dụng ra sao
  1001 Tips: Con trỏ và hàm (Pointer & Function) trong C++

Tạo Enum trong C/C++

Để tạo enum trong C/C++ ta dùng từ khóa enum với cú pháp sau:

enum ten_enum {trang_thai_1: gia_tri_1, trang_thai_2: gia_tri_2,...}

Ví dụ:

#include<stdio.h> 

enum dayOfWeek{Mon=2, Tue=3, Wed=4, Thur=5, Fri=6, Sat=7, Sun=8}; 

int main()
{
enum dayOfWeek day; 
 day = Wed; 

printf("Wednesday: %d \n",day); 

printf("All day of week: %d - %d - %d - %d - %d - %d - %d", Mon, Tue, Wed, Thur, Fri, Sat, Sun); 

return 0; 
}

Kết quả:

Kiểu Enum trong C/C++ (Code ví dụ Enumeration trong C/C++)

C++ tuyển dụng nhiều vị trí, lương cao, ứng tuyển ngay!

Trường hợp bạn không truyền giá trị cho các trạng thái trong enum thì nó sẽ tự nhận các giá trị tăng dần từ 0. Hoặc tăng dần theo giá trị của trạng thái trước đó.

Ví dụ:

enum dayOfWeek{Mon, Tue, Wed, Thur, Fri, Sat, Sun};

tương đương với:

enum dayOfWeek{Mon=0, Tue=1, Wed=2, Thur=3, Fri=4, Sat=5, Sun=6};

Hay

enum dayOfWeek{Mon, Tue=3, Wed=4, Thur=5, Fri=3, Sat, Sun};

Tương đương với:

enum dayOfWeek{Mon=0, Tue=3, Wed=4, Thur=5, Fri=3, Sat=4, Sun=5};

Lưu ý

Các trạng thái trong một enum có thể có giá trị bằng nhau.

Các trạng thái trong enum chỉ nhận giá trị là kiểu integer.

Trong cùng một phạm vi (scope), thì 2 enum không thể có trạng thái trùng tên.

Bài viết gốc được đăng tải tại codecute.com

Có thể bạn quan tâm:

Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev

Javascript sự khác biệt map và weakmap. What make a different?

Javascript sự khác biệt map và weakmap

Bài viết được sự cho phép của tác giả Kiên Nguyễn

Sự khác biệt map và weakmap luôn là một phần kiến thức cần nắm vững đối với lập trình viên Javascript. Nắm rõ sự khác biệt còn phải hiểu lúc nào nên sử dụng loại nào nữa. Đấy, vô vàn vấn đề cần tìm hiểu.

Tuy nhiên, khó cũng phải hiểu. Vì Data Structure không phải muốn dùng sao cũng được. Ở các System lớn, chỉ cần thay đổi một kiểu của DS thôi cũng gây ra hàng tá vấn đề.

Dữ liệu lớn, request xử lý hàng đống. Memory là thứ cần kiểm soát chặt chẽ để đảm bảo hệ thống luôn vận hành trơn tru. Kieblog hân hạnh giới thiệu bài viết sự khác biệt map và weakmap. Bắt đầu ngay thôi nào!

Tuyển dụng Javascript cho bạn

1. Định nghĩa

Map thì đã quá quen thuộc rồi

The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.

Đối tượng Map lưu cặp key-value (khoá – giá trị) theo thứ tự chèn vào của khoá. Bất kỳ giá trị nào (cả đối tượng (objects) và primitive values) đều có thể sử dụng làm key hoặc value.

WeakMap thì bản thân bao gồm 2 chữ. Weak và Map, hẳn là phải có cái gì đó “yếu hơn” rồi.

The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced. The keys must be objects and the values can be arbitrary values.

Đối tượng WeakMap là collection của các cặp key/value với các key được tham chiếu yếu ớt. Các key phải là đối tượng và các value có thể là bất kỳ giá trị nào. 

Cả Map và WeakMap đều cho phép lưu trữ theo kiểu key-value. Key và uniques và một loạt Value đi kèm. Tuy nhiên vẫn tồn tại một số sự khác biệt map và weakmap.

Javascript sự khác biệt map và weakmap. What make a different
Weak không có nghĩa là yếu. Chỉ “lỏng lẻo” hơn một vài điểm thôi

2. Sự khác biệt Map và Weak Map

2.1 Key Store

Cùng là cơ chế lưu trữ key-value. Nhưng có sự khác biệt rõ ràng về tiêu chuẩn của key.

WeakMap accepts only objects as keys whereas a Map,in addition to objects, accepts primitive datatype such as strings, numbers etc.

WeakMap chỉ chấp nhận kiểu objects đóng vai trò như là key. Trong khi Map, ngoài kiểu Objects, nó còn chấp nhận cả các kiểu nguyên thủy như Strings, Numbers,…

JavaScript
map.set(44, 12);

// Lỗi
weakmap.set(44, 13);

// Lỗi. Không thể tạo WeakMap từ 2D array.
var map_1 = new WeakMap([[1, 2], [4, 5]]);

Mà cái thằng WeakMap này cũng dị. Mấy function hay methods dùng được với map thì không dùng được với Weakmap.

JavaScript
console.log(weakmap.size); //undefined


//loop through the keys in an map
for(var i of map)
{
console.log(i);
}

//loop through the keys in an weakmap doesn't work
for(var i of weakmap)
{
console.log(i);
}

//delete all keys
map.clear();

weakmap.clear(); //but this works

Ngoài chuyện Primitive Type thì còn một vấn đề khác nữa là Memory Leak. Cái này là “cốt lõi”. Có nó mới có chữ Weak trong WeakMap. Khác biệt cốt lõi nhất!

  15 ví dụ sử dụng map, reduce và filter
  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết

2.2 Vấn đề Memory Leak

Memory thì từ xưa đến nay đã luôn là vấn đề cố hữu của Map. Một Map được tạo ra cũng đồng nghĩa với một phần memory được cấp phát. Cấp thì dễ, nhưng đôi khi mấy anh dev lại quên lấy lại phần đó (mặc dù đã sử dụng xong Map).

Sự khác biệt giữa Map và WeakMap lại là vấn đề này. Đây cũng là điểm khác biệt cần nắm rõ để có lựa chọn sáng suốt khi lựa chọn Map hay WeakMap.

Để dễ hiểu hơn thì ta có thể xem xét ví dụ sau:

JavaScript

var map = new Map();
var weakmap = new WeakMap();

(function(){
var a = {x: 12};
var b = {y: 12};

map.set(a, 1);
weakmap.set(b, 2);
})()

Xét như ví dụ phía trên, function tóm gọn lại từ dòng 4 đến dòng 10. Tuy nhiên để access được b = {y: 12}; bên ngoài function scope thực sự là không thể.

Mặc dù cả Map và Weakmap đều là global access variable. Tuy nhiên cơ chế của WeakMap cho phép Garbage collector xóa pointer tới b của chính nó. Bản thân chữa weak mang nghĩa là yếu, liên kết của weak map tới chính đứa con mà nó set vào là liên kết lỏng lẻo.

So “Map” can cause more garbages in memory. We can say that “Map” references are strong pointer whereas “WeakMap” references are weak pointers.

Chính vì vậy Map có thể chiếm dụng khá nhiều về mặt memory. Cũng có thể nói “map” tham chiếu mạnh hơn so với “WeakMap”. Tham chiếu ở đây được hiểu là tham chiếu tới memory được cấp phát.

3. Lúc nào nên xài cái gì?

Không phải ngẫu nhiên mà Javascript ES6 bổ sung thêm WeakMap. Rõ ràng Map luôn có sự bất tiện khi sử dụng.

Javascript sự khác biệt map và weakmap. What make a different
Rõ ràng có sự bất tiện khi sử dụng Map

Vấn đề memory có được dọn dẹp hay không đã là sự khác biệt map và weakmap. Vậy lúc nào ta nên dùng WeakMap?

  • Đầu tiên, ta cần một Map để chứa key-value. Tuy nhiên thời gian sử dụng chỉ gói gọn trong một vài dòng code. Tính toán, mapping xong lại không xài tới Map nữa -> Ưu tiên sử dụng WeakMap.
  • Keeping private data about a specific object and only giving access to it to people with a reference to the Map. A more ad-hoc approach is coming with the private-symbols proposal but that’s a long time from now. Đảm bảo an toàn cho dữ liệu, chỉ cho phép access đối với các đối tượng có tham chiếu và cần sử dụng tới WeakMap.

Chắc sẽ còn một vài trường hợp khác WeakMap trở nên hữu ích. Tui sẽ bổ sung cho mấy ông sau.

4. Tham khảo

Thank for your attention – Have a great day – Happy coding!

Bài viết gốc được đăng tải tại kieblog.vn

Có thể bạn quan tâm:

Xem thêm tìm việc IT hấp dẫn trên TopDev

Bảo mật ứng dụng Java web bởi Spring Security

Bảo mật ứng dụng Java web bởi Spring Security

Bài viết được sự cho phép của smartjob.vn

Chúng mình xin chia sẻ với bạn kỹ thuật bảo mật tiên tiến, mạnh mẽ dành cho Java web sử dụng Spring Security. Bài viết hội tụ các best-practice, các kỹ thuật tối tân nhất hiện nay. Nội dung sẽ hay và khó.

Công nghệ sử dụng (technology-stack)

  • Spring Security
  • Spring Boot
  • Spring Web MVC
  • Gradle (build system)
  • Thymeleaf (template engine)

Công cụ sử dụng

  • IntelliJ IDEA 2016.1.3
  • Apache Tomcat 8.0.35

Trước khi bắt tay thực hiện, Bạn nên đọc các bài viết trên SmartJob:

  • Giới thiệu Spring Boot (để hiểu về Spring Boot)
  • Kiểm tra tính hợp lệ của dữ liệu đầu vào form Spring Web MVC bởi Hibernate Validator  (để hiểu về luồng đi của Spring Web MVC)

Spring Security [1] là bộ khung bảo mật ứng dụng Java web cung cấp cơ chế cấp phép quyền (authorization) và xác thực người dùng (authentication). Sức mạnh của Spring Security thể hiện ở sự dễ dùng, dễ cấu hình, khả năng mở rộng, và khả năng bảo mật ứng dụng mạnh mẽ. Spring Security chống được các kỹ thuật hacking tinh vi:

  • Session fixation (Tấn công chiếm quyền điều khiển session của người dùng) [2]
  • Clickjacking (click chuột tự động, ví dụ click vào nút Like Facebook mà không xin phép người dùng)
  • CSRF (Cross-site request forgery: Tạo truy vấn (request) giả mạo truyền từ trang này sang trang khác)

Mục tiêu

Chúng ta sẽ xây dựng ứng dụng Java web có trang chủ, trang đăng nhập, khu vực bảo mật (chỉ truy cập được sau khi người dùng hợp lệ đăng nhập). Cấu trúc project sau khi hoàn tất sẽ như thế này

Bảo mật ứng dụng Java web bởi Spring Security

Bạn sẽ phải tạo/chỉnh sửa 7 file:

  1. Application.java
  2. MvcConfig.java
  3. WebSecurityConfig.java
  4. dang_nhap.html
  5. khu_vuc_bao_mat.html
  6. trang_chu.html
  7. build.gradle

Sử dụng IntelliJ IDEA để khởi tạo project:

Bảo mật ứng dụng Java web bởi Spring Security

Bộ khung project được dựng trên nền Spring Boot. Bấm chọn Spring Initializr, rồi bấm Next.

Bảo mật ứng dụng Java web bởi Spring Security

Bạn điền thông tin, các tùy chọn vào 10 mục như ảnh chụp màn hình. Bước thứ 11 là bấm nút Next

Bảo mật ứng dụng Java web bởi Spring Security

Chọn và nhặt vào thư viện cần dùng. 3 thành phần tham gia mở rộng ứng dụng Spring Boot là:

  • Security
  • Web
  • Thymeleaf

Phiên bản Spring Boot ổn định, mới nhất tại thời điểm viết bài là 1.3.5.RELEASE

Bảo mật ứng dụng Java web bởi Spring Security

Đặt tên project, chọn vị trí lưu mã nguồn project

Bảo mật ứng dụng Java web bởi Spring Security

Cấu hình cho Gradle build system

Bảo mật ứng dụng Java web bởi Spring Security

InteliJ IDEA và Spring Initializer tự động sinh ra cho bạn cấu trúc thư mục của project. Tìm file build.gradle sửa lại nội dung như sau:

Dòng 10, 29 cho phép chúng ta đóng gói ứng dụng Spring Boot thành file WAR truyền thống. (Nếu để theo mặc định, Spring Boot sẽ đóng gói ứng dụng web thành file JAR thực thi dùng Apache Tomcat nhúng, run trực tiếp, rất đặc sắc. Tuy nhiên theo cách này việc deploy sẽ quá đơn giản đến mức khiến bạn đọc khó hiểu, tại sao không có file WAR mà ứng dụng Java web vẫn chạy).

Tìm Java job lương cao trên TopDev ngay!

Tạo thêm thư mục java trong thư mục src/main, rồi tạo thêm package vn.smartjob.demo_spring.demo_security . Tạo class Application.java

Mã nguồn dưới đây thực chất đã chuyển đổi (convert) ứng dụng Spring Boot nguyên bản (tạo ra file JAR có thể run được) thành ứng dụng web Java truyền thống (đóng gói thành file WAR) bằng cách:

– Dòng 12, class Application  được extends từ class org.springframework.boot.context.web.SpringBootServletInitializer
– Dòng 14 đến 17, phải Override method configure  để đóng gói ứng dụng Spring Boot thành file WAR truyền thống.

  8 công cụ miễn phí để bảo mật khi lập trình phần mềm
  Bảo mật web - Một số kiểu tấn công

Tạo thêm thư mục resources bên trong thư mục src\main. Tạo thư mục templates bên trong thư mục resources.. Sau đó tạo 3 tập tin giao diện (sử dụng Thymeleaf template engine). Các file giao diện sử dụng Thymeleaf. Ở đâu Thymeleaf xử lý (render) ra giao diện, sẽ sử dụng HTML element mà trong đó chứa thuộc tính th:____  . Các thẻ security chèn vào trong giao diện sẽ do Spring Security xử lý.

File trang_chu.html

Dòng 26: Cấp phép truy cập, khởi tạo luồng lo-gic bảo mật.
Dòng 27: Cho phép tất cả người dùng (đã đăng nhập, hay chưa đăng nhập) đều được truy cập trang chủ.
Dòng 30: Nếu người dùng có nhu cầu, đưa người dùng đến trang Đăng nhập.
Dòng 31: Tất cả mọi người dùng đều có quyền tiếp cận (truy cập) trang Đăng nhập.
Dòng 34: Sau khi đăng nhập, người dùng đã được xác thực có thể Đăng xuất.

Dòng 48: Cấp phép người dùng có tên đăng nhập smartjob, mật khẩu 4321, với vai trò (role) là người dùng thông thường (USER). Trên một hệ thống sẽ có nhiều role khác nhau.

Chạy ứng dụng trên Apache Tomcat 8

Bảo mật ứng dụng Java web bởi Spring Security

Chúng ta cố tình nhập sai tên đăng nhập hoặc mật khẩu để kiểm tra thông báo lỗi và kiểm tra khả năng ngăn chặn của Spring Security:
Bảo mật ứng dụng Java web bởi Spring Security

Khi nhập đúng tên đăng nhập: smartjob và mật khẩu: 4321 thì người dùng sẽ truy cập được khu vực bảo mật:

Bảo mật ứng dụng Java web bởi Spring Security

Đăng nhập thành công, người dùng truy cập được khu vực đặc quyền riêng. Thậm chí Trình duyệt web còn hỏi bạn có muốn lưu tên đăng nhập, mật khẩu ứng dụng trong trình duyệt hay không. Để sử dụng tính năng đăng xuất (do Spring Security cung cấp), bạn bấm nút Đăng xuất để kiểm tra việc vận hành của việc xóa thông tin người dùng trên trình duyệt.

Mẹo: Trong quá trình phát triển ứng dụng, có thể bạn phải xóa thông tin đăng nhập lưu trong trình duyệt đi để test khả năng bảo mật. Bạn làm như sau: Trình duyệt Google Chrome, chọn Setting, gõ từ khóa tìm kiếm pri (privacy)

Bảo mật ứng dụng Java web bởi Spring Security

Chọn Content settings… rồi tìm

Bảo mật ứng dụng Java web bởi Spring Security

Chọn All cookies and site data… 

Bảo mật ứng dụng Java web bởi Spring Security

Nhớ bấm nút X rồi sau đó Done để xóa thông tin bảo mật lưu trên trình duyệt, nhằm mục đích chuẩn bị môi trường test ứng dụng Spring Security.

Tải về mã nguồn từ server SmartJob: spring_security hoặc clone/fork từ GitHub: https://github.com/SmartJobVN/spring_security

 Bài viết gốc được đăng tải tại smartjob.vn

Có thể bạn quan tâm:

Xem thêm Việc làm lập trình Java hấp dẫn trên TopDev

Web app là gì? So sánh Website và Web Application

website v

Tác giả: Hillary Nyakundi

Người dùng cuối thường sẽ không phân biệt được những điểm giống và khác nhau của website và web application. Họ chỉ việc nhập URL và sử dụng kết quả tìm kiếm là được. Nhưng với các dev, bạn chính là người build nên các nền tảng này cho người dùng sử dụng. Do đó việc nắm bắt được sự khác nhau này chắc chắn sẽ giúp ích rất nhiều cho công việc.

Web developer Jobs for you in Vietnam

Web Application là gì?

Web Application còn hay được gọi tắt là web app là một phần của phần mềm có thể được truy cập bởi trình duyệt. Nói cách khác, web app là website có chức năng và các yếu tố tương tác.

Các web app có khả năng tùy biến cực cao và có thể thực hiện nhiều tác vụ và chức năng khác nhau. Chúng thường phức tạp hơn và khó xây dựng hơn, đồng thời chúng cần một đội ngũ phát triển phần mềm có kinh nghiệm để tạo ra chúng.

Một số web apps phổ biến hiện nay như Twitter, Facebook, Gmail, Adobe CC và Youtube.

website vs web app
Web Application là gì?

Đặc điểm của Web Application

  • Đa nền tảng
  • Dễ dàng test với các bài kiểm tra automated
  • Được lưu trữ trên đám mây

Bạn sử dụng Web Application để làm gì?

  • Có thể sử dụng trên mọi nền tảng vì chúng hỗ trợ tất cả các trình duyệt hiện đại
  • Bạn không cần phê duyệt từ cửa hàng ứng dụng để có một web app
  • Người dùng có thể truy cập chúng bất kỳ lúc nào, từ bất kỳ đâu
  • Có thể sử dụng trên cả thiết bị di động hoặc máy tính để bàn để truy cập dữ liệu
  • Dễ hiểu hơn vì sử dụng cùng một bộ mã trong toàn bộ ứng dụng

Xem thêm So sánh Single Page App (SPA) vs Progressive Web App (PWA)

Website là gì?

Website là một tập hợp các trang web có liên quan chứa hình ảnh, văn bản, âm thanh, video và hơn thế nữa. Nó có thể bao gồm một trang hoặc nhiều trang và nó cung cấp cả nội dung trực quan và văn bản. Có rất nhiều loại website khác nhau hiện tại trang web giáo dục, cộng đồng, tìm kiếm, viết blog,…

Một số website phổ biến như Wikipedia, Google, Amazon và Craigslist.

website vs web app
Website là gì

Đặc điểm của một Website

  • Thân thiện với người dùng
  • Có thể dễ dàng tìm kiếm bằng công cụ tìm kiếm
  • Hiển thị nội dung chất lượng
  • Có một bố cục dễ điều hướng

Khi nào bạn cần dùng đến website?

  • Bạn có thể cần một trang web để giới thiệu sản phẩm của mình
  • Trang web giúp bạn thiết lập thương hiệu cho doanh nghiệp
  • Giúp tạo ra bằng chứng xã hội để người khác có thể thấy những gì bạn đã và đang làm
  • Sử dụng nó để quảng cáo và nâng cao nhận thức về thương hiệu của mình
  15 thư viện slider jquery miễn phí cho dự án website của bạn
  Cải thiện hiệu năng cho JavaScript Web Application chỉ trong vòng vài bước đơn giản

Sự khác biệt chính giữa Website và Web Application

Sự tương tác của người dùng

Website cung cấp nội dung văn bản và hình ảnh mà người dùng có thể xem và đọc, nhưng điều này không ảnh hưởng đến hoạt động của trang web.

Với web app, người dùng không chỉ xem nội dung trên trang mà còn thao tác dữ liệu. Người dùng có thể tương tác từng người một bằng cách điền vào biểu mẫu hoặc cung cấp dữ liệu cần thiết để tương tác với ứng dụng.

Vấn đề xác thực

Xác thực không phải lúc nào cũng cần thiết cho các website dựa trên thông tin. Người dùng có thể được yêu cầu đăng ký nhận các bản cập nhật thường xuyên để truy cập các tùy chọn bổ sung, và thế là xong.

Các web app cần xác thực vì chúng cung cấp phạm vi tùy chọn và chức năng/tương tác rộng hơn nhiều so với một trang web. Điều này có nghĩa là bạn phải có tên người dùng và mật khẩu để truy cập vào tài khoản của mình.

website vs web app
Một số khác biệt cơ bản giữa website với web application

Tasks và sự linh hoạt

Một website sẽ chỉ hiển thị dữ liệu và thông tin được thu thập trên một trang cụ thể khi người dùng đã tìm kiếm.

Trong một web app, các chức năng cao hơn và phức tạp hơn so với các chức năng của một trang web.

Mục đích sáng tạo

Một website chủ yếu bao gồm nội dung tĩnh. Điều này có nghĩa là thông tin có thể truy cập công khai cho tất cả khách truy cập.

Web app được thiết kế để tương tác với người dùng cuối. Điều này có nghĩa là nếu không có thông tin đăng nhập bắt buộc, bạn có thể không truy cập được vào bất kỳ dữ liệu nào.

  1001 lý do mỗi doanh nghiệp cần có một website riêng cho mình

Deployment

Khi xử lý một website, những thay đổi nhỏ không bao giờ yêu cầu biên dịch lại và triển khai đầy đủ. Bạn chỉ cần cập nhật mã HTML và mọi thứ sẽ được cập nhật.

Trong khi với web app, bạn cần phải biên dịch lại và triển khai lại ứng dụng bất cứ khi nào bạn thực hiện thay đổi.

Phát triển một website là một quá trình tương đối đơn giản. Nhưng việc tạo một web app đòi hỏi kiến ​​thức sâu hơn, nhiều kinh nghiệm hơn và lập kế hoạch nhiều hơn. Do đó, nắm rõ sự khác biệt của chúng giúp bạn hiểu rõ mình cần làm gì và phát triển như thế nào.

Bài viết được phỏng dịch theo bài viết gốc tại freecodecamp.org

Có thể bạn quan tâm:

Xem thêm các vị trí it jobs hấp dẫn trên TopDev

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

Bài viết được sự cho phép của tác giả Kien Dang Chung

Video trong bài viết

Chúng ta có quy trình 3 bước để máy có thể học nhưng trước khi đi đến phần thuật toán, tôi muốn giới thiệu với các bạn một chút về môi trường chúng ta sẽ thực hành viết code Python.

Tham khảo: Jupyter Notebook, công cụ không thể thiếu khi học Python. Bài viết này coi như bạn đã có biết cách sử dụng Jupyter Notebook.

  Vẽ đồ thị trong Python với thư viện Matplotlib
  "Code dễ đọc" là như thế nào?

1. Markdown và LaTex trong Jupyter Notebook

Jupyter Notebook là công cụ thực hiện code Python, không những thế bạn có thể đưa vào văn bản, hình ảnh giúp cho các đoạn code dễ hiểu và có thể chia sẻ với mọi người.

Phần văn bản của Jupyter Notebook có thể đưa vào nội dung rất phong phú với các cú pháp Markdown và LaTex:

  • Markdown là một cú pháp sẽ được phân tích cú pháp thành HTML, nó có thể đưa vào tất các các phần tử của HTML, do đó Notebook của bạn sẽ không khác gì một trang web cả.
  • LaTex là công cụ đánh dấu và hiển thị cho các công thức toán học và khoa học. Bạn thử xem hai hàm số này, cái nào dễ nhìn hơn: y = x^2 + 2x + 1 và y=x2+2x+1y=x2+2x+1.

Trang web bạn đang xem All Laravel được chúng tôi xây dựng trên nền tảng OctoberCMS cũng đang sử dụng các công cụ như Markdown và LaTex để biên soạn nội dung các bài viết mà bạn đang xem.

1.1 Cú pháp Markdown

Có khá nhiều cú pháp trong Markdown nhưng tôi sẽ giới thiệu sơ qua một số cú pháp hay dùng nhất:

Tiêu đề: Trong HTML chúng ta có các thẻ tiêu đề từ H1 đến H6 thì trong Markdown, chúng ta thực hiện định dạng một câu thành tiêu đề bằng dấu # ở trước. Ví dụ:

# Đây là tiêu đề H1 
nó sẽ tương ứng với 
<h1>Đây là tiêu đề H1</h1>

Muốn có tiêu đề H2 chúng ta sử dụng hai dấu ##, H3 tương ứng với ###…

Định dạng văn bản: Một số định dạng phổ biến như viết đậm, viết nghiêng trong Markdown sẽ như sau:

**Đoạn này chữ đậm** 
nó sẽ tương ứng với 
<strong>Đoạn này chữ đậm</strong>

*Đoạn này chữ nghiêng*
nó sẽ tương ứng với 
<em>Đoạn này chữ đậm</em>

Danh sách: Có hai loại danh sách là danh sách có thứ tự với số ở đầu (ol) và danh sách không có thứ tự (ul). Trong Markdown các danh sách được viết khá dễ dàng:

* Python
* C#
* PHP

Tương đương với

<ul>
    <li>Python</li>
    <li>C#</li>
    <li>PHP</li>
</ul>

Kết quả thực tế như sau:

  • Python
  • C#
  • PHP

Tương tự với danh sách có thứ tự, chúng ta chỉ cần viết như khi đánh văn bản hay dùng:

1. Python
2. C#
3. PHP

Tương đương với

<ol>
    <li>Python</li>
    <li>C#</li>
    <li>PHP</li>
</ol>

Kết quả thực tế như sau:

  1. Python
  2. C#
  3. PHP

Có rất nhiều các cú pháp trong Markdown, bạn có thể tìm hiểu thêm trên mạng với từ khóa Markdown syntax, ở đây tôi chỉ giới thiệu để bạn hiểu được Markdown là gì? Bản chất Markdown là một ngôn ngữ đánh dấu trung gian, nó khá tiện dụng khi viết nội dung đặc biệt với các tài liệu khoa học. Các hệ thống hỗ trợ Markdown sẽ thực hiện theo thứ tự như sau:

Markdown -> HTML -> Hiển thị nội dung cho người dùng.

1.2 Cú pháp LaTex

LaTex nhận dạng nội dung bên trong một đoạn văn bản là công thức hay không thông qua thẻ $ và $$.

  • Với $, nội dung bên trong sẽ là biểu thức nằm trên cùng một dòng với văn bản ở ngoài.
  • Với $$ nội dung bên trong là biểu thức sẽ được trình bày ở giữa một dòng mới.

Ví dụ: Phương trình hàm parabol y=3x2+2x+1y=3×2+2x+1 là dạng cùng dòng (inline) với thẻ $ trong LaTex. Nhưng biểu thức sau đây lại sử dụng $$:

i=0ni2=(n2+n)(2n+1)6∑i=0ni2=(n2+n)(2n+1)6

Chỉ số trên và chỉ số dưới: sử dụng _ cho chỉ số dưới và ^ cho chỉ số trên. Ví dụ: $x^2$ sẽ có kết quả là x2x2, $n_i$ sẽ có kết quả là nini và kết hợp cả hai $\theta_0^{(i)}$ sẽ cho kết quả là θ(i)0θ0(i). Các biểu thức toán sẽ rất đẹp phải không bạn.

Tổng, tích phân: Với tổng chúng ta sử dụng \sum, tích phân là \int với các chỉ số trên và chỉ số dưới giống như ở phần trên. Ví dụ: $\sum_{i=0}^ni^2$ cho kết quả ni=0i2∑i=0ni2. Ví dụ khác về tích phân $$\int_0^{\frac{\pi}{4}}\sqrt{1-x^2}dx$$ cho kết quả

π401x2−−−−−√dx∫0π41−x2dx

Phân số: Phân số trong LaTex sử dụng cú pháp $\frac{a}{b}$, ví dụ $\frac{(n^2+n)(2n+1)}{6}$ cho kết quả (n2+n)(2n+1)6(n2+n)(2n+1)6.

Trên đây là một số cú pháp cơ bản khi biểu diễn các biểu thức toán học với LaTex, bạn có thể xem nhiều các công thức toán học khác có thể được biểu diễn bằng LaTex ở đây.

1.3 Đệ nhất lẩu Jupyter, Markdown và LaTex

Với sự kết hợp của Markdown và LaTex chúng ta có thể biểu diễn các thuật toán với các biểu thức toán học kết hợp với các nội dung diễn giải tuyệt vời. Không chỉ có vậy, Jupyter Notebook là một tài liệu có chứa cả các cell có code Python có thể thực thi được, bạn thấy đấy, giờ đây chúng ta chỉ cần 1 chỗ vừa có thể xem các diễn giải các công thức và dưới đó là các phần code thực hiện và xem các kết quả chương trình đưa ra. Có thể nói ĐỆ NHẤT LẨU JML (Jupyter-Markdown-LaTex) đã mang lại cho chúng ta những lồi nẩu cực cực cực … cực kỳ hấp dẫn.

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

2. Vẽ đồ thị trong Python

Các cụ nhà ta có câu:

Trăm nghe không bằng một thấy.

Cho thấy tầm quan trọng của việc biểu diễn dữ liệu bằng các biểu đồ, đồ thị. Trong phần này, chúng ta sẽ thực hiện vẽ đồ thị các hàm số trong Python, nó giúp cho các thuật toán lằng nhằng có thể được diễn tả bằng hình ảnh một cách dễ hiểu nhất.

Trong hệ sinh thái Python, có rất nhiều các thư viện bên thứ 3 được phát triển dưới dạng mã nguồn mở, rất phổ biến và cực hữu ích khi làm việc với Python. Trong phần này tôi giới thiệu với bạn hai thư viện được dùng khá nhiều trong Khóa học Machine Learning này đó là Numpy và Matplotlib.

  • Numpy: giúp thao tác với các mảng đa chiều, sinh dữ liệu và thực hiện các phép biến đổi dữ liệu dễ dàng hơn.
  • Matplotlib: thư viện giúp bạn mô phỏng dữ liệu thành các biểu đồ, đồ thị, thư viện không thể thiếu khi bạn thực hiện phân tích dữ liệu.

Nói thì nghe cao siêu vậy thôi, chúng ta cùng bắt tay vào một ví dụ vẽ đồ thị, bạn sẽ thấy các thư viện này rất dễ sử dụng. Trong bài trước, bạn đã nghe đến khái niệm về hàm chi phí hay hàm mất mát (từ giờ tôi sẽ chỉ dùng tên gọi Hàm chi phí), đó là cơ sở để tính toán các sai lệch khi đưa ra các giá trị khởi tạo trong bước 1 của Quy trình 3 bước trong Machine Learning. Chúng ta cần vẽ đồ thị của hàm chi phí để có thể tìm được các điểm cực tiểu mà tại đó là lời giải của thuật toán Grandient Descent.

2.1 Phương thức plot()

Giả sử chúng ta có một hàm chi phí y=x2+x+1y=x2+x+1, chúng ta sẽ vẽ hàm chi phí này để có thể tìm hiểu về điểm cực tiểu, nơi mà chi phí thấp nhất (Chi phí – cost, ở đây không có nghĩa là mất mát về tiền, chi phí ở đây với ý nghĩa là …). Bắt đầu thôi:

Đầu tiên, chúng ta thực hiện import các thư viện cần thiết:

import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

Hai dòng đầu tiên là import các thư viện matplotlib và numpy, dòng %matplotlib inline là một câu lệnh của Jupyter Notebook, nó giúp vẽ các đồ thị bên trong các cell. Tiếp đó, để vẽ được hàm y=x2+x+1y=x2+x+1 chúng ta sẽ sử dụng phương thức plot() của pyplot là một module trong matplotlib mà ta đã đặt tên ngắn gọn là plt.

Phương thức plot() giúp vẽ một danh sách các điểm thành một đồ thị, phương thức này có nhiều tham số nhưng chúng ta chỉ quan tâm đến tham số x và y là hai danh sách (Python List) với giá trị là tọa độ x và y.

Ví dụ:

x_list = [0,2,7]
y_list = [1,8,9]

plt.plot(x_list, y_list)
plt.show()

Kết quả khi thực thi chúng ta có đồ thị như sau:

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

Chú ý, phương thức plot() trả về một đối tượng Python do đó để thực sự vẽ ra đồ thị, chúng ta cần gọi phương thức show().

2.2 Tạo dữ liệu mẫu với numpy

Bạn thấy đấy, chúng ta có 3 điểm là (0,1) (2,8) và (7,9), ở đây chúng ta đưa hết giá trị trên tọa độ x vào biến x_list và trên tọa độ y vào y_list. plot() đã vẽ ra ba điểm này và giữa hai điểm liên tiếp nó vẽ một đường thẳng. Ok, vậy chúng ta có thể vẽ phương trình y=x2+x+1y=x2+x+1 như thế nào? Chẳng lẽ chúng ta phải tự tạo ra dữ liệu là danh sách các tọa độ x, y này, như thế thì thật mất nhiều công sức, chưa kể là giữa hai điểm ở đây là một đường thẳng, như vậy đồ thị vẽ ra cũng không trơn tru vì chỉ là một đường nối các điểm với nhau.

Không có vấn đề gì, chúng ta vẫn còn Numpy, bạn nhớ chứ, chúng ta đã import thư viện này vào nhưng chưa sử dụng đến. Trong numpy có phương thức linspace() cho phép tạo ra một mảng số với số lượng phần tử cho trước và nằm trong một phạm vi cho trước.

x_1 = np.linspace(start=-3, stop=3, num=100)

Dòng code này sẽ tạo ra một mảng gồm 100 phần tử chạy trong khoảng [-3,3] với giá trị các phần tử cách đều nhau.

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

2.3 Vẽ đồ thị hàm parabol

Ok, chúng ta đã tạo ra được dữ liệu mẫu cho trục x trong khoảng từ [-3, 3], giờ là lúc cần định nghĩa hàm y=x2+x+1y=x2+x+1 trong Python và tính ra các giá trị cho trục y tương ứng với các giá trị trục x.

def f(x):
    return x**2 + x + 1
y_1 = f(x_1)

Kết quả ta có biến y_1 là một mảng các giá trị hàm số y=x2+x+1y=x2+x+1 tương ứng với x tại các giá trị trong mảng x_1.

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

Ok, dữ liệu cho các trục x, y đã chuẩn bị xong, giờ chúng ta sẽ vẽ đồ thị y=x2+x+1y=x2+x+1.

plt.plot(x_1, y_1)
plt.show()

Kết quả chúng ta có đồ thị y=x2+x+1y=x2+x+1 như hình dưới đây:

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

Đồ thị đã rất đẹp, nhưng chúng ta vẫn cần định dạng lại chút, ví dụ thêm nhãn cho các trục tọa độ, giới hạn tọa độ hiển thị:

plt.xlim(-3, 3)
plt.ylim(0, 8)
plt.xlabel('X', fontsize=16)
plt.ylabel('f(x)', fontsize=16)
plt.plot(x_1, y_1)
plt.show()

Trong đoạn code trên, xlim() và ylim() để giới hạn vùng tọa độ sẽ hiển thị trên trục x và y, xlabel() và ylabel() để gán nhãn cho các trục tọa độ, kết quả chúng ta được đồ thị mới như sau:

Tạo dữ liệu và vẽ đồ thị với Numpy và Matplotlib

2.4 Vài lời tâm sự

Đồ thị hàm parabol y=x2+x+1y=x2+x+1 rất đẹp được vẽ lên từ 100 điểm nối với nhau. Chúng ta thấy đường parabol rất trơn tru vì trong một khoảng ngắn có tới 100 điểm thì các điểm gần như sát với nhau do đó chúng ta không cảm nhận được những đoạn thẳng nối từng hai điểm liên tiếp.

Bạn sẽ đặt câu hỏi, tại sao tôi chọn khoảng [-3, 3] để vẽ đồ thị, thực ra khi vẽ chúng ta sẽ phải dò dẫm chút, đưa ra một khoảng bất kỳ và chỉnh dần về khoảng sao cho đồ thị có những điểm đặc biệt nằm chọn trong đó. Khi vẽ bạn cũng chọn số điểm vừa phải, nếu thấy chưa trơn tru thì tăng dần lên tránh việc máy tính phải tính toán nhiều, đó là thói quen cần thiết của những người làm về khoa học dữ liệu.

Một thực tế nữa là khi làm việc với data science, chúng ta chỉ luôn tính xấp xỉ chứ không thể có những con số tuyệt đối như khi học toán học. Những con số xấp xỉ đã có một giá trị rất cao mặc dù nếu khi thi toán, giải kết quả xấp xỉ là bạn bị điểm 0 liền. Ví dụ, khi tính toán một phương án đầu tư, chỉ cần cho kết quả cỡ 60-70% là đã coi như 100% chứ không như trong toán, lúc nào cũng phải 1+1=21+1=2.

3. Bài tập

Nhân tiện về chủ đề vẽ đồ thị và khảo sát hàm số, một chủ đề rất thích hợp với chương trình toán trong Phổ thông trung học. Mình đưa ra một số bài tập ở đây để mọi người vẽ và hồi tưởng về một thời mài đít quần trên ghế nhà trường :D.

Bài tập: Soạn một notebook trên Jupyter bao gồm cả đề bài, vẽ đồ thị với Python.

Cho đồ thị hàm số y=14x332x2+5y=14×3−32×2+5

  1. Khảo sát sự biến thiên, vẽ đồ thị đã cho.
  2. Tìm giá trị của m để phương trình x36x2+m=0x3−6×2+m=0 có 3 nghiệm phân biệt.

Hehe, giải kiểu gì cũng được nhé, miễn là ra kết quả, kể cả kết quả gần đúng. Lời giải có trong bài tiếp theo nhé.

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Sử dụng Dead Letter Exchange trong RabbitMQ

Sử dụng Dead Letter Exchange trong RabbitMQ

Bài viết được sự cho phép của tác giả Giang Phan

Dead Letter Exchange trong RabbitMQ

Dead Letter Exchange là gì?

Dead Letter là một tin nhắn không thể gửi đến người nhận. Dead Letter Queue (DLQ), là hàng đợi chứa tin nhắn chưa được gửi, không thể được gửi đến đích của chúng vì lý do này hay lý do khác.

Trong hàng đợi tin nhắn, DLQ là một dịch vụ được cài đặt để lưu trữ các tin nhắn đáp ứng một hoặc nhiều sự kiện sau:

  • Tin nhắn bị từ chối (rejected) bởi một Queue Exchange.
  • Message hết hạn (expire) do Time to live (TTL).
  • Vượt quá giới hạn chiều dài hàng đợi (length limit).
  Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud
  Sử dụng binding Exchange to Exchange trong RabbitMQ

Dead Letter Exchange là một Exchange bình thường, có thể là một trong 4 loại Exchange (Direct, Fanout, Topic, Headers).

Điều gì xảy ra với Dead Letter Message?

  • Gửi tới một Dead Letter Exchange.
  • Thêm một số thông tin vào header của Message trước khi gửi đến Dead Letter Exchange.

Cấu hình Dead Letter Exchange sử dụng Optional Queue Arguments

Để gán một Dead Letter Exchange cho một Queue sử dụng agruments x-dead-letter-exchange khi định nghĩa Queue.

channel.exchangeDeclare("gpcoder.exchange.name", "direct");

Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "gpcoder.exchange.name");
channel.queueDeclare("GPCoderQueue", false, false, false, args);

Đoạn code trên đơn giản tạo một Exchange mới gọi là gpcoder.exchange.name và Exchange mới này là Dead Letter Exchange cho hàng đợi mới được tạo. Lưu ý rằng Exchange  không phải được khai báo khi hàng đợi được khai báo, nhưng nó phải tồn tại tại thời điểm các Message được Dead Letter, nếu không thì các Message sẽ bị hủy bỏ.

Theo mặc định RabbitMQ sẽ lấy khoá định tuyến từ Message ban đầu được gửi đến Exchange. Chúng ta cũng có thể chỉ định một khóa định tuyến sẽ được sử dụng khi Dead Letter Message nếu muốn.

args.put("x-dead-letter-routing-key", "some-routing-key");

Routing Dead-Lettered Message

Dead-lettered message được định tuyến tới Dead Letter Exchange theo thứ tự ưu tiên sau:

  • Theo khoá định tuyến được chỉ định cho hàng đợi Dead Letter Message được chỉ định.
  • Theo khoá định tuyến ban đầu Message được publish.

Ví dụ: Nếu một Message ban đầu được publish đến Exchange với khoá định tuyến foo. Sau đó Message này bị reject và nó trở thành một Dead Letter Message. Và nó được publish đến Dead Letter Exchange với khoá định tuyến foo. Giả sử chúng ta đã chỉ định một khóa định tuyến sẽ được sử dụng khi Dead Letter Message là bar, lúc này Message được publish đến Dead Letter Exchange với khoá định tuyến bar.

Dead-lettered message được re-published với tính năng publisher confirm được bật mặc định để đảm bảo rằng Dead-letter queue phải gửi xác nhận Message (ack) đã được lưu trữ trước khi nó bị xoá ở Queue gốc.

Message bị thay đổi như thế nào khi chuyển sang Dead-Lettered Message?

Header bị thay đổi:

  • Exchange name bị thay thế bởi Dead-letter exchange name.
  • Routing key có thể bị bởi một Routing key khác.
  • Nếu điều trên xảy ra, thì CC và BCC header cũng sẽ bị remove.

Thêm header x-death, với một mảng các giá trị:

  • queue: tên của Queue mà Message được publish trước khi nó trở thành Dead-Lettered Message.
  • reason: lý do xảy ra Dead-Lettered Message. Có thể là: rejected, expired, maxlen.
  • time: thời gian Message bị dead lettered.
  • exchange: tên Exchange mà Message được publish, nó có thể là dead letter exchange nếu Message bị dead lettered nhiều lần.
  • routing-keys: là routing key (bao gồm CC keys nhưng không bao gồm BCC keys) của Message được publish.
  • count: số lần mà Message bị dead-lettered trong Queue này vì lý do này.
  • original-expiration: nếu Message bị dead-lettered vì lý do TTL, nào là giá trị của thuộc tính expiration ban đầu của Message. Thuộc tính expiration sẽ bị remove từ dead-lettering message để ngăn việc expiring lần nữa trong Queue mà nó được định tuyến đến.

3 header được thêm cho mỗi dead-lettering event đầu tiên:

  • x-first-death-reason
  • x-first-death-queue
  • x-first-death-exchange

Chúng có cùng các giá trị như reason, queue, và exchange của event xảy ra Dead-Lettered ban đầu. Sau khi thêm, các header này không bao giờ được sửa đổi.

Lưu ý rằng: mảng giá trị x-death được sắp xếp gần đây nhất trước, do đó, Dead-Lettered gần đây nhất sẽ được ghi lại trong mục đầu tiên.

Ví dụ sử dụng Dead Letter Exchange trong RabbitMQ

Trong ví dụ này tôi sử dụng Dead Letter Exchange để mô phỏng trường hợp Retry xử lý sau mỗi 300 millisecond nếu ngay lần nhận Message đó không thể xử lý thành công.

Sử dụng Dead Letter Exchange trong RabbitMQ

  1. Tạo một WorkQueue và bind đến WorkExchange.
  2. Tạo một RetryQueue và bind đến RetryExchange.
    • Gán agruments: x-dead-letter-exchange đến WorkExchange
    • Gán agruments: x-message-ttl là 300 ms.
  3. Producer publish một Message đến WorkExchange. Sau đó, WorkExchange sẽ chuyển Message đến WorkQueue.
  4. Consumer nhận Message từ WorkQueue và cố gắng xử lý nó.
  5. Trường hợp xử lý thất bại, Consumer sẽ publish Message đó đến RetryExchange. Sau đó, RetryExchange sẽ chuyển Message đến RetryQueue.
  6. Message sẽ lưu tại RetryQueue trong 300 ms.
  7. Khi Message bị expire, nó sẽ được chuyển đến WorkExchange và được chuyển đến WorkQueue.
  8. Khi đó Consumer có thể nhận lại Message từ WorkQueue và xử lý lại.

Hãy xem code implement:

package com.gpcoder.deadletterexchange;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

public class App {

// Exchange
private static final String WORK_EXCHANGE_NAME = "GPcoder.WorkExchange";
private static final String RETRY_EXCHANGE_NAME = "GPcoder.RetryExchange";

// Queue
private static final String WORK_QUEUE_NAME = "WorkQueue";
private static final String RETRY_QUEUE_NAME = "RetryQueue";

private static final int RETRY_DELAY = 300; // in ms

private static Channel channel;
private static int RETRY_COUNT = 0;

public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();

channel = connection.createChannel();

// Create the WorkQueue
channel.exchangeDeclare(WORK_EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true);
channel.queueDeclare(WORK_QUEUE_NAME, true, false, false, null);
channel.queueBind(WORK_QUEUE_NAME, WORK_EXCHANGE_NAME, "", null);

// Create the RetryQueue
Map<String, Object> arguments = new HashMap<>();
arguments.put("x-dead-letter-exchange", WORK_EXCHANGE_NAME);
arguments.put("x-message-ttl", RETRY_DELAY);
channel.exchangeDeclare(RETRY_EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true);
channel.queueDeclare(RETRY_QUEUE_NAME, true, false, false, arguments);
channel.queueBind(RETRY_QUEUE_NAME, RETRY_EXCHANGE_NAME, "", null);

// basicPublish - ( exchange, routingKey, basicProperties, body)
String message = "GPCoder Message";
System.out.println("[" + LocalDateTime.now() + "] [Work] [Send]: " + message);
channel.basicPublish(WORK_EXCHANGE_NAME, "", null, message.getBytes());

consumer(WORK_QUEUE_NAME);
}

private static void consumer(String queueName) throws IOException {
// basicConsume - ( queue, autoAck, deliverCallback, cancelCallback)
DeliverCallback deliverCallback = (consumerTag, message) -> {
String content = new String(message.getBody());
System.out.println("[" + LocalDateTime.now() + "] [Received] [" + queueName + "]: " + content);
System.out.println("");
if (RETRY_COUNT < 5) { publishToRetryExchange(content); RETRY_COUNT++; } else { RETRY_COUNT = 0; } }; CancelCallback cancelCallback = consumerTag -> System.out.println(consumerTag);
channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
}

// Publish to RetryQueue on failure
private static void publishToRetryExchange(String message) throws IOException {
System.out.println("[" + LocalDateTime.now() + "] [Retry" + RETRY_COUNT + "] [Re-Publish]: " + message);
channel.basicPublish(RETRY_EXCHANGE_NAME, "", null, message.getBytes());
}
}

Output chương trình:

[2020-05-03T22:57:03.614] [Work] [Send]: GPCoder Message
[2020-05-03T22:57:03.620] [Received] [WorkQueue]: GPCoder Message

[2020-05-03T22:57:03.620] [Retry0] [Re-Publish]: GPCoder Message
[2020-05-03T22:57:03.922] [Received] [WorkQueue]: GPCoder Message

[2020-05-03T22:57:03.922] [Retry1] [Re-Publish]: GPCoder Message
[2020-05-03T22:57:04.224] [Received] [WorkQueue]: GPCoder Message

[2020-05-03T22:57:04.224] [Retry2] [Re-Publish]: GPCoder Message
[2020-05-03T22:57:04.526] [Received] [WorkQueue]: GPCoder Message

[2020-05-03T22:57:04.526] [Retry3] [Re-Publish]: GPCoder Message
[2020-05-03T22:57:04.828] [Received] [WorkQueue]: GPCoder Message

[2020-05-03T22:57:04.828] [Retry4] [Re-Publish]: GPCoder Message
[2020-05-03T22:57:05.131] [Received] [WorkQueue]: GPCoder Message

Như bạn thấy, Message được tự động chuyển từ WorkQueue sang RetryQueue sau mỗi 300 ms nhờ vào Dead Letter Message. Đây là ví dụ cho trường hợp một Message hết hạn (expire) do Time to live (TTL).

Tương tự các bạn có thể set agruments là agruments.put(“x-max-length”, 10) để test trường hợp số lượng Message trong Queue vượt quá giới hạn chiều dài hàng đợi (length limit).

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins.

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins.

Truy cập vào trang quản lý Jenkins trên trình duyệt (ví dụ của mình là http://localhost:8080)

  Hướng dẫn build java project, maven project trên Jenkins
  Hướng dẫn cấu hình JDK (Java) cho Jenkins

Trên thanh menu bên trái chọn Manage Jenkins > Manage Plugins

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Chọn tab Available để tìm plugin cần cài mới, sau đó gõ tên plugin cần cài.

Trong ví dụ này mình thực hiện cài plugin Maven để thực hiện build các project Maven.

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Jenkins sẽ cài Maven plugin và các module liên quan.

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Sau khi cài đặt xong plugin maven, chúng ta có thể kiểm tra lại bằng cách tạo 1 item maven project mới:

Chọn New Item

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Bạn sẽ thấy lựa chọn cho Maven project

Cài Plugin cho Jenkins, Cài Maven Plugin cho Jenkins

Okay, Done!

References: https://plugins.jenkins.io/maven-plugin/

Bài viết gốc được đăng tải tại stackjava.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Load Balancers I – Stateful App Servers và những điều nên biết

Load Balancers I – Stateful App Servers và những điều nên biết

Bài viết được sự cho phép của tác giả Kiên Nguyễn

Ở bài viết trước, ta đã phân tích về Load Balancer và bài toán “Server nào sẽ handle request nào?“, ở bài viết này, ta sẽ bàn tiếp về một khía cạnh khác của Load Balancer là Stateful App Servers.

Qua bài viết, phần nào ta đã hiểu được rằng tại sao App Servers không hề quan tâm tới User State. Tuy nhiên, với những Servers được thiết kế Stateful App Servers, bằng cách nào ta có thể áp dụng Load Balancer thành công?.

  Hướng dẫn sử dụng ReactJS Props và State
  Cân bằng tải (Load Balancing)

Tất cả sẽ có ngay sau đây. Bắt đầu ngay thôi nào!

1. Stateful App Servers

Bản thân nó luôn đối đãi như nhau với các request từ phía client. Công bằng và văn minh vcl.

Sự công bằng này đảm bảo cho mô hình Load Balancer hoạt động hiệu quả, server nào trống sẽ được phân công làm nhiệm vụ ngay. Nếu một server quan tâm tới user state, nó sẽ bị kẹt không biết tới khi nào (ví dụ như một chị đi shopping 3 tiếng mới thêm một món vào giỏ hàng). Server nếu hold cứ hold mãi không biết tới lúc nào.

Bản thân kiến trúc Load Balancer cũng cần giải pháp để kết nối những công việc còn “chưa xong” ở phía client. Kiến trúc này thường được biết tới như Stateful App Servers. Lúc này mỗi machine trong kiến trúc balancer sẽ giữ một số thông tin phía client. Bản thân những thông tin này cho phép Server có thể tùy ý tracking client đã làm việc với server nào

Những yếu tố có thể giúp việc stateful dễ dàng hơn:

  • IP Address
  • Session Id (Include SSL)
  • Cookies (ở Kieblog đã có một bài về Cookies rồi)

2. Persistence Layer

Với những application đã được thiết kế theo hướng Stateful App Servers thì điều quan tâm tới state hiện tại của user để có cách handle hợp lý. Trường hợp có Load Balancer, bằng cách nào ta có thể đáp ứng được “stateful”, mà vẫn đảm bảo “load balancer” thành công.

2.1 IP Address

IP address là một cách khả phố biến để phán định xem server nào sẽ tiếp tục xử lý request từ phía client. Tracking IP sẽ được thực hiện ngay từ lần đầu tiên User request tới server.

Ví dụ client A send request tới Server B. Ở các request tiếp theo, khi server phát hiện địa chỉ IP nó đã handle trước đó. Sử dụng IP Address thường đi kèm thêm lớp Network Load Balancer, có trách nhiệm phân giải IP, block các IP đến từ khu vực không cho phép thiết lập trước đó.

Load Balancers I – Stateful App Servers và những điều nên biết
Kiến trúc Application Load Balancer với IP Address. Nguồn ảnh / Source: aws.amazon.com

Sử dụng IP Address cũng là giải pháp thường biết tới với tên “Layer 4”. Bản thân Layer 4 ở đây là Transport Layer trong kiến trúc 7 tầng của mạng máy tính (7 layers OSI Model). Sử dụng IP Address cũng là biện pháp khá phổ biến cho các Stateful App Servers

2.2 Web Application

NgoàimLayer 4, ta cũng có thể sử dụng một số kỹ thuật thường được sử dụng ở phía Application như:

  • Session Id
  • Session Id SSL
  • Cookies

để phán định server sẽ handle request còn dang dở. Session và Cookies từ đâu đã là thành phần không thể thiếu của Stateful App Servers. Tuy nhiên để handle session trong kiến trúc Load Balancer, ta cần biết tới một khái niệm mới là Sticky Session.

Load Balancers I – Stateful App Servers và những điều nên biết
Với Session stickiness, request được điều phối đi đúng server để tiếp tục handle

Session stickiness, a.k.a., session persistence, is a process in which a load balancer creates an affinity between a client and a specific network server for the duration of a session, (i.e., the time a specific IP spends on a website). Using sticky sessions can help improve user experience and optimize network resource usage.

Session Stickiness là quá trình load balancer khởi tạo mối quan hệ giữa client và server trong thời gian của một phiên (session). Sử dụng sticky session cải thiện performance và user experienced, tối ưu tài nguyên server được sử dụng.

Dựa vào session id được cấp phát, Session stickiness sẽ lựa chọn đúng Server đã handle các request còn dang dở. Ở các request tiếp theo, nó cũng điều động các request đi đúng hướng, trỏ về đúng server mục tiêu.

3. Tham khảo

Thank for read my post – Wish you have best of luck – Happy coding!

Bài viết gốc được đăng tải tại kieblog.vn

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Vue 3 có gì mới? – What’s new from Vue 3?

Bài viết được sự cho phép của tác giả Kiên Nguyễn

Bản thân tôi rất yêu thích Vuejs, không ngạc nhiên khi luôn trông chờ, tìm hiểu xem Vue 3 có gì mới?. Quả nhiên Vue 3 không làm tôi thất vọng.

Với những cải tiến đáng giá từ performance cho tới API,điển hình là sự ra đời của Composition API thay cho Options API ở Vue 2.

  3 phút làm quen với Vue.js
  API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth

Bắt đầu ngay thôi nào!

1. Vue 3 có gì mới?

Không những thay đổi lớn về performance, không thể chê được vào đâu khi bổ sung hàng loạt tính năng mới, nhưng kích thước của Vue 3 cũng chỉ bằng Vue 2 (12KB).

Cải tiến đáng giá được nhắc tới trong bài viết này bao gồm:

  • Composition API
  • Multiple root elements
  • Suspense
  • Multiple v-models

Sơ bộ anh em có thể xem qua video này để nắm bắt thêm Vue 3 có gì mới nha!.

2. Composition API

Kể từ khi Vue 2 nổi lên như là ngôi sáng sáng giữa bầu trời, rất nhiều dự án lớn đã sử dụng Vue. Một khi dự án lớn (cỡ vài trăm component), vấn đề tái sử dụng (reusable code) và scability (mở rộng) trở nên quan trọng hơn bao giờ hết.

Ok, Composition API là câu trả lời đầu tiên cho Vue 3 có gì mới?. Vậy Composition API là gì?

Composition API as a reactive API coupled with the ability to register lifecycle hooks using globally imported functions.

Composition API là thành phần của Reactive API, với khả năng đăng kí các lifecycle hooks sử dụng các import global cho functions.

Quất thêm cái nữa khó hiểu hơn:

The main point is that the Composition API provides a different way to manage reactivity at all points in an application, without compromising organization and readability.

Điểm mấu chốt mà Composition API cung cấp là một “cách khác” để quản lý reactivity tất cả các điểm trong application, mà không ảnh hưởng tới tổ chức code và khả năng đọc hiểu.

Vãi nồi khó hiểu, đọc vậy mông lung như một trò đùa.

2.1 Dễ hiểu hơn được không?

Thực chất Composition API cho phép ta đóng gói một loạt các method trong life cycle. Ví dụ, trước kia ở Vue 2, created tính toán, chuẩn bị dữ liệu cho object A, watch theo dõi object A khi thay đổi, … Vô vàn thứ cần làm với A. Source code trở nên mất kiểm soát, khó hiểu nếu bạn không phải là người viết ra component đó.

Vue 3 có gì mới? – What’s new from Vue 3?
Các vùng có màu khác nhau thì độc lập với nhau. Nội đủ hết method trong life cycle cũng đã là nhiều với component.

Chính bởi khi có quá nhiều Component và nhiều logic phức tạp. Khó maintain và scale, nên ta cần tới Composition API.

Vue 3 có gì mới? – What’s new from Vue 3?
Với Composition API, tất cả các đoạn code xử lý liên quan tới Object A có thể được gom lại duy nhất ở setup.

Tuy nhiên, đừng quên là Vue 3 vẫn hỗ trợ Options API, nên nếu muốn, không có vấn đề gì khi cứ viết các method theo Life Cycle của Vue nha. Với Options API, cùng lướt qua component vô cùng đơn giản với Options API.

Vue.js Component

<template>
<div id="app">
<p>You clicked {{ numOfClicks }} times.</p>
<button @click="handleClick()">Click me to increment!</button>
</div>
</template>

<script>
export default {
name: "App",
data() {
return {
numOfClicks: 0,
};
},
created() {},
methods: {
handleClick: function () {
this.numOfClicks++;
},
},
};
</script>

<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Ví dụ sử dụng Composition API với setup()

Vue.js Component

<template>
<div id="app">
<p>You clicked {{ numOfClicks }} times.</p>
<button @click="handleClick()">Click me to increment!</button>
</div>
</template>

<script>
import { ref } from "vue";

export default {
name: "App",
setup() {
let numOfClicks = ref(0);

function handleClick() {
numOfClicks.value++;
}

return {
handleClick,
numOfClicks,
};
},
};
</script>

<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Tuy nhiên, sử dụng Composition API cần lưu ý:

Because the component instance is not yet created when setup is executed, there is no this inside a setup option. This means, with the exception of props, you won’t be able to access any properties declared in the component – local statecomputed properties or methods.

Bởi vì Component instance chưa hề được tạo ra khi method setup được thực thi, nên this chắc chắn không work. Ngoại trừ cái thằng props ra, tuyệt nhiên ta không thể access tới bất cứ properties nào khai báo trong component, local state, computed properties hoặc methods cũng không là ngoại lệ.

3. Multiple root elements

Multi root elements ở đây được hiểu là component không cần phải thuộc về duy nhất một node cha nữa. Câu trả lời thứ 2 cho Vue 3 có cái gì mới xem ra dễ hiểu hơn nhiều!.

Bai bai cái lỗi khó chịu quỷ tha ma bắt này. Bắt đầu từ Vue 3, một component có thể có nhiều hơn một node cha.

Vue 3 có gì mới? – What’s new from Vue 3?

Vue.js Component

<template>
<div class="counter">
<p> Count: {{ count }} </p>
<button @click="increment"> Increment </button>
<button @click="decrement"> Decrement</button>
</div>
</template>

Tha hồ, mặc sức mà tạo node con trong template với Vue 3. Việc bỏ đi một node cha cũng bớt phiền phức khi làm việc với css. Trước đây 2 tag p nếu bắt buộc chung nhau 1 div phải viết css parent child mệt mỏi. Tuy nhiên, giờ mạnh ai người đó xài css của mình.

Vue.js Component

<template>
<p> Count: {{ count }} </p>
<button @click="increment"> Increment </button>
<button @click="decrement"> Decrement</button>
</template>

4. Suspense

Suspense là cái tiến mới ở Vue 3 liên quan tới Asynchorous (Bất đồng bộ). Trước đây khi làm việc với API, do việc xử lý call API là bất đồng bộ, nên cần chờ tới khi có response trả về mới thực hiện render.

Thông thường sử dụng v-if, tuy nhiên với Suspense, mọi việc trở nên đơn giản hơn nhiều.

Suspense is a special component that renders a fallback content instead of your component until a condition is met.

Suspense là component dặc biệt render nội dung dự phòng thay vì component chính (lúc này chưa có data), cho tới khi condition (điều kiện để render component) được xác lập.

Sử dụng Suspense cũng khá đơn giản, chỉ cần lưu ý tới 2 từ khóa default và fallback. Cùng xem xét ví dụ sau:

Vue.js Component

<template>
<Suspense>
// Sau khi đã có response từ API, nội dung template này sẽ render sau.
<template #default>
<div v-for="item in articleList" :key="item.id">
<article>
<h2>{{ item.title }}</h2>
<p>{{ item.body }}</p>
</article>
</div>
</template>
// Trước khi có data từ API, nội dung trong template này sẽ tải trước
<template #fallback>
Articles loading...
</template>
</Suspense>
</template>
<script>
import axios from 'axios'
export default {
async setup() {
let articleList = await axios
.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response)
return response.data
})
return {
articleList
}
}
}
</script>

5. Multiple V-models

Làm việc với Vue 2 chắc chắn đã biết tới v-models. V-models là two way binding. Dữ liệu binding 2 chiều, thường được sử dụng với form trên component.

Hữu dụng là thế, tuy nhiên Vue 2 chỉ cho phép một component có duy nhất một v-models. Vue 3 thì khác, cho phép không giới hạn số lượng v-model trong component.

Vue.js Component

<template>
<Suspense>
// Sau khi đã có response từ API, nội dung template này sẽ render sau.
<template #default>
<div v-for="item in articleList" :key="item.id">
<article>
<h2>{{ item.title }}</h2>
<p>{{ item.body }}</p>
</article>
</div>
</template>
// Trước khi có data từ API, nội dung trong template này sẽ tải trước
<template #fallback>
Articles loading...
</template>
</Suspense>
</template>
<script>
import axios from 'axios'
export default {
async setup() {
let articleList = await axios
.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response)
return response.data
})
return {
articleList
}
}
}
</script>

6. Tham khảo

Thank for read the article – Have a nice weekend – Happy coding!

Bài viết gốc được đăng tải tại kieblog.vn

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Gitlab CI

Gitlab CI

Bài viết được sự cho phép của tác giả Lê Chí Dũng

Đến thời điểm hiện nay, tôi thường yêu cầu các dự án của mình phải có CI. Nếu viết bằng script như nodejs thì CI sẽ có nhiệm vụ check syntax, để các thành viên trong nhóm cùng một kiểu viết giống nhau, và chạy các mức test khác nhau như unit test, CDC test.

Điểu tuyệt vời của gitlab là nó đi kèm với bộ CI miễn phí cho cả dự án private (yay). Blog này sẽ trình bày chiến lược để thiết lập ENV test trên Gitlab CI để build docker image, và upload nó lên gitlab registry.

  CI/CD là gì? Triển khai quy trình CI/CD với Gitlab
  34 sản phẩm phần mềm Social Networking tốt nhất

Gitlab CI

Gitlab runner

Là nơi chương trình test của bạn sẽ được chạy. Bạn có thể có một PC riêng biệt cho việc build và test. Gitlab cung cấp một chương trình khá tiện https://gitlab.com/gitlab-org/gitlab-ci-multi-runner để thiết lập runner cục bộ. Cá nhân tôi chỉ sử dụng multi runner này khi chương trình cần tài nguyên lớn.

Phần lớn thời gian tôi sử dụng shared runner https://about.gitlab.com/gitlab-com/settings/#shared-runners. Xin cảm ơn sự tử tế của Digital Ocean khi cho mỗi build một tài nguyên 4GB chạy trong mỗi máy ảo riêng biệt.

Shared runner chạy trên docker, nên có thể khai báo các docker có sẵn khá tiện (yay).

.gitlab-ci.yml

Là file cấu hình cho gitlab CI. Dưới đây là một ví dụ trong đó khai báo một trạng thái của test pipeline là unit test. Phần sau dựa trên giả thuyết tôi đang xây dựng một web app với nodejs, và chạy unit test với npm run test.

image: node:boron-alpine

stages:
 - unit_test

unit_test_job:
 stage: unit_test
 script:
 - npm install
 - npm run test

Với mỗi git push lên CI được trigger. CI sẽ pull về docker image node:boron-alpine giống với docker chạy trong staging và production environment của web app này. Stages khai báo các bước của CI. Trong trường hợp này, tôi chỉ có một bước duy nhất là unit test khai báo trong unit_test_job.

Gitlab CI

Nhưng tôi tin vào 12factor, và tôi muốn có quá trình build trước. CI hay staging hay production sẽ khác nhau ở ENV truyền vào docker như trình bày ở https://12factor.net/build-release-run. Tôi sẽ tạo một job để tạo artifact, và chạy test trên artifact này.

image: docker:1.12
services:
 - docker:dind

stages:
 - build

variables: 
 CONTAINER_TEST_IMAGE: registry.gitlab.com/company/project:$CI_BUILD_REF_NAME
before_script:
 - docker info
build_image_job:
 stage: build
 script:
 - docker build -t $CONTAINER_TEST_IMAGE .
 - docker run $CONTAINER_TEST_IMAGE npm run test

Setup này sử dụng docker in docker (dind)  để build docker image trong một docker (nơi CI đang chạy). Đều này đạt được do shared runner chạy với privileged enable.

Như vậy lúc này CI sẽ tạo một docker có tên biến CONTAINER_TEST_IMAGE , và chạy test trong image này.

Tôi muốn tiến thêm một bước nữa, pipeline bao gồm: build, test, và release. Quá trình release xảy ra khi tôi tag git tag -a version, nó sẽ tạo ra tag latest và upload lên gitlab registry.

Khoa, gitlab registry? Đúng vậy, gitlab cho phép bạn lưu các image lên host của họ. Bạn sẽ có CI, và registry (miễn phí).

image: docker:1.12

services:
- docker:dind

stages:
- build
- test
- release
- deploy

variables:
 CONTAINER_TEST_IMAGE: registry.gitlab.com/company/project:$CI_BUILD_REF_NAME
 CONTAINER_RELEASE_IMAGE: registry.gitlab.com/company/project:latest

before_script:
 - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com

build:
 stage: build
 script:
 - docker build --pull -t $CONTAINER_TEST_IMAGE .
 - docker push $CONTAINER_TEST_IMAGE

unit_test:
 stage: test
 script:
 - docker pull $CONTAINER_TEST_IMAGE
 - docker run $CONTAINER_TEST_IMAGE npm run unit_test

cdc_test:
 stage: test
 script:
 - docker pull $CONTAINER_TEST_IMAGE
 - docker run $CONTAINER_TEST_IMAGE npm run cdc_test

release-image:
 stage: release
 script:
 - docker pull $CONTAINER_TEST_IMAGE
 - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
 - docker push $CONTAINER_RELEASE_IMAGE
 only:
 - tags
 - triggers

Gitlab rất hào phóng khi cung cấp đầy đủ các công cụ và dịch vụ để bạn có thể xây dựng một quá trình CI khá hoàn chính, từ việc chạy các test đến việc lưu trữ các image của bạn.

Hy vọng bạn sẽ tìm thấy sự hữu dụng trong ecosystem của gitlab.

Bài viết gốc được đăng tải tại lcdung.top

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Biết Python – quen ngay Julia

Biết Python - quen ngay Julia

Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng

Julia là ngôn ngữ lập trình mới, trông rất giống code Python, chạy nhanh hơn Python3 ít nhất 2 lần và có nhiều tính năng hấp dẫn. Bạn không cần phải từ bỏ Python hay ngôn ngữ XYZ để học Julia, Julia chỉ đơn giản là một bông hoa đẹp mà ai thích… thì múc.

Julia là ngôn ngữ lập trình “làm gì cũng được”, nhưng được tập trung vào lĩnh vực tính toán khoa học và muốn thế chỗ Python (nhưng đường còn dài, và còn nhiều hơn chông gai).

Cài đặt

Xem https://docs.julialang.org/en/v1/

Tại thời điểm viết bài (2019 tháng 4), Julia ở bản 1.1.0 – đã ổn định hơn trước rất nhiều, ít bug hơn, chạy nhanh hơn.

Từ Python ngó sang

Julia trông rất giống Python, cách dùng các học, cách code cũng tương tự, nên nếu biết Python thì việc viết được code để làm công việc thường ngày (của 1 DevOps) chỉ trong vòng vài tiếng.

REPL

Gõ lệnh trực tiếp bằng lệnh julia trên Linux/MacOS

$ julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.1.0 (2019-01-21)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> 1 + 1
2

Đây gọi là chế độ “REPL” (Read-Eval-Print-Loop) == (gõ vào – chạy – in ra kết quả – cứ thế mà làm).

  Những cải tiến đáng giá của Python 3.12

IPython

Không cần cài thêm gì, Julia REPL tự có đủ các tính năng thiết yếu của IPython.

Đọc document của 1 function? Gõ ? rồi gõ bất cứ cái gì cần hỏi:

julia> 1 + 1
2
###### gõ ? xong , biến từ julia> thành help?>
help?> sum
search: sum sum! summary cumsum cumsum! isnumeric VersionNumber issubnormal get_zero_subnormals

...
 sum(itr)

  Returns the sum of all elements in a collection.

Màu mè (syntax highlight) cũng tự có sẵn rồi.

Chạy file code

File code Julia có đuôi .jl, ví dụ hello.jl. Chạy file code bằng cách gõ lệnh: julia hello.jl

Cài đặt package

Để cài các package trên mạng, sử dụng package manager CÓ SẴN của Julia. Chuyện về virtualenv tạm chưa bàn tới ở đây vì khá rõ ràng là không cần thiết (cài package không cần gõ sudo gì cả).

Việc cài đặt package trong Julia thực hiện hơi khác so với Python Pip hay NodeJS NPM một chút. Sẽ không có câu lệnh nào để gõ cả, không có chương trình thêm nào hết. Julia thực hiện cài đặt package khi một đoạn code Julia được chạy (gọi function thực hiện cài đặt).

Ví dụ một file tên (tuỳ ý) như sau:

# gicungduoc.jl
using Pkg
Pkg.add("HTTP")
Pkg.add("JSON")
Pkg.add("DocOpt")

Chạy code này: julia gicungduoc.jl sẽ cài đặt các package, sau đó cứ thế mà dùng các thư viện này.

  Ruby vs Python: Đâu mới là ngôn ngữ tốt hơn cho lập trình ứng dụng

The good, the OK, the ugly

The good – phần tốt

Pipe operator

Tốt hay xấu là tuỳ do từng người tự phán xét. Hãy xem đoạn code sau:

Python: ''.join(" Py thon ".strip().split())

Julia: " Py thon " |> strip |> split |> xs -> join(xs, "")

Python

def double(x):
    return x * 2
def incr(x):
    return x + 1

print(incr(double(incr(2))))
double(x) = x * 2
incr(x) = x + 1
println(2 |> incr |> double |> incr)
# 7

|> gọi là Piping operator, lấy đầu ra của function này làm đầu vào cho function khác. Giúp việc goi funciton liên tục (và đọc nó) dễ dàng hơn. Giống UNIX command.

Nhanh

Julia thường nhanh hơn Python ít nhất 2 lần

Không quan trọng indentation

Dù bạn thụt ra thụt vào 2 3 4 5 ký tự, hay dùng tab đều không quan trọng. Chuyện này vốn gây đau đầu cho không ít người dùng Python.

Python

s = 0
for i in range(1000):
    if i % 3 == 0 or i % 5 == 0:
        s = s + i
print(s)

Julia

for i in 1:999
 if i % 3 == 0 || i % 5 == 0
   global s = s + i
 end
end
println(s)
# 233168

Julia dùng từ end để kết thúc if hay for, nên không cần thiết sử dụng dấu cách hay tab để thụt dòng. Thậm chí có thể dùng ; để phân cách các phần, và viết trên 1 dòng (bạn KHÔNG THỂ làm điều này với Python khi có for):

julia> s = 0; for i in 1:999; if i % 3 == 0 || i % 5 == 0; global s = s + i ; end ; end; println(s)
233168
Range bao gồm cả số kết thúc

Một điều gây khó chịu với người mới code Python là phần kết thúc của range không được tính. Tức nếu viết range(1,1000) thì chỉ có từ 1 đến 999. Trong đầu luôn phải nhớ bớt đi 1. Julia 1:999 nghĩa là 1 đến 999, không thêm bớt gì.

Không bị “leak” biến i trong vòng lặp ra ngoài

Đây là 1 bug của Python, do sau này quá muộn để sửa, người ta coi nó như 1 tính năng.

for i in [1,2,3]:
    print(i)
print(i)  # i vốn ở trong vòng lặp for, nay thoát ra ngoài với giá trị = 3
Hỗ trợ functional

Viết map trong Julia rất dễ chịu – dễ đọc:

map([1,2,3]) do x
  x + 1
end

Cách viết dùng lambda:

map(x -> x+1, [1,2,3])

sẽ tạo array chứa [2,3,4]

Python

list(map(lambda x: x+1, [1,2,3]))

The OK – ổn

Index from 1

Chuyện này gây sốc với lập trình viên lâu năm C, Java, PHP, Python … Nhưng không phải là hiếm có. Lua, MatLab, R đều dùng index từ 1.

ns=[1,2,3,4]; print(ns[4])

Trong Julia code này sẽ in ra số 4 nhưng Python sẽ xảy ra exception do Python index đếm từ 0

Dùng nhiều sẽ quen và cũng không ghê gớm lắm, do Julia sử dụng cả phần cuối của range.

Ví dụ slice: Python lấy 3 số đầu tiên của list:

ns[0:3]

Julia:

ns[1:3]

Đều kết thúc là 3 – đều là số phần tử cần lấy.

Nhưng tệ hơn khi cần lấy 2 phần tử cuối:

ns[end-1:end]

end là một index magic (tự xuất hiện), đại diện cho index của phần tử cuối cùng.

Trong ví dụ này gõ số 4 thay end cũng được.

The ugly – thảm hại

Unicode string – sẽ rất đau đầu khi chuyển từ Python sang.

Index của string (mặc định Unicode) trong Julia là byte index, không phải index theo thứ tự của ký tự.

Python

In [16]: w = "Điêu"

In [20]: w[0],w[1]
Out[20]: ('Đ', 'i')

Julia

ulia> w = "Điêu"
"Điêu"

julia> w[1]
'Đ': Unicode U+0110 (category Lu: Letter, uppercase)

julia> w[2]
ERROR: StringIndexError("Điêu", 2)
Stacktrace:
 [1] string_index_err(::String, ::Int64) at /nix/store/2fmf5sqi0jx5zdlqx0gpw2m6nrsbcch2-julia-1.0.1/lib/julia/sys.dylib:?
 [2] getindex_continued(::String, ::Int64, ::UInt32) at /nix/store/2fmf5sqi0jx5zdlqx0gpw2m6nrsbcch2-julia-1.0.1/lib/julia/sys.dylib:?
 [3] getindex(::String, ::Int64) at /nix/store/2fmf5sqi0jx5zdlqx0gpw2m6nrsbcch2-julia-1.0.1/lib/julia/sys.dylib:?
 [4] top-level scope at none:0

julia> w[3]
'i': ASCII/Unicode U+0069 (category Ll: Letter, lowercase)

Do chữ Đ trong Unicode UTF-8 được biểu diễn bằng 2 byte, ta chỉ có thể truy cập được index 1, không truy cập được index 2. Và chữ i ngay sau Đ sẽ là index 3.

Exception

TBD

Chú ý

  • Julia khởi động mất 0.2-0.4 giây, Python khởi động nhanh gấp 10.
  • String trong Julia phải dùng double quote "", single quote '' dành cho ký tự (Char).
  • Nối string dùng * chứ không phải +.
  • Sẽ không có method gắn liền vào các object như string hay list trong Python, thay vào đó là các function có sẵn (thường không cần import, gọi là trong Base)

Ví dụ 1 chương trình CLI nhận argument, gọi HTTP với JSON

import HTTP
import JSON
using DocOpt  # import docopt function

function main()
    doc = """Fist Julia program which makes HTTP requests to httpbin endpoint

    Usage:
      main.jl request <endpoint>

    Options:
      -h --help     Show this screen.
      --version     Show version.
    """

    args = docopt(doc, version=v"0.0.1")
    endpoint = args["<endpoint>"]
    url = "https://httpbin.org/$endpoint"
    println("Accessing $url")
    resp = HTTP.get(url)
    d = JSON.Parser.parse(String(resp.body))
    println("My IP is " * d["origin"])

    println("Now also send post")
    r = HTTP.request("POST", "https://httpbin.org/post",
            ["Content-Type" => "application/json"],
            JSON.json(Dict('a'=>2, 'b'=>3))
            )
    data = JSON.Parser.parse(String(r.body))

    open("/tmp/data.json", "w") do f
        write(f, JSON.json(data["json"]))
    end
    open("/tmp/data.json", "r") do f
        d = JSON.Parser.parse(String(read(f)))
        println(d)
    end

    open(`ls -l`) do io
        for line in eachline(io)
            if !isa(match(r".*\.jl", line), Nothing)
                println(line)
            end
        end
    end
end

main()

Chạy

$ julia  main.jl  -h
Fist Julia program which makes HTTP requests to httpbin endpoint

Usage:
  main.jl request <endpoint>

Options:
  -h --help     Show this screen.
  --version     Show version.

$ julia main.jl request ip
Accessing https://httpbin.org/ip
My IP is 3.117.2.254, 3.117.2.254
Now also send post
Dict{String,Any}("b"=>3,"a"=>2)
-rw-r--r-- 1 viethung.nguyen viethung.nguyen 1189 Apr 12 08:38 main.jl

Code hoàn toàn tương đương với code Python.

Kết luận

Còn chờ gì nữa? Làm tí Julia thôi.

Phần tiếp theo (nếu có) sẽ đi vào các tính năng của Julia sử dụng trong tính toán khoa học.

Tham khảo

Bài viết gốc được đăng tải tại pp.pymi.vn

Có thể bạn quan tâm:

Xem thêm tuyển IT hấp dẫn trên TopDev

Kiểu bool C/C++ | Code hướng dẫn và ứng dụng thực tiễn

Kiểu bool, boolean trong lập trình C/C++ (Code ví dụ)

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Trong lập trình, việc xử lý các giá trị đúng/sai là điều thường xuyên phải thực hiện, đặc biệt trong các câu lệnh điều kiện, vòng lặp và kiểm tra logic. Kiểu dữ liệu Boolean được sử dụng để biểu diễn hai trạng thái logic cơ bản này. Cùng tìm hiểu về Bool trong C/C++ được sử dụng như thế nào, cú pháp ra sao trong bài viết của TopDev.

Bool trong C/C++ là gì?

Bool trong C/C++ là gì?

Trong C++, kiểu dữ liệu boolean được sử dụng để biểu diễn hai trạng thái logic: đúng hoặc sai. Kiểu dữ liệu này được gọi là bool, và nó có thể chứa một trong hai giá trị:

  • true: Đại diện cho giá trị đúng.
  • false: Đại diện cho giá trị sai.

Kiểu dữ liệu bool được sử dụng rộng rãi trong các câu lệnh điều kiện như if, while, for, và các phép toán logic khác. Khi một giá trị bool được sử dụng trong điều kiện, giá trị true được coi là 1 và false được coi là 0.

Ban đầu, ngôn ngữ C không hỗ trợ kiểu bool, mà nó dùng số integer để biểu thị true/false (0 tức là false, khác 0 tức là true). Bắt đầu từ phiên bản C99 standard for C language thì mới bắt đầu hỗ trợ kiểu bool.

  Các kiểu dữ liệu trong lập trình C/C++ (Data type)

Cách sử dụng kiểu bool trong C/C++

Cách 1: Sử dụng thư viện <stdbool.h>

Thư viện <stdbool.h> là một phần của C99, cung cấp định nghĩa cho kiểu bool, cũng như các hằng số truefalse. Thư viện này thường được sử dụng trong C hơn là trong C++.

Với cách này ta sử dụng kiểu bool của C (với C++ thì mặc định không cần khai báo thư viện <stdbool.h>)

Ví dụ:

#include<stdio.h>
#include <stdbool.h>

int main()
{
bool value = false;
if (value) { // tương đương với kiểm tra value == true
printf("value is true"); 
} else {
printf("value is false");
}
return 0; 
}

Kiểu bool, boolean trong lập trình C/C++ (Code ví dụ)

C++ tuyển dụng nhiều vị trí, lương cao, ứng tuyển ngay!

Cách 2: Tự định nghĩa kiểu bool với enum

Nếu bạn không muốn sử dụng kiểu bool tích hợp sẵn, bạn có thể tự định nghĩa nó bằng cách sử dụng enum (liệt kê). Điều này giúp bạn tạo ra kiểu dữ liệu bool của riêng mình với các giá trị truefalse.

enum bool { false, true }; // tương đương với typedef enum { false=0, true=1 } bool;

Ví dụ:

#include<stdio.h>
typedef enum { false, true } bool;

int main()
{
 bool value = false;
if (value) { // tuong duong v?i ki?m tra value == true
 printf("value is true");
} else {
 printf("value is false");
}
return 0;
}

Cách 3: Định nghĩa kiểu bool với integer

Một cách khác để mô phỏng kiểu bool là sử dụng một số nguyên (integer). Trong cách này, bạn quy ước rằng 0 đại diện cho false1 (hoặc bất kỳ giá trị khác 0) đại diện cho true.

typedef int bool;
#define true 1
#define false 0

int main() {
    bool isTrue = true;    // isTrue = 1
    bool isFalse = false;  // isFalse = 0

    if (isTrue) {
        // Thực hiện một số hành động khi isTrue là true
    }

    return 0;
}

Cách 4: Khai báo hằng số true/false

Bạn cũng có thể tự định nghĩa các hằng số truefalse mà không cần phải tạo kiểu dữ liệu mới. Điều này thường được sử dụng trong các ngôn ngữ hoặc môi trường không hỗ trợ kiểu bool một cách tự nhiên.

#define true 1
#define false 0

int main() {
    int isTrue = true;    // isTrue = 1
    int isFalse = false;  // isFalse = 0

    if (isTrue) {
        // Thực hiện một số hành động khi isTrue là true
    }

    return 0;
}

Cách 1 chỉ chạy được từ phiên bản C99 standard for C language. Tuy nhiên hầu hết các bản compiler C/C++ đều đã update cho nên các bạn nên dùng cách này. Cách 2,3,4: thì hoạt động giống nhau.

Nhìn chung thì kiểu bool vẫn là kiểu integer, nên cho dù dùng cách nào thì bạn vẫn có thể gán bool bằng một giá trị integer bất kì (0 tức là false, khác 0 tức là true).

Các ứng dụng thực tiễn của Bool C++

Kiểu dữ liệu boolean có rất nhiều ứng dụng trong lập trình, từ việc kiểm tra điều kiện trong câu lệnh if, vòng lặp while, for, đến việc sử dụng trong các phép toán logic phức tạp.

Kiểm tra điều kiện trong câu lệnh if

Câu lệnh if là một trong những câu lệnh điều kiện phổ biến nhất trong lập trình, và boolean đóng vai trò quan trọng trong việc xác định các điều kiện đúng hoặc sai.

Ví dụ:

#include <iostream>

int main() {
    bool isLoggedIn = true;

    if (isLoggedIn) {
        std::cout << "User is logged in." << std::endl;
    } else {
        std::cout << "User is not logged in." << std::endl;
    }

    return 0;
}

Sử dụng trong vòng lặp while

Vòng lặp while sử dụng boolean để xác định khi nào vòng lặp sẽ tiếp tục chạy và khi nào sẽ dừng.

Ví dụ:

#include <iostream>

int main() {
    int count = 0;
    bool keepGoing = true;

    while (keepGoing) {
        std::cout << "Count: " << count << std::endl;
        count++;
        if (count >= 5) {
            keepGoing = false;  // Dừng vòng lặp khi count >= 5
        }
    }

    return 0;
}

Sử dụng trong các phép toán Logic

Boolean cũng được sử dụng trong các phép toán logic, như AND (&&), OR (||), và NOT (!), giúp thực hiện các kiểm tra điều kiện phức tạp.

Ví dụ:

#include <iostream>

int main() {
    bool isAdmin = true;
    bool isLoggedIn = true;

    if (isAdmin && isLoggedIn) {
        std::cout << "User is an admin and is logged in." << std::endl;
    } else {
        std::cout << "Access denied." << std::endl;
    }

    return 0;
}

Kiểu dữ liệu boolean là một phần quan trọng và không thể thiếu trong lập trình, giúp lập trình viên thực hiện các kiểm tra điều kiện và các phép toán logic một cách dễ dàng và hiệu quả. Dù là trong ngôn ngữ C với sự thiếu hụt ban đầu của kiểu boolean hay trong C++ với kiểu dữ liệu boolean tích hợp sẵn, việc hiểu và sử dụng đúng cách kiểu boolean là kỹ năng quan trọng mà mỗi lập trình viên cần nắm vững.

Qua bài viết này, hy vọng bạn đã có cái nhìn sâu hơn về cách sử dụng kiểu boolean trong C và C++, cũng như biết cách áp dụng nó vào các tình huống thực tế trong lập trình.

Nguồn tham khảo: codecute.com

Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev