Home Blog Page 87

Làm tròn hay làm méo?

Làm tròn hay làm méo?

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

Làm việc với kiểu dữ liệu float (số thực) luôn mang lại những bất ngờ đầy thú vị (thú vị không có hàm ý là tốt hay xấu). Nếu như kiểu integer (số nguyên) luôn tròn trịa, đẹp đẽ, thì float lại xù xì, thô ráp, thiếu chính xác (float là biểu diễn gần đúng), thực dụng, và đầy dãy bất ngờ.

  "Dân làm Product khác hoàn toàn 180 độ với dân làm outsourcing"

YinYang

Số nguyên như một bức tranh về những tưởng tượng của con người. Còn số thực thì rất thực, như cuộc sống này vậy.

Python có sẵn function round dùng để làm tròn một số float về kiểu int, rất dễ hiểu, gần gữi như lúc ta học

P.S: code trong bài sử dụng Python 3.5

In [2]: round(4.2)
Out[2]: 4

In [3]: round(6.9)
Out[3]: 7

In [4]: round(6.0)
Out[4]: 6

In [5]: round(7.0)
Out[5]: 7

Mọi thứ đều đơn giản, cho đến khi có vấn đề xảy ra. Liệu kết quả sẽ thu được là mấy nếu làm tròn 9.5? Là 9 hay là 10? Nếu tuân theo logic thông thường, ta sẽ làm tròn về số nguyên nào mà ở gần 9.5 hơn. Với 9.5, khoảng cách tới 9 hay 10 đều là 0.5. Vậy em chọn lối nào?

Đưa ra lựa chọn là một điều không hề đơn giản, đưa ra lựa chọn đúng thì phải mãi về sau có kết quả rồi ta mới biết.

Giả sử với bộ dữ liệu có

L = [5.5, 6.5, 7.5, 8.5]

Bộ dữ liệu này có giá trị trung bình là

In [1]: L = [5.5, 6.5, 7.5, 8.5]

In [2]: sum(L)/len(L)
Out[2]: 7.0

Khi mang đi làm tròn, ta chỉ muốn thu được các giá trị “tròn” hơn, nhưng vẫn mong muốn giữ nguyên ý nghĩa của bộ dữ liệu – giá trị trung bình (mean) ở đây là một đại diện có thể xem xét.

Nếu làm tròn lên số nguyên lớn hơn, ta có:

In [3]: import math

In [4]: [math.ceil(n) for n in L]
Out[4]: [6, 7, 8, 9]

In [5]: up = [math.ceil(n) for n in L]

In [6]: sum(up)/len(up)
Out[6]: 7.5

Bộ dữ liệu của ta giờ đã có vẻ tiến lên so với ban đầu.

Nếu làm tròn xuống số nguyên gần nhất, ta có:

In [7]: [math.floor(n) for n in L]
Out[7]: [5, 6, 7, 8]

In [8]: down = [math.floor(n) for n in L]

In [9]: sum(down)/len(down)
Out[9]: 6.5

Bộ dữ liệu có vẻ đã “dịch xuống” một chút.

Giải pháp nào để làm tròn mà giảm thiểu sự lệch của bộ dữ liệu? Vấn đề này có thể không xuất hiện ở Việt Nam, với đơn vị tiền tệ biểu diễn bằng kiểu integer, với đơn vị tối thiểu là trăm (đồng), nhưng hẳn đã khiến người Mỹ đau đầu khi đơn vị dola ($) thường xuất hiện ở dạng 1.5 $, 2.4 $…

Và nói đến tiền, những người hiểu về tiền nhất, có lẽ là các nhà ngân hàng (banker). Ngành banker có một phương pháp làm tròn mà Microsoft, … các ngôn ngữ lập trình đều học theo, đó là làm tròn tới số chẵn gần nhất.

In [2]: [round(n) for n in L]
Out[2]: [6, 6, 8, 8]

In [3]: bankers = [round(n) for n in L]

In [4]: sum(bankers)/len(bankers)
Out[4]: 7.0

Trong một bộ số liệu bất kỳ, khi tỷ lệ giữa số chẵn và số lẻ là như nhau, nếu làm tròn 5.5 lên 6 (số chẵn gần nhất), ta tăng nó lên 0.5, còn với 6.5, làm tròn sẽ giảm đi 0.5 thì kết quả là các số lẻ tiến lên, các số chẵn lùi lại, ta giữ được thế cân bằng. Cách làm tròn này vốn tồn tại với cái tên “bankers’ rounding”, sau này được chuẩn hóa vào tiêu chuẩn xử lý số thực (float) IEEE-754 mà hầu hết các ngôn ngữ lập trình tuân theo.

Cái gì quá cũng không tốt, to quá, nhỏ quá, mạnh quá, yếu quá, ít quá, nhiều quá đều không ổn. Vạn vật chỉ phát triển khi đạt tới một thế cân bằng, âm dương hòa hợp, đất trời nảy hoa, cỏ cây xanh lá.

P.P.S: cách làm tròn này là một thay đổi của Python 3 so với Python 2, có ghi trong changelog của python 3.0

Tham khảo

Xem thêm bài viết về một “sự thật” cần biết về số thực tại đây.

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 IT hấp dẫn trên TopDev

Code ví dụ TypeScript, hướng dẫn tạo project TypeScript

Code ví dụ TypeScript, hướng dẫn tạo project TypeScript

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

Code ví dụ TypeScript, hướng dẫn tạo project TypeScript

Yêu cầu: đã hiểu biết về javascript/nodejs.Biết cách sử dụng npm (Xem lại: Hướng dẫn NodeJs)

Việc làm Typescript lương cao up to 2000USD

1. Tạo TypeScript project

Trong ví dụ này, mình sẽ tạo Project TypeScript với tên là typescript-project

Tạo folder typescript-project:

mkdir typescript-project

Vào foder typescript-project:

cd typescript-project

Khởi tạo project nodejs (bước này có thể bỏ qua, vì khi bạn cài đặt package nào đó nó cũng tự động tạo file package.json rồi. Xem lại Tạo nodejs project)

Code ví dụ TypeScript, hướng dẫn tạo project TypeScript

Cài thư viện (package) typescript:

npm i typescript --save-dev

*Lưu ý: ở đây mình dùng option --save-dev vì package typescript chỉ cần thiết cho môi trường dev. Sau khi build project thành các file .js thì package typescript không cần thiết.

Sau khi cài xong package typescript thì ta có thể khởi tạo project TypeScript bằng lệnh:

npx tsc --init

Lệnh này sẽ tạo ra file tsconfig.json, chứa cấu hình của project TypeScript như: file js được build ra chỗ nào? những file nào sẽ được build…

Hướng dẫn tạo project TypeScript chi tiết, ví dụ TypeScript

Đây là cấu  trúc project typescript-project được sinh ra

Code ví dụ TypeScript, hướng dẫn tạo project TypeScript

File tsconfig.json mình sẽ sửa lại đơn giản như sau:

{

"compilerOptions": {

"target": "es6",

"module": "commonjs",

"strict": true,

"outDir": "dist",

"sourceMap": true

}

}

Ý nghĩa của các field trong file tsconfig.json thì các bạn có thể đọc ở comment trong file sau khi được sinh ra ở trên. Ở đây mình giải thích lại một số field mình dùng:

  • "target": "es6" các file .js được generate từ file .ts sẽ được format theo chuẩn es6
  • "outDir": "dist" các file .js được sinh ra ở folder dist
  Authorization Code grant type với Proof Key for Code Exchange (PKCE) trong OAuth 2.1
  Các kiểu dữ liệu trong lập trình C/C++ (Data type)

2. Code ví dụ TypeScript

Mình sẽ tạo file index.ts trong folder src với nội dung sau: (thường thì 1 project sẽ chứa code trong folder src)

class Demo {

 message: string;




 constructor(message: string){

this.message = message;

}




public hello() {

 console.log(this.message);

}

}




const demo = new Demo('hello world');

 demo.hello();

Hướng dẫn tạo project TypeScript chi tiết, ví dụ TypeScript

Đọc code file index.ts ta sẽ thấy nó khá giống với Java hay .Net, cho chỉ rõ kiểu dữ liệu của biến…

3. Thực hiện compile project TypeScript

Để build project typescript, ta chạy lệnh:

npx tsc

Hướng dẫn tạo project TypeScript chi tiết, ví dụ TypeScript

Như bạn thấy, file .js được tạo ra trong folder dist

Hướng dẫn tạo project TypeScript chi tiết, ví dụ TypeScript

Bạn cũng có thể thực hiện build và chạy project typescript bằng cách thêm script vào trong file package.json

Ví dụ mình thêm script “start”: “tsc && node dist/index.js” vào file package.json

Khi chạy thì chỉ cần gõ lệnh npm start

Hướng dẫn tạo project TypeScript chi tiết, ví dụ TypeScript

Download code ví dụ trên tại đây hoặc tại https://github.com/stackjava/typescript-project

References: https://www.typescriptlang.org/docs/

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 IT hấp dẫn trên TopDev

Hướng dẫn sử dụng bootstrap tourist để làm trợ giúp cho phần mềm

Hướng dẫn sử dụng bootstrap tourist để làm trợ giúp cho phần mềm

Bài viết được sự cho phép của tác giả Phạm Công Sơn

Trước khi đi vào hướng dẫn cài đặt và sử dụng Bootstrap Tourist các bạn có thể thử tiện ích này ngay sau đây

Để có thể tải Bootstrap Tourist các bạn có thể click vào đây hoặc truy cập vào Github Bootstrap Tourist. Tại đường link tải thư viện của tôi, tôi đã thêm vào một đối tượng MyTour để tối giản việc sử dụng Bootstrap Tourist hơn.

  Cài đặt Spring Boot CLI
  Bootstrap là gì? Tặng 20 Templates Bootstrap miễn phí
Hướng dẫn cài đặt
<link href="bootstrap.min.css" rel="stylesheet"> <link href="bootstrap-tour.min.css" rel="stylesheet"> <script src="jquery.min.js"></script> <script src="bootstrap.min.js"></script> <script src="bootstrap-tour.min.js"></script> <!-- Phần mở rộng tôi viết thêm --> <script src="bootstrap-tourist.extension.com.min.js"></script>

Ngoài ra phần mở rộng tôi viết có sử dụng linq.js mà tôi đã có bài viết Thư viện Linq.js trong javascript

Hướng dẫn sử dụng

Tại các element trên website, những chỗ mà các bạn muốn làm các hướng dẫn cho khách hàng (các bước trong tour) thì các element cần phải có các attribute sau đây

  1. data-tour-header: Tiêu đề của box hướng dẫn khi xuất hiện
  2. data-tour: Nội dung của box hướng dẫn khi xuất hiện
  3. data-tour-position: Vị trí hiển thị. Có 4 giá trị: left,right,bottom,top

Ví dụ như hướng dẫn hiển thị ở tiêu đề bài viết này

<h2 class="post-title text-danger tour-tourist-0-element" data-tour-header="Đây là tiêu đề bài viết" data-tour="Hướng dẫn sử dụng bootstrap tourist để làm trợ giúp cho phần mềm" data-tour-id="2244" data-tour-position="bottom">Hướng dẫn sử dụng bootstrap tourist để làm trợ giúp cho phần mềm</h2>

Tiếp đến các bạn gọi hàm trên javascript để thực thi

var tour = new MyTour({ area: $("body") }); tour.init(); $("[data-btn=StartTour]").click(function () {     tour.start(); });

Ở đây tham số khi khởi tạo MyTour các bạn có thể tham khảo chi tiết Document tại https://github.com/IGreatlyDislikeJavascript/bootstrap-tourist.

Đây là một số hình ảnh tôi sử dụng bootstrap-tourist trên phần mềm của tôi

Bấm vào nút dấu ? để bắt đầu tour

Thực hiện từng bước hướng dẫn

Rất dễ cho khách hàng đúng không các bạn

Chúc các bạn áp dụng tiện ích này vào sản phẩm của mình thành công

Sơn 20

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

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

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

Kiểu dữ liệu Boolean và toán tử logic AND, OR, NOT trong Python

Kiểu dữ liệu Boolean và các toán tử AND OR NOT trong Python

Trong các bài trước chúng ta đã làm quen với các kiểu dữ liệu số nguyên (int), số thập phân (float) và kiểu chuỗi (string) trong Python. Tiếp theo, chúng ta sẽ làm quen với một kiểu dữ liệu khác là Boolean, một kiểu dữ liệu được sử dụng trong hầu hết các ngôn ngữ lập trình hiện nay. Cùng TopDev tìm hiểu về Boolean trong Python và các toán tử AND OR NOT thông qua các ví dụ minh họa thật chi tiết.

Xem thêm nhiều việc làm Python lương cao trên TopDev

Kiểu dữ liệu Boolean trong Python

Boolean hay Bool trong python là gì? Boolean là kiểu dữ liệu mà mọi ngôn ngữ lập trình ngày này đều sử dụng, và tất nhiên Boolean cũng là một kiểu dữ liệu trong Python.

Boolean đại diện cho hai giá trị logic duy nhất là: đúng (True) và sai (False).

Lưu ý khi code, giá trị True/False phải viết hoa, nếu không sẽ bị báo lỗi.

Trong máy tính, kiểu dữ liệu này được lưu trữ trên 1 bit (là đơn vị lưu trữ nhỏ nhất), có giá trị là 1 hoặc 0.

Thông thường, các giá trị Boolean là True hoặc False không được gán trực tiếp với biến mà thông qua một phép so sánh, ví dụ:

age = 20
is_over_age = age >= 18
is_under_age = age < 18
is_twenty = age == 20

Một biểu thức so sánh sẽ trả về kết quả là dạng Boolean tức là True hay False. Chúng ta có các phép so sánh thường dùng như:

  • > Lớn hơn
  • >= Lớn hơn hoặc bằng
  • == So sánh bằng
  • < Nhỏ hơn
  • <= Nhỏ hơn hoặc bằng.
  • is so sánh hai đối tượng có bằng nhau không
  • is not: phủ định của is
  Biến và kiểu dữ liệu cơ bản trong Python
  Lệnh if, elif, if else trong Python là gì?

Toán tử logic boolean NOT, AND và OR

Trong Python, có thể sử dụng các toán tử Logic Boolean để tạo ra những so sánh phức tạp. Danh sách các toán tử logic trong Python bao gồm:

  • and: Trả về kết quả là True nếu cả hai vế là True, trả về False nếu 1 trong hai vế là False.
  • or: Trả về kết quả là True nếu 1 trong 2 vế là True và trả về False nếu cả hai vế là False.
  • not: đứng trước một biểu thức so sánh, trả về giá trị phủ định của biểu thức đứng sau.

Toán tử logic boolean NOT, AND và OR

Toán tử NOT trong Python

Toán tử logic not là một phép toán đơn giản và chỉ tác động lên một giá trị Boolean. Nó đảo ngược giá trị của một biểu thức Boolean: nếu biểu thức là True, not sẽ biến nó thành False, và ngược lại.

  • NOT True sẽ thành False.
  • NOT False sẽ thành True.

Giả sử bạn có một biến is_raining để chỉ định xem trời có đang mưa không và bạn muốn in ra thông báo chỉ khi trời không mưa:

is_raining = False

if not is_raining:
    print("Trời không mưa, bạn có thể ra ngoài!")
else:
    print("Trời đang mưa, hãy ở trong nhà!")

Kết quả: Trời không mưa, bạn có thể ra ngoài!

Trong ví dụ này, not is_raining sẽ đảo ngược giá trị Boolean của is_raining. Vì is_rainingFalse, not is_raining sẽ là True, do đó câu lệnh print("Trời không mưa, bạn có thể ra ngoài!") được thực thi.

Toán tử AND trong Python

Phép toán and là một phép toán nhị phân (binary operator) và tác động lên hai giá trị Boolean. Kết quả của phép toán and chỉ là True khi cả hai giá trị đều là True; nếu một trong hai giá trị là False, kết quả sẽ là False:

  • True AND True sẽ là True.
  • True AND False sẽ là False.
  • False AND True sẽ là False.
  • False AND False sẽ là False.

Giả sử bạn muốn kiểm tra xem một số y có nằm trong khoảng từ 5 đến 15 hay không:

y = 12

if y > 5 and y < 15:
    print("y nằm trong khoảng từ 5 đến 15")
else:
    print("y không nằm trong khoảng từ 5 đến 15")

Kết quả: y nằm trong khoảng từ 5 đến 15

Biểu thức y > 5 and y < 15 chỉ trả về True nếu cả hai điều kiện y > 5y < 15 đều đúng.

Toán tử OR trong Python

Phép toán or cũng là một phép toán nhị phân và tác động lên hai giá trị Boolean. Kết quả của phép toán orTrue nếu ít nhất một trong hai giá trị là True. Chỉ khi cả hai giá trị đều là False, kết quả mới là False.

  • True OR True sẽ là True.
  • True OR False sẽ là True.
  • False OR True sẽ là True.
  • False OR False sẽ là False.

Sử dụng toán tử or

Nếu bạn muốn kiểm tra xem một số z có phải là số chẵn hoặc là một số dương hay không:

z = -4

if z % 2 == 0 or z > 0:
    print("z là số chẵn hoặc là số dương")
else:
    print("z không là số chẵn và không phải là số dương")

Kết quả: z là số chẵn hoặc là số dương

Trong ví dụ này, biểu thức z % 2 == 0 or z > 0 trả về Truez % 2 == 0True (vì z là số chẵn), dù z > 0False.

  Cấu trúc dữ liệu List trong Python và các thao tác cơ bản

Boolean trong các toán tử so sánh

Trong Python, các toán tử so sánh được sử dụng để so sánh hai giá trị và kết quả của các phép so sánh này luôn là một giá trị Boolean: True hoặc False. Các toán tử so sánh giúp kiểm tra mối quan hệ giữa hai biến hoặc giữa một biến và một giá trị cụ thể, và được sử dụng rộng rãi trong các câu lệnh điều kiện như if, while.

Dưới đây là bảng trình bày các toán tử so sánh trong Python và kết quả Boolean tương ứng:

Toán tử Ý nghĩa Ví dụ Kết quả
== Bằng nhau 5 == 5 True
5 == 10 False
!= Khác nhau 5 != 10 True
5 != 5 False
> Lớn hơn 10 > 5 True
5 > 10 False
< Nhỏ hơn 3 < 7 True
7 < 3 False
>= Lớn hơn hoặc bằng 10 >= 10 True
5 >= 10 False
<= Nhỏ hơn hoặc bằng 7 <= 10 True
10 <= 7 False

Kết hợp với toán tử logic:

Biểu thức Ý nghĩa Kết quả
x == z and y > x Kiểm tra xem cả hai điều kiện đều đúng hay không (x == zy > x) True
x == z or y < x Kiểm tra xem ít nhất một trong hai điều kiện đúng (x == z hoặc y < x) True
not x == z Đảo ngược kết quả của điều kiện (x == z) False

Bảng trên cung cấp cái nhìn tổng quan về cách sử dụng các toán tử so sánh và kết quả của chúng khi kết hợp với các toán tử logic Boolean trong Python.

Các toán tử logic boolean NOT, AND, và OR là nền tảng của logic trong lập trình và được sử dụng rộng rãi trong việc kiểm tra điều kiện, xây dựng biểu thức phức tạp và điều khiển luồng chương trình. Hiểu sâu sắc về kiểu dữ liệu Boolean và các toán tử NOT, AND, và OR là bước quan trọng để viết mã Python hiệu quả và logic hơn.

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

10x engineer – cắt giảm chi phí 10 lần

10x engineer - cắt giảm chi phí 10 lần

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

10x engineer là một thần thoại (myth) lâu đời trong giới IT, mơ tưởng về 1 developer có khả năng code “hơn” người bình thường 10 lần. Vì là “myth”, nên có người tin, có người không.

The Myth

Thần thoại 3x 4x 5x … 10x (xxxxxxxxxx)

Việc lên internet tìm kiếm 10x engineer trên thế giới không quá khó khăn, nhưng gặp khi đi làm ngoài thực tế là chuyện không nhiều. 10x thế giới tạm kể:

những ví dụ trên chỉ phục vụ mục đích dễ hình dung, bởi họ thuộc cỡ 100 hay 1000x chứ không phải 10x. Bí quyết là gì không rõ, nhưng điểm chung: họ đều đã ngoài 40 và dành hơn nửa cuộc đời làm software. Không có ai 30 đã về nghỉ hay lên làm manager cả.

  "Vì sao mình chọn start-up sau Facebook?" Hiếu Phạm - Software Engineer tại ROCKSET
  Biến Git và GitHub trở thành công cụ đắc lực cho Software Engineer

Tiêu chí 10x không rõ ràng, vì đây là “myth”, nên mỗi người nghĩ theo 1 kiểu. Theo một tiêu chí ví dụ, mrX gõ nhanh hơn mrY 10 lần, nên cũng có khi được gọi là 10x engineer.

Bài viết này không liên quan tới chuyện các 10x nói trên, mà đơn giản chỉ là tiết kiệm 10x chi phí chạy code Python, nhờ được học Python “tử tế”.

Ví dụ

Sinh ra 1 file .log.gz chứa 1_500_000 dòng (từ 3 dòng lặp đi lặp lại)

import gzip

lines = [
    'http 2015-05-13T23:39:43.945958Z my-loadbalancer 192.168.131.39:2817 10.0.0.1:80 0.000073 0.001048 0.000057 200 200 0 29 "GET http://www.example.com:80/index HTTP/1.1" "curl/7.38.0" - - arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337262-36d228ad5d99923122bbe354"',
    'https 2015-05-13T23:39:43.945958Z my-loadbalancer 192.168.131.39:2817 10.0.0.1:80 0.000086 0.001048 0.001337 200 200 0 57 "GET https://mytest-111.ap-northeast-1.elb.amazonaws.com:443/p/a/t/h?foo=bar&hoge=fuga HTTP/1.1" "curl/7.38.0" DHE-RSA-AES128-SHA TLSv1.2 arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337262-36d228ad5d99923122bbe354"',
    'https 2015-05-13T23:39:43.945958Z my-loadbalancer 192.168.131.39:2817 10.0.0.1:80 0.000086 0.001048 0.001337 200 200 0 57 "GET https://mytest-111.ap-northeast-1.elb.amazonaws.com:443/p/a/t/h?foo=bar&hoge=fuga:904abc HTTP/1.1" "curl/7.38.0" DHE-RSA-AES128-SHA TLSv1.2 arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337262-36d228ad5d99923122bbe354"',
]
with gzip.open("bigfile.log.gz", "wb") as fout:
    i = 0
    while i < 1_500_000:
        line = lines[i % len(lines)] + "\n"
        fout.write(line.encode('utf-8'))
        i = i + 1

File này có kích thước khá nhỏ (<10MB)

$ python makelog.py; ls -la bigfile.log.gz
-rw-rw-r-- 1 hvn hvn 2960897 Jun 30 22:42 bigfile.log.gz
$ gunzip bigfile.log.gz; wc -l bigfile.log; ls -l bigfile.log
1500000 bigfile.log
-rw-rw-r-- 1 hvn hvn 559000000 Jun 30 22:42 bigfile.log
$ ls -lh bigfile.log
-rw-rw-r-- 1 hvn hvn 534M Jun 30 22:42 bigfile.log

nhưng khi giải nén, kích thước lớn hơn rất nhiều lần (do dữ liệu trùng lặp nhiều nên nén lại từ to thành rất nhỏ).

Đây là đoạn code ban đầu, nó đọc các dòng text từ 1 file có đuôi .log.gz ra. Hãy xem kỹ xem bạn có thể “tối ưu” được bao nhiêu bước và trở thành mấy x từ đây?

Code albv1.py

import gzip

i = 0
with gzip.open("bigfile.log.gz", "rt") as f:
    for line in f.readlines():
        i = i + 1
        if i == 10:
            break

print("Proceeded {} lines".format(i))

File nén có đuôi .gz được tạo bởi các chương trình gzip, bên dưới dùng thư viện zlibThư viện gzip của Python cho phép mở file .gz như file text bình thường, nó thực hiện giải nén phía sau bức màn bí mật. Mode mở file rt giúp lib gzip hiểu ta muốn thu được str sau khi giải nén, còn khi mặc định nó mở ở mode rb, trả về kiểu bytes. Chạy đoạn code trên, sử dụng /usr/bin/time -v để đo thời gian chạy và các thông số chi tiết về bộ nhớ max. (trên MacOS dùng -l)

$ /usr/bin/time -v python3 albv1.py
Proceeded 10 lines
    ...
    Maximum resident set size (kbytes): 693652
    ...

Code này dùng ~ 600 MB RAM.

Sau khi thay đổi, code chỉ còn dùng ~ 9MB RAM

$ /usr/bin/time -v python3 albv2.py
Proceeded 10 lines
    ...
    Maximum resident set size (kbytes): 9752
    ...

Chỉ thay đổi duy nhất 1 dòng:

$ diff albv1.py albv2.py
12c12
<     for line in f.readlines():
---
>     for line in f:

Điều này bất kỳ học viên Pymi.vn nào cũng phát hiện ra ngay, bởi trong hệ thống bài tập đã có 1 bài xử lý file 30 triệu dòng nặng hơn 500 MB tương tự. Cách xử lý từng dòng một:

for line in f:

mà không dùng f.readlines() hay f.read(), vì chúng đọc toàn bộ nội dung file từ ổ cứng vào RAM. Chú ý cả sự chênh lệch, Python đọc file text 534MB vào thành 670MB RAM.

“Bí kíp” đọc file theo dòng này dù chẳng có gì đặc biệt, ghi rõ trong tài liệu trang chủ nhưng lại trở thành chuyện lạ với hàng ngàn bài hướng dẫn trên mạng, thậm chí cả sách cũng dạy dùng readlines. Hãy thử search github có tới hơn 2 triệu kết quả, dù cho github không search chính xác được, thì chuyện này vẫn không phải là hiếm.

Search StackOverFlow python read file into list, trả về hàng loạt kết quả cũng không ổn tí nào.

readlines hay read hoàn toàn ok khi lập trình viên làm chủ được kích thước file đầu vào (file cố định, file được cam kết là nhỏ), nhưng khi file có size tới hàng MB, nó sẽ chiếm không ít RAM để chạy chương trình.

Phiên bản v2 có thể xử lý file có kích thước lớn tùy ý, 10GB, 100GB, đều vẫn chỉ dùng < 10MB (với giả thiết kích thước mỗi dòng không quá khác biệt).

Vậy chỉ cần được học Python tử tế, đã trở thành 10x rồi.

Độ đo

Để tính mấy x cho rõ ràng, bài này sẽ sử dụng đơn vị đo mà loài người ưa chuộng nhất: tiền.

Tính tiền 1 chương trình trong 1 cái máy thì khá khó, nhưng ngày nay, khi “cloud computing” là thời thượng, chạy code trên AWS lambda giúp chuyện tính tiền dễ như học toán cấp 1. Xem AWS Lambda pricing

Tiền cũng là thước đo lý tưởng khi các công ty ngày nay đua theo “performance review”, “360 review”, “data driven”… Một dòng review ghi: “cắt giảm chi phí 70.000 đô la Biden/năm nhờ tối ưu code” sẽ giúp manager dễ hiểu, dễ đánh giá hơn hẳn viết “tăng tốc chương trình 100 lần nhờ tối ưu regex sử dụng non greedy-matching” hay “cải thiện tính đọc được và tính ổn định của code”.

Theo thử nghiệm trên máy, hai phiên bản v1 và v2 chạy về tốc độ là như nhau (hoặc chênh 1 2 3 giây trên tổng 60s không đáng kể), thì phần còn lại của biểu thức phụ thuộc vào lượng RAM sử dụng. Tăng cấu hình RAM cho Lambda function bao nhiêu lần, thì giá gấp bấy nhiêu. Code đăng ký dùng 256 MB RAM sẽ có giá đắt gấp đôi code đăng ký 128MB. Với ví dụ trong bài, mỗi file log kích thước cỡ 300-600 MB, lập trình viên sẽ thường để mức an toàn là 1024MB (1GB) tránh tình trạng có file 800MB xuất hiện mà thiếu RAM.

Code v2 luôn dùng 10MB RAM (=> 100x), nhưng mức tối thiểu AWS Lambda cho phép là 128MB, vậy ở đây tiết kiệm 8 lần => 8x.

Cú twist giật mình: câu chuyện thực ra không đơn giản vậy, với nhiều RAM hơn, AWS Lambda sẽ cấp thêm “năng lượng” cho CPU tỷ lệ với RAM, trong ví dụ này, nếu hầu hết thời gian chương trình đều để dùng CPU, giảm 8x RAM đăng ký đồng nghĩa với giảm tốc độ CPU 8 lần. Hay kết quả là v2 chạy mất 8s x 128MB thì v1 chạy mất 1s x 1024 MB, và giá tiền là như nhau.

Lambda allocates CPU power in proportion to the amount of memory configured. Memory is the amount of memory available to your Lambda function at runtime. You can increase or decrease the memory and CPU power allocated to your function using the Memory (MB) setting. To configure the memory for your function, set a value between 128 MB and 10,240 MB in 1-MB increments. At 1,769 MB, a function has the equivalent of one vCPU (one vCPU-second of credits per second).

Lambda configuration memory

Theo tài liệu này, nếu function chỉ sử dụng 1 core (code không sử dụng thư viện multiprocess), tốc độ CPU của nó đạt tối đa khi cấu hình 1769MB, dù có tăng RAM lên 2048MB thì chỉ tăng thêm 1 core nữa chứ không làm core ban đầu mạnh lên, hay nói cách khác: không làm code chạy nhanh hơn.

PS: trong môi trường lượng CPU là cố định (máy ảo, máy vật lý…), v2 vẫn là 100x.

Cú twist số 2: việc tính tiền trên các hệ thống cloud không hề đơn giản, có hàng ngàn dịch vụ cung cấp giải pháp phân tích, đọc hiểu, tối ưu code cloud. Hay mọc cả ra nghề FinOps chuyên về tối ưu hóa cloud cost, ngành kinh tế trên mây (cloud economics) với các chuyên gia có nghệ danh “cloud economist”.

Kết luận 1: 100x là có thật, nhưng còn phụ thuộc vào hoàn cảnh, không nằm ngoài “thuyết tương đối”. Việc giảm 8x RAM ở đây không làm giảm chi phí, công việc tiếp theo là cắt giảm chi phí bằng cách tăng tốc code.

Tuy không cải thiện về đơn vị đo của bài này là tiền, nhưng một đoạn code không chỉ có mỗi tiền, ngoài hiệu năng, nó còn nhiều tiêu chí khác khó đánh giá hơn như “tính đọc được” (code dễ đọc), “tính ổn định”,… Dùng for line in f cải thiện được tính ổn định của chương trình, cho phép nó chạy ngon lành khi kích thước file đầu vào tăng lên – trong khi chương trình ban đầu sẽ lỗi do không đủ RAM.

Tăng tốc regex

Phiên bản sau thêm công đoạn xử lý từng dòng để lọc ra các giá trị mong muốn, sử dụng công cụ: “regular expression” – hay gọi ngắn là regex. Bạn đọc không nên quá tập trung hay sợ hãi khi nhìn vào phần “pattern” viết đống giun dế gì, vì không nhiều người có khả năng đọc, hiểu, phân tích đoạn này, kể cả có 10 năm đi code hay làm sysadmin. Code regex thường khó đọc khó hiểu, khi cần dùng chủ yếu các lập trình viên đi copy, đoạn bên dưới cũng là copy từ link trong comment.

import gzip
import regex

# copied and edited from https://gist.github.com/szinck/d456fbf691483ab77d2453c316db3371
pattern = '(.*?) (.*?) (.*?) ([0-9.]+):([0-9]*) ([0-9.]+):([0-9]*) ([.0-9]*) ([.0-9]*) ([.0-9]*) (-|[0-9]*) (-|[0-9]*) ([-0-9]*) ([-0-9]*) "(.*?) .*:([0-9]+)([^? ]*)(\\x3f?.*?) (.*?)" "(.*?)" (.*?) (.*?) (.*?) "(.*?)" *$'
# example in AWS docs does not work directly with python https://docs.aws.amazon.com/athena/latest/ug/application-load-balancer-logs.html

p = re.compile(pattern)

i = 0
with gzip.open("bigfile.log.gz", "rt") as f:
    for line in f.readlines():
        i = i + 1
        m = p.match(line)
        if m:
            result = " ".join(m.group(17, 11))
            # print("sending", result)
        if i == 10:
            break

print("Proceeded {} lines".format(i))

Không hiểu gì thì làm sao mà tăng tốc?

Học regex trong 7 phút

7 phút đủ để quán bia làm xong món “giò nóng 7 phút”. Trong 7 phút đủ để bạn có kiến thức regex bằng với 90% lập trình viên trên thế giới.

regex là gì

regex là một ngôn ngữ dùng để mô tả pattern (tiếng Việt hay dịch là dạng, mẫu) của 1 giá trị. Ví dụ: một số điện thoại di động ở Việt Nam là một số có 10 hay 11 chữ số. Các pattern sau sẽ “match” (khớp mẫu) số điện thoại:

  • \d+
  • [0-9]+

Hai pattern này tương đương, nó sẽ match với 1 hoặc nhiều chữ số viết liền nhau. Dấu + theo sau là biểu diễn cho “1 hoặc nhiều”. Phổ biến không kém dấu +, là dấu *. Dấu * có nghĩa là match 0 hoặc nhiều:

  • \d*
  • [0-9]*

cũng sẽ match số điện thoại di động ở Việt Nam.

Dùng + khẳng định phải có ít nhất 1 số từ 0 đến 9 (ký hiệu [0-9]), thì dùng * dễ dãi hơn, không có số nào cũng được. Pattern .* là pattern phổ biến nhất với người học regex với thời lượng dưới 5 ngày.

. đại diện cho 1 ký tự nào đó, nào cũng được, a b c hay 0 1 2 hay % = # gì cũng ok. .* là pattern match được mọi thứ.

Tránh nhầm lẫn dấu * hay thấy khi gõ câu lệnh Linux, kiểu như ls ~/*.py* này không phải regex, đây là khái niệm globbing, mặc dù tác dụng hơi giống, nó sẽ trả về tất cả các tên file có đuôi .py

Dấu ? match 0 hoặc 1 lần, pattern https? sẽ match cả http lẫn https.

Dùng trang regex101.com để thử các pattern và xem kết quả cho tiện.

Hay bật python3 lên rồi gõ

>>> import re
>>> re.findall('.*', '0987654321')
['0987654321', '']

Có thể chỉ định số lần match với cú pháp {ít nhất, nhiều nhất}, pattern 0[0-9]{9, 10} match số điện thoại di động ở Việt Nam.

Đơn giản, đúng không? Hãy viết 1 đoạn regex để kiểm tra 1 email có hợp lệ không.

Mọi người đều biết “chung chung” là email có dạng gìđó@gìđấy.đuôi, vậy regex có thể là .+@.+\..+. Chú ý dấu . trong tên miền phải gõ \., vì dấu . là 1 ký hiệu regex đặc biệt đã nói ở trên. Đây là regex đầy đủ để kiểm tra 1 địa chỉ email, và không có một ai trên trái đất này cho rằng nó đơn giản cả.

Đến đây, đã có 1 manh mối để tối ưu tốc độ rồi… re là standard library của Python, có sẵn, không cài gì cả. Nhưng đoạn code trên lại import 1 thư viện tên regex. Đây là thư viện phải cài thêm,

This regex implementation is backwards-compatible with the standard ‘re’ module, but offers additional functionality.

Thử thay regex bằng re giúp cắt giảm 10s trong đoạn code chạy 60s trên máy tác giả. Có thể “đoán” rằng re có trong stdlib và được tối ưu đủ trò nên chạy nhanh hơn. Những việc đoán này phải dựa trên cơ sở đo. Để đo tốc độ trong Python, python có sãn thư viện cProfile.

Profiling Python với cProfile

Thay regex bằng re, chạy lại đoạn code với câu lệnh sau để xem các function nào dùng nhiều thời gian nhất/gọi nhiều lần nhất.

  • tottime total time: tổng thời gian function chạy sau N lần, không tính chuyện gọi function khác.
  • cumtime cummulative time: tổng thời gian function chạy sau N lần, bao gồm cả việc gọi các function khác.
$ /usr/bin/time -v python3 -m cProfile -s tottime albv1.py
Proceeded 50000 lines
         252074 function calls (251832 primitive calls) in 45.948 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    50000   45.834    0.001   45.834    0.001 {method 'match' of 're.Pattern' objects}
        1    0.033    0.033   45.948   45.948 albv1.py:1(<module>)
        1    0.016    0.016    0.061    0.061 {method 'readlines' of '_io._IOBase' objects}
     2277    0.014    0.000    0.014    0.000 {built-in method zlib.crc32}
    50000    0.012    0.000    0.012    0.000 {method 'group' of 're.Match' objects}
     2275    0.008    0.000    0.008    0.000 {method 'decompress' of 'zlib.Decompress' objects}
    50054    0.005    0.000    0.005    0.000 {method 'join' of 'str' objects}
    52282    0.004    0.000    0.004    0.000 gzip.py:314(closed)
     2276    0.004    0.000    0.034    0.000 _compression.py:66(readinto)

Kết quả cho thấy hầu hết thời gian đều dùng vào việc chạy regex method matchre viết bằng C, lẽ ra phải chạy rất nhanh, thì khi copy thử pattern và 1 ví dụ lên regex101, sẽ thấy lý do vì sao nó chậm. Để kiểm tra pattern có match string ví dụ sau không, re phải dùng tới 112690 bước!!!

http 2015-05-13T23:39:43.945958Z my-loadbalancer 192.168.131.39:2817 10.0.0.1:80 0.000073 0.001048 0.000057 200 200 0 29 “GET http://www. example.com:80/index HTTP/1.1” “curl/7.38.0″ – – arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 ” Root=1-58337262-36d228ad5d99923122bbe354″

con số này quá lớn, dù có viết đoạn code lằng nhằng với 20 câu if, cũng không thể tới 112690 bước. Tăng tốc regex không phải chuyện dễ, nhưng có 1 tip rất phổ biến: chỗ nào dùng .* chỗ đó có vẻ chậm/sai/cần tối ưu (khác với .*?).

Đoạn regex mới

pattern = '(.*?) (.*?) (.*?) ([0-9.]+):([0-9]*) ([0-9.]+):([0-9]*) ([.0-9]*) ([.0-9]*) ([.0-9]*) (-|[0-9]*) (-|[0-9]*) ([-0-9]*) ([-0-9]*) "(.*?) https?://[^:]+:([0-9]+)([^? ]*)(\\x3f?.*?) (.*?)" "(.*?)" (.*?) (.*?) (.*?) "(.*?)" *$'

có 1 điểm khác so với đoạn cũ

pattern = '(.*?) (.*?) (.*?) ([0-9.]+):([0-9]*) ([0-9.]+):([0-9]*) ([.0-9]*) ([.0-9]*) ([.0-9]*) (-|[0-9]*) (-|[0-9]*) ([-0-9]*) ([-0-9]*) "(.*?) .*:([0-9]+)([^? ]*)(\\x3f?.*?) (.*?)" "(.*?)" (.*?) (.*?) (.*?) "(.*?)" *$'

chỗ .*:([0-9]+) dùng để match domain và port như https://pymi.vn:443, thay .* trong đoạn này với https?://[^:]+ cho tác dụng tương đương. https?://[^:]+ match 1 đoạn text bắt đầu bằng http hay https, rồi :// rồi bất cứ thứ gì cho tới khi gặp dấu : thì dừng lại. Đoạn này match sau 524 bước

Chú ý đoạn code mới cho rằng mọi url đều bắt đầu với http hay https, điều này có thể sai (ví dụ wss:// cho websocket), tùy theo yêu cầu bài toán.

Một cách khác, là dùng pattern [^:]+:[^:]+: match mọi thứ có dạng something:something dừng lại khi gặp dấu : thứ 2. Pattern sẽ match wss://abcde trong string wss://abcde:443, pattern này match sau 518 bước.

Một cách khác nữa, là dùng .+?:.+?:+ và * bình thường sẽ match nhiều nhất có thể, thì khi thêm ? sau nó, +? hay *? sẽ match ít nhất có thể. Đây gọi là tính năng non-greedy Cho string abcdabcda.+d sẽ match abcdabcd nhưng a.+?d chỉ match abcd. Pattern này match sau 543 bước.

Dấu đóng mở ngoặc () dùng để capture kết quả, kết quả match thành công sẽ được lưu lại thành 1 group, đánh theo thứ tự xuất hiện. Đoạn code trong bài lấy ra group 17 và 11 từ kết quả match.

$ /usr/bin/time -v python3 -m cProfile -s tottime albv1_regex.py

Proceeded 50000 lines
         252201 function calls (251956 primitive calls) in 0.310 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    50000    0.208    0.000    0.208    0.000 {method 'match' of 're.Pattern' objects}
        1    0.026    0.026    0.310    0.310 albv1_regex.py:1(<module>)
        1    0.016    0.016    0.061    0.061 {method 'readlines' of '_io._IOBase' objects}
     2277    0.014    0.000    0.014    0.000 {built-in method zlib.crc32}
    50000    0.008    0.000    0.008    0.000 {method 'group' of 're.Match' objects}
     2275    0.008    0.000    0.008    0.000 {method 'decompress' of 'zlib.Decompress' objects}
    52282    0.004    0.000    0.004    0.000 gzip.py:314(closed)
    50054    0.004    0.000    0.004    0.000 {method 'join' of 'str' objects}
     2276    0.004    0.000    0.030    0.000 gzip.py:454(read)

45 giây -> xuống còn 0.3 giây cho ta cảm giác code mới chắc là sai nên mới 150x như vậy.

Sửa regex xong làm sao biết đúng sai?

Một cách đơn giản là thử, cho 2 pattern match và lấy kết quả ra rồi so sánh lần lượt với mỗi dòng log, qua cả file đều giống nhau là có vẻ ổn rồi.

p1 = re.compile(pattern1)
p2 = re.compile(pattern2)

for line in f:
    m1 = p1.match(line)
    m2 = p2.match(line)
    if m1:
        assert m1.groups() == m2.group(), (m1, m2, line)

PS: khi tối ưu đoạn code này, vô tình phát hiện ra đoạn code ban đầu xử lý không đúng khi URL path có chứa dấu :, 3 phiên bản mới không gặp phải vấn đề này.

Kết luận 2: 150x là có thật và không cần phải học “regex” nâng cao.

Học và dùng regex

Python có viết 1 tài liệu cơ bản về regex trong mục howto, nếu một ngày buồn chán quá không có gì làm, hay muốn tìm ý nghĩa của cuộc sống, bạn có thể ngồi học regex.

xkcd

Hoặc đi tìm một “khóa học regex”? cái này chưa có, cơ hội khởi nghiệp làm giàu còn rất rộng mở cho các chuyên gia công nghệ bán “khoá học làm chủ regex để học sâu với trí tuệ nhân tạo 4.0”.

Regex là một công cụ mạnh, nhưng khó dùng đúng, nó giải quyết được 1 số bài toán, 1 số thì không và nên dùng cách khác đơn giản hơn như parse HTML.

regex nổi tiếng phức tạp, và từng tạo ra không ít sự cố trong các hệ thống lớn toàn cầu.

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.

Khi một bài toán có thể giải quyết theo 1 cách khác đơn giản hơn, thì nên tránh dùng regex.

Chú ý: trong ví dụ này, nhằm mục tiêu giữ lại code gần giống với code ban đầu nhất, không thay đổi quá nhiều, nên đã không viết lại đoạn code lọc ra urlpath và statuscode mà vẫn dùng regex.

Tăng tốc gửi message đến kafka

Kafka là gì

Apache Kafka is an open-source distributed event streaming platform used by thousands of companies for high-performance data pipelines, streaming analytics, data integration, and mission-critical applications.

https://kafka.apache.org/

Nói đơn giản, Kafka như hệ thống ống nước, mạng lưới điện, mạng lưới viễn thông, nó đủ tính năng để đáp ứng mọi nhu cầu truyền tải dữ liệu từ nhiều nguồn đến nhiều đích. Kafka được dùng phổ biến trong các doanh nghiệp, các hệ thống xử lý data, logging…

Kafka có nhiều tính năng, bài này sử dụng nó như 1 hệ thống pub-sub, tức có 1 bên gửi message đi, và 1/nhiều bên nhận message.

Cài đặt kafka

Cài Java

sudo apt-get update && sudo apt-get install -y openjdk-11-jre-headless

Cài đặt kafka đơn giản với 5 bước không cần sudo

curl -LO https://mirror.downloadvn.com/apache/kafka/2.8.0/kafka_2.13-2.8.0.tgz
tar xvf kafka_2.13-2.8.0.tgz
cd kafka_2.13-2.8.0
bin/zookeeper-server-start.sh config/zookeeper.properties
## mở 1 terminal khác
cd kafka_2.13-2.8.0
bin/kafka-server-start.sh config/server.properties

Python Kafka producer

Phiên bản đầy đủ của chương trình trước khi mang đi tối ưu: nó đọc file log AWS ALB đã nén .gz, lấy ra urlpath và status code bằng regex, rồi gửi kết quả đến kafka.

pip install kafka-python
import gzip
import re
from kafka import KafkaProducer

producer = KafkaProducer(linger_ms=5, batch_size=65536, acks=0, compression_type="lz4")

pattern = '(.*?) (.*?) (.*?) ([0-9.]+):([0-9]*) ([0-9.]+):([0-9]*) ([.0-9]*) ([.0-9]*) ([.0-9]*) (-|[0-9]*) (-|[0-9]*) ([-0-9]*) ([-0-9]*) "(.*?) [^:]+:[^:]+:([0-9]+)([^? ]*)(\\x3f?.*?) (.*?)" "(.*?)" (.*?) (.*?) (.*?) "(.*?)" *$'
p = re.compile(pattern)

i = 0
with gzip.open("bigfile.log.gz", "rt") as f:
    for line in f:
        i = i + 1
        if i % 10000 == 0:
            print(i)
        m = p.match(line)
        if m:
            result = " ".join(m.group(17, 11))
            producer.send("alblog", result.encode("utf-8"))

print("Processed {} lines".format(i))

Khi chưa gửi message tới kafka, code chạy mất 8s, khi gửi đến kafka trên cùng máy, code chạy mất 60s (khi profile chậm hơn nữa do quá trình profile can thiệp ảnh hưởng tới tốc độ):

Processed 1500000 lines
         133875187 function calls (133873425 primitive calls) in 91.895 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1500001    8.978    0.000    8.978    0.000 {method 'match' of 're.Pattern' objects}
  1500000    8.602    0.000   73.735    0.000 kafka.py:538(send)
  1500282    7.845    0.000   14.095    0.000 default_records.py:406(append)
  1500000    6.948    0.000   39.138    0.000 record_accumulator.py:200(append)
  1500282    4.675    0.000   28.579    0.000 record_accumulator.py:57(try_append)
        1    4.299    4.299   92.439   92.439 albv1_regex2.py:1(<module>)
  1500000    4.147    0.000    6.439    0.000 future.py:32(__init__)
  7501128    3.138    0.000    4.001    0.000 util.py:10(encode_varint)
  1500000    2.754    0.000   12.242    0.000 kafka.py:716(_partition)
  3000001    2.270    0.000    2.688    0.000 cluster.py:106(partitions_for_topic)
  1500000    1.946    0.000    4.090    0.000 cluster.py:119(available_partitions_for_topic)
  1500000    1.840    0.000    4.318    0.000 kafka.py:664(_wait_on_metadata)
    65554    1.721    0.000    1.721    0.000 {built-in method zlib.crc32}
  1500000    1.682    0.000    2.811    0.000 default_records.py:563(size_of)
15397286/15397055    1.615    0.000    1.615    0.000 {built-in method builtins.len}
...

Việc gửi 1.5 triệu message tới kafka chạy cùng máy mất tới 73s (cumtime) trong output profiling. Trong đó có dòng thứ 3, 4 và 5 đều là “append”. Mở code của thư viện kafka-python ra xem, phần này append các message vào 1 list “accumulator”, để bao giờ đủ 65536 phần tử mới gửi đi (batch_size=65536 lúc tạo producer). Batching là tính năng phổ biến trong các thư viện liên quan tới network, do việc gửi nhận qua network thường chậm, nên gom lại một đống rồi gửi đi để giảm số lần gửi/nhận. Nhưng trong ví dụ này, việc batching tốn tới 20s thì có vẻ không ổn. Sau một hồi chỉnh sửa các tham số (batch_size, linger_ms …), giải pháp lại là “think outside of the box”, tìm xem Python còn có thư viện kafka nào khác không.

Thư viện confluent-kafka-python sử dụng librdkafka viết bằng C hứa hẹn cho một performance tốt hơn nhiều

import gzip
import re
from confluent_kafka import Producer


producer = Producer(
    {'bootstrap.servers': "localhost:9092",
    'queue.buffering.max.messages': 65536,
    'acks': 0,
     'compression.type': 'lz4'}
)


pattern = '(.*?) (.*?) (.*?) ([0-9.]+):([0-9]*) ([0-9.]+):([0-9]*) ([.0-9]*) ([.0-9]*) ([.0-9]*) (-|[0-9]*) (-|[0-9]*) ([-0-9]*) ([-0-9]*) "(.*?) [^:]+:[^:]+:([0-9]+)([^? ]*)(\\x3f?.*?) (.*?)" "(.*?)" (.*?) (.*?) (.*?) "(.*?)" *$'

p = re.compile(pattern)

i = 0
with gzip.open("bigfile.log.gz", "rt") as f:
    for line in f:
        i = i + 1
        if i % 10000 == 0:
            print(i)
        m = p.match(line)
        if m:
            result = " ".join(m.group(17, 11))
            try:
                producer.produce("alblog", result.encode("utf-8"))
                producer.poll(0)
            except BufferError:
                print("Buffer full, waiting for free space on the queue")
                producer.poll(1)
    producer.flush()

print("Processed {} lines".format(i))

và thực nghiệm thấy đúng là như thế:

Processed 1500000 lines
         11882360 function calls (11882085 primitive calls) in 21.700 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1500000    9.328    0.000    9.328    0.000 {method 'match' of 're.Pattern' objects}
  1500000    4.197    0.000    4.197    0.000 {method 'produce' of 'cimpl.Producer' objects}
        1    3.457    3.457   21.700   21.700 albv1_regex2.py:1(<module>)
  1500000    1.511    0.000    1.511    0.000 {method 'poll' of 'cimpl.Producer' objects}
    65554    0.519    0.000    0.519    0.000 {built-in method zlib.crc32}
  1500000    0.410    0.000    0.410    0.000 {method 'group' of 're.Match' objects}
    65552    0.386    0.000    0.386    0.000 {method 'decompress' of 'zlib.Decompress' objects}
  1565559    0.255    0.000    0.255    0.000 gzip.py:314(closed)
  1500117    0.232    0.000    0.232    0.000 {method 'join' of 'str' objects}
    65553    0.218    0.000    1.687    0.000 _compression.py:66(readinto)
    65553    0.207    0.000    1.417    0.000 gzip.py:454(read)

Từ 91s -> 21.7s, ta rút gọn thêm được 4x.

Kết luận 3: thư viện có this có that, hãy tự đo và kiểm tra các options.

Kết quả

Sau 3 lần tối ưu, code mới dùng 100x ít RAM hơn, nhanh gấp 150 * 4 == 600 lần code ban đầu, chi phí giảm: 600 lần so với ban đầu. Giả sử đoạn code này hiện đang tốn $6000/tháng (6 * 12 = $72k/năm), thì sau khi tối ưu còn $10/tháng -> $120/năm.

$70.000 mỗi năm được tiết kiệm này nên dùng để thưởng nóng cho 10x dev hay chỉ thưởng $7k?

Thực tế (kinh tế) thì không phải thế, thưởng nóng $1-2-3k đã là nhiều lắm rồi. Không bàn tới chuyện quản lý doanh nghiệp/nhân sự/kinh tế ở đây, nhưng có thể thấy 1 điều, 1 lập trình viên có mức lương cao ngất ngưởng không phải là chuyện vô lý, khi họ có thể tự trả lương cho mình 1 vài năm trong vòng 1 2 ngày tối ưu code.

Kết luận

10x engineering là có thật. 10x phụ thuộc vào hoàn cảnh, tiêu chí đánh giá, nhưng học Python tại PyMi.vn rõ ràng là khoản đầu tư 10x. Việc tối ưu code, sử dụng cProfile của Python là một công việc thú vị, nhưng cần đặt vào đúng chỗ. Tối ưu đoạn code tiêu tốn $72k/năm để còn $120/năm mang lại lợi ích kinh tế khác biệt (trong môi trường doanh nghiệp) so với tối ưu đoạn code $72/năm còn $0.12/năm.

Bạn đọc đam mê có thể tiếp tục tối ưu và gửi kết quả tới tác giả bằng cách tạo 1 pull request trên GitHub. Ngoài ra, có thể viết hẳn 1 chương trình hẳn hoi giúp lấy log AWS load balancer về rồi gửi tới 1 đích đến tùy ý. Đây là một vấn đề phổ biến khi dùng AWS Load Balancer mà chưa có giải pháp triệt để.

Không phải kết luận

Giống như mọi bài viết về optimize/benchmark, kết quả rất phụ thuộc và bài toán cụ thể, môi trường (phiên bản, hệ điều hành …) cụ thể. Bài viết này KHÔNG kết luận:

  • for line in f nhanh hay chậm hơn for line in f.readlines()
  • Lib re nhanh hơn lib regex
  • confluent-kafka-python nhanh hơn kafka-python

Kết quả có thể hoàn toàn bị đảo ngược khi test trên 1 hệ điều hành khác (như MacOS, Windows) hay một phiên bản Python/thư viện khác, hay từng đoạn code chạy riêng sẽ khác với khi 2,3 đoạn code kết hợp lại. Kết luận chỉ nên đưa ra khi đem đi chạy thật với tình huống cụ thể, đến lúc tính tiền.

References

Hết

Bài viết thực hiện trên

$ grep VERSION= /etc/os-release; python3 --version
VERSION="20.04.2 LTS (Focal Fossa)"
Python 3.8.5

HVN at http://pymi.vn and https://www.familug.org.

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 Việc làm IT hấp dẫn trên TopDev

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

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

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript).

Eslint là một package (thư viện) cho phép tìm và sửa các vấn đề trong project typescript. Ví dụ như các vấn đề format code, cú pháp…

Thử tưởng tượng, nhiều người cùng code chung 1 project, nhưng người thì để tag, người thì dùng space; người thì dùng double quote, người thì dùng single quote… như thế khi gộp lại sẽ rất rối mắt và dễ gây conflict. Trong trường hợp này, eslint sẽ giúp chúng ta tìm các lỗi format và tự động sửa lại theo 1 chuẩn định nghĩa sẵn. Với các lỗi ko thể tự sửa thì nó sẽ báo lỗi/cảnh báo để cho ta sửa.

(lúc trước người ta dùng tslint, nhưng tslint hiện tại đã bị decrepated, và chuyển sang dùng eslint)

Tuyển lập trình viên Typescript lương cao

Áp dụng Eslint cho project TypeScript

Mình có 1 project TypeScript đơn giản như sau: (Xem lại: tạo project TypeScript)

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Cài package eslint bằng lệnh:

npm install eslint --save-dev
  • package eslint chỉ dùng để tìm và xử lý các vấn đề trước khi build nên ta chỉ cần lưu ở môi trường dev (--save-dev)

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Sau khi cài đặt xong eslint, ta cấu hình eslint bằng lệnh:

npx eslint --init

Khi chạy lệnh này, ta sẽ được chọn các cấu hình và mục đích sử dụng eslint

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Riêng phần định nghĩa style cho project thì mình tự định nghĩa style của mình như sử dụng single quote, kết thúc file bằng LF (linux)…

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript) Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Kết quả: file .eslintrc.json được tạo ra (file này có thể ko phải là .json mà có thể là file .yaml hoặc javascript tùy lựa chọn của bạn)

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Đây là file .eslintrc.json của mình

{

"env": {

"browser": true,

"commonjs": true,

"es2021": true

},

"extends": [

"eslint:recommended",

"plugin:@typescript-eslint/recommended"

],

"parser": "@typescript-eslint/parser",

"parserOptions": {

"ecmaVersion": 12

},

"plugins": [

"@typescript-eslint"

],

"rules": {

"indent": [

"error",

4

],

"linebreak-style": [

"error",

"unix"

],

"quotes": [

"error",

"single"

],

"semi": [

"error",

"always"

]

}

}

Trong phần rules sẽ định nghĩa các rule đã chọn: như indent bằng space, sử dụng single quote, kết thúc bằng dấu chấm phẩy, nếu ko follow theo các rule này thì khi lint (kiểm tra) sẽ có lỗi. Nếu chỉ muốn thông báo warning thì ta thay "error" bằng "warn" hoặc có thể dụng số 0 (ko báo lỗi) / 1 (báo warning)/ 2 (báo error). Ví dụ

"semi": [

"warn",

"always"

]

hoặc

"semi": [

1,

"always"

]

Sau khi đã cấu hình xong eslint, ta thêm 2 script lint và lint-and-fix vào file package.json

{

 ...

"scripts": {

 ...

"lint": "eslint . --ext .ts",

"lint-and-fix": "eslint . --ext .ts --fix"

},

...

}
  • Lệnh lint sẽ tìm các file .ts để kiểm tra theo rules đã định nghĩa
  • Lệnh lint-and-fix sẽ kiểm tra các file .ts để sửa lại theo các rules đã định nghĩa. Với các lỗi ko thể tự sửa thì sẽ báo lỗi, ví dụ mình thêm rule "no-console": "error" mà trong code có dùng console.log thì nó sẽ thông báo lỗi

Demo

Chạy lệnh npm run lint để kiểm tra:

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Như hình trên có thể thấy trong file index.ts của mình có các lỗi như ko code theo chuẩn indent đã định nghĩa, vẫn sử dụng double quote, hay vẫn đang kết thúc file bằng CRLF (windows).

Thực ra thì khi bạn cài eslint, Ide nó đã warning lỗi cho bạn ngay khi code rồi: ví dụ ở đây mình dùng visual studio và đã cài plugin eslint

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Thực hiện fix lại các lỗi chưa theo rule bằng cách chạy lệnh npm run lint-and-fix

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Kết quả:

Dấu nháy kép được thay bằng dấu nháy đơn; dấu cách thừa bị xóa đi

Code ví dụ TypeScript Eslint (áp dụng eslint cho TypeScript)

Download code ví dụ trên tại đây hoặc tại đây: https://github.com/stackjava/typescript-eslint

References: https://eslint.org/docs/user-guide/getting-started

https://khalilstemmler.com/blogs/typescript/eslint-for-typescript/

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 IT hấp dẫn trên TopDev

Senior & Junior Java Dev – điều gì làm nên sự khác biệt

Senior & Junior Java Dev – điều gì làm nên sự khác biệt
Senior & Junior Java Dev – điều gì làm nên sự khác biệt

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

Đối với nghề lập trình viên, kinh nghiệm code là cực kì quan trọng. Nhìn vào một đoạn code, người làm lâu năm có thể nhìn ra đó là đoạn code của Senior Java hay Junior Java. Cũng chẳng phải ngẫu nhiên lại có sự chênh lệch mức lương giữa 2 rank này. =)))

  10 Java Web Framework tốt nhất
  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java

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

Đơn giản thôi: Have no idea.

Để cố gắng trở thành Senior, bản thân chúng ta phải luôn luôn học hỏitrau dồi kiến thức. May mắn thay, ngay từ những ngày đầu lọ mọ code từng dòng code, mình đã được sư phụ chỉ cho vài đường cơ bản, tiện đây muốn chia sẻ với các bạn.

Bài viết này mình được sư phụ đầu tiên của mình viết cho. Anh Lương Nguyễn Trung (Senior Java Developer).

1. Kiểm tra NULL (CHECK NULL).

Java NULL, vấn đề muôn thủa. Một Senior với kinh nghiệm code dồi dào sẽ biết cách phòng tránh, hạn chế các trường hợp dẫn tới NullPointerException.

Senior sẽ luôn biết cách phòng tránh Java NullPointerException.But when i do. So funny!.

Một trong những lỗi thường gặp nhất của những bạn mới đó là thiếu kiểm tra Object có phải là NULL hay không.

Thay vì sử dụng những Object này một cách trực tiếp để thực hiện xử lý (cộng trừ nhân chia, cắt chuỗi, nối chuỗi, getLength size…)

Hãy tạo ra những hàm common, trong những hàm này sẽ thực hiện việc kiểm tra giá trị NULL, và thực hiện sử lý tương ứng.

BAD CODE:

public String StringUtil.nullToEmpty(String str) { 
if (str == null) { 
return ""; 
} 
return str; 
}

GOOD CODE:

public String StringUtil.substring(String str, int start, int len) { 
str = nullToEmpty(str); 
// Luôn thực hiện kiểm tra độ dài trước khi substring. 
if (str.length() > len) { 
return str.substring(start, len); 
} 
return str.substring(start); 
}

Mặc dù là nỗi sợ hãi thường trực của các Java Dev, null cũng có đôi điều thú vị. Các bạn có thể đọc thêm ở bài viết này.

2. Sử dụng toán tử cộng trừ nhân chia.

Khi thực hiện cộng trừ nhân chia, trường hợp nếu sử dụng kiểu dữ liệu là Long, Double,… sẽ có trường hợp giá trị trả về bị sai

Decimal dec1 = 4; 
Decimal dec2 = 2; 
Decimal dec3 = dec1 / dec2;

-> Đúng ra, giá dec3 sẽ có giá trị là 2 
Tuy nhiên, trong một vài trường hợp dec3 sẽ có giá trị là 2.0000…1 hoặc 1.99999…9 
Do đó, nếu ta dùng giá trị dec3 để đi so sánh với 2, giá trị sẽ trả về là FALSE

Trường hợp này, nên sử dụng để tính toán. Kì công hơn, hãy tạo class NumberUtil để sử lý việc cộng trừ nhân chia, làm tròn, compare giá trị, format kiểu số…

3. Khai báo biến bên ngoài IF FOR WHILE.

String str; 
for (int i = 0; i < strList.size(); i++) { 
str = strList.get(i); 
… 
} 
// Biến str chỉ được sử dụng bên trong FOR
// Nhưng lại được khai báo bên ngoài.

Source vẫn sẽ chạy đúng, không sai.

Tuy nhiên, sẽ có một vài vấn đề sau:

  • Trường hợp xử lý phức tạp, sẽ khó để một người khác đọc và hiểu ý nghĩa của biến này là gì.
  • Nếu str không phải là String, Number, Date… mà là một kiểu Object có kích thước lớn, thì mặc dù đã ra khỏi IF, FOR, WHILE (biến không còn được sử dụng nữa), nhưng biến này vẫn sẽ giữ giá trị và gây tốn memory.

Xử lí như thế nào?.

  • Khai báo biến bên trong IF FOR WHILE
  • Sử dụng for each (for (String str : strList) {)

4. Danh sách chứa rất nhiều giá trị, không nên sử dụng list.get(i).

Khi danh sách chứa rất nhiều giá trị, không nên sử dụng hàm get tại vị trí thứ i để lấy giá trị này ra.

Nguyên nhân là do hàm get sẽ thực hiện duyệt từng phần tử từ 0 -> i để lấy giá trị của vị trí thứ i này ra, việc này sẽ tốn rất nhiều thời gian nếu vị trí cần lấy là càng về cuối của danh sách.

Ví dụ:

  • get(0)-> Danh sách duyệt 1 lần để trả về giá trị tại vị trí thứ 0.
  • get(10)-> Danh sách duyệt 11 lần để trả về giá trị tại vị trí thứ 10.
  • get(100)-> Danh sách duyệt 101 lần để trả về giá trị tại vị trí thứ 100
// Trường hợp giá trị của danh sách là kiểu Object, 
// Object này có một hạng mục là key để phân biệt với các phần tử khác trong danh sách. 
-> Sử dụng map<key, object> 

// Trường hợp cần loop trên từng phần tử của danh sách 
-> Sử dụng for each 
for (Object dto : dtoList) { 

-> Sử dụng iterator 
Iterator ite = dtoList.iterator(); 
while (ite.hasNext()) { 
Object obj = ite.next(); 
}

5. So sánh String trong Java.

Khi thực hiện so sánh String, không nên sử dụng ==.

if (str == "1") 
// Trường hợp str là NULL, sẽ phát sinh NullPoiterException

Nên:

  • Sử dụng equals
  • Để giá trị cố định đằng trước.
if ("1".equals(str)) 
// Trường hợp str là NULL, 
// Giá trị sẽ trả về là FALSE mà không phát sinh NullPoiterException
Tất nhiên, trong Java, không phải khi nào sử dụng equals cũng là tốt.Tất nhiên, không phải lúc nào sử dụng equals cũng tốt!.

6. Hạn chế thiết lập cứng giá trị trong source code.

Nhiều bạn thường hay thiết lập giá trị cố định vào đoạn source của mình. Tuy nhiên, giá trị này có khi được sử dụng ở nhiều nơi khác nhau trong source.

Như thế, trường hợp có thay đổi tài liệu, hoặc do mình thiết lập giá trị sai, ta phải sửa lại giá trị này ở tất cả mọi nơi đang sử dụng nó, trong lúc sửa, có thể ta cũng sẽ sửa sót, không hết những chỗ cần sửa.

String projectNameHasVersion = "Project AAA" + "1.0.0"; 
if (str == "ABCDE") {

Nên:

Hãy khai báo Constants ở đầu file, hoặc trong constants.java

public static String PROJECT_NAME = "Project AAA"; 
public static String VERSION = "1.0.0"; 

public void Function_1() { 
String projectNameHasVersion = PROJECT_NAME + VERSION; 
} 

public void Function_2() { 
if (VERSION > …) 
}

7. Luôn sử dụng ENUM khi có thể.

Trường hợp cần phải thiết lập nhiều giá trị Constants mà lại phụ thuộc vào một Key nào đó, nếu ta chỉ khai báo constant thì khi sử dụng có khả năng ta sẽ sử dụng sai giá trị constants của key tương ứng này.

public static String TYPE_A_NAME = "..."; 
public static String TYPE_A_WIDTH = "..."; 
public static String TYPE_A_LENGTH = "..."; 

public static String TYPE_B_NAME = "..."; 
public static String TYPE_B_WIDTH = "..."; 
public static String TYPE_B_LENGTH = "..."; 

public void getInfo(String typeName) { 
if (TYPE_A_NAME.equals(typeName) { 
return TYPE_A_WIDTH + TYPE_A_LENGTH; 
} else if (TYPE_B_NAME.equals(typeName) { 
// -> Ở đây đúng ra cần trả về thông tin của TYPE_B,
// Nhưng có thể do bất cẩn hoặc do lỗi copy
// lại đang trả về giá trị của TYPE_A

return TYPE_B_WIDTH + TYPE_A_LENGTH; 
} 
}

Nên:

Tạo enum để lưu các giá trị thuộc về cùng một key vào 1 giá trị duy nhất

public enum MyType { 
TYPE_A("Type A", "Width of A", "Length of A"), -> Mô tả các giá trị của TYPE_A
TYPE_B("Type B", "Width of B", "Length of B"), -> Mô tả các giá trị của TYPE_B
; 

private String name; 
private String width; 
private String length; 

MyType(String name, String width, String length) { 
this.name = name; 
this.width = width; 
this.length = length; 
} 

public String getName() { 
return name; 
} 

public String getWidth() { 
return width; 
} 

public String getLength() { 
return length; 
} 
}
public void getInfo(String typeName) { 
if (MyType.TYPE_A.getName().equals(typeName) { 
return MyType.TYPE_A.getWidth() + MyType.TYPE_A.getLength(); 
if (MyType.TYPE_B.getName().equals(typeName) { 
return MyType.TYPE_B.getWidth() + MyType.TYPE_B.getLength(); 
} 
} 

public void getInfo(MyType myType) { 
return myType.getWidth() + myType.getLength(); 
}
Hãy luôn sử dụng enum khi có thể.If you know, what i mean.

Tại sao Enum lại luôn được ưu tiên sử dụng?. Để tìm hiểu sâu hơn, các bạn có thể đọc thêm bài viết này.

8. Tìm hiểu thêm về Stream, forEach, Lambda.

Từ phiên bản 1.8 trở đi, java có hỗ trợ thêm các feature mới là Stream, forEach, Lambda nếu có thời gian, nên tìm hiểu thêm phần này. Các bạn cũng có thể đọc thêm ở bài viết về stream trên blog này. Muốn trở thành Senior tất nhiên phải bỏ công học hỏi. kkk

Nó sẽ giúp việc lập trình trở nên đơn giản và tiết kiệm thời gian hơn!.

Again, thanks for reading, love u so much!

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 IT hấp dẫn trên TopDev

Code ví dụ TypeScript logger (ghi log TypeScript với log4js)

Code ví dụ TypeScript logger (ghi log TypeScript với log4js)

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

Code ví dụ TypeScript logger (ghi log TypeScript với log4js)

(Xem lại: Code ví dụ nodejs log4js)

  Authorization Code grant type với Proof Key for Code Exchange (PKCE) trong OAuth 2.1
  Các kiểu dữ liệu trong lập trình C/C++ (Data type)

1. Code ví dụ TypeScript log4j

khởi tạo project typescript. (Xem lại: tạo project TypeScript)

mkdir typescript-log4j

cd typescript-log4j




npm i typescript --save-dev

npx tsc --init

Cài đặt module log4js

npm i log4js

Tạo file src/logger.ts: khởi tạo và cấu hình log4j

import { configure, getLogger } from "log4js";




configure({

"appenders": {

"application": {

"type": "console"

},

"file": {

"type": "file",

"filename": "/logs/application.log",

"compression": true,

"maxLogSize": 10485760,

"backups": 100

}

},

"categories": {

"default": {

"appenders": [

"application",

"file"

],

"level": "info"

}

}

});




export const logger = getLogger();

Trong đó:

  • export const logger = getLogger(); : khởi tạo đối tượng log4js và export ra để các file khác sử dụng.
  • configure: cấu hình log4js, ở đây mình cấu hình 2 kiểu log là log ra file và log ra console với level là info. Riêng phần log ra file thì cấu hình ghi log ra file /logs/application.log với kích thước là 10485760 byte, nếu vượt quá thì sẽ tạo file mới (không quá 100 file)

Tạo file src/index.ts gọi tới đối tượng log4js đã export từ file logger.ts để ghi log:

import { logger } from "./logger";




logger.trace("stackjava.com");

logger.debug("stackjava.com");

logger.info("stackjava.com");

logger.warn("stackjava.com");

logger.error("stackjava.com");

logger.fatal("stackjava.com");

Cấu trúc project

Code ví dụ TypeScript logger (ghi log TypeScript với log4js)

Demo:

Code ví dụ TypeScript logger (ghi log TypeScript với log4js)

Có thể bạn quan tâm: Việc làm lập trình Typescript lương cao tại Topdev.

File log được ghi ra:

[2021-06-12T16:58:45.127] [INFO] default - stackjava.com

[2021-06-12T16:58:45.132] [WARN] default - stackjava.com

[2021-06-12T16:58:45.133] [ERROR] default - stackjava.com

[2021-06-12T16:58:45.133] [FATAL] default - stackjava.com

Okay done!

Download code ví dụ trên tại đây hoặc tại đây https://github.com/stackjava/typescript-log4js

References:

https://www.npmjs.com/package/log4js

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 IT hấp dẫn trên TopDev

Hướng dẫn KIỂM TRA file *.REG liệu có AN TOÀN hay không?

Hướng dẫn KIỂM TRA file *.REG liệu có AN TOÀN hay không?

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

Nếu như bạn thường xuyên theo dõi các bài viết có trên Blog Chia Sẻ Kiến Thức thì có lẽ file có định dạng *.reg đã quá quen thuộc với bạn rồi đúng không 🙂

Để hiểu thêm về định dạng *.reg thì bạn hãy đọc lại bài viết này của Admin nhé: Registry là gì? Hướng dẫn toàn tập về Regedit trên Windows

File *.reg là danh sách các tùy chỉnh cho Windows Registry, nó rất thuận tiện để thay đổi những key đơn giản, giúp bạn tùy chỉnh và can thiệp sâu vào hệ thống.

  10 trình quản lý file hàng đầu trong JavaScript
  11 cách tăng tốc nhanh cho WordPress bằng file wp-conig.php

Tuy nhiên, nó lại ẩn chứa những nguy hiểm tiềm tàng nếu bạn chỉnh sửa sai, thiết lập sai, hoặc khi bạn tải một file *.reg ở một trang không được chứng thực sau đó sử dụng nó.

Chính vì vậy mà hôm nay, mình sẽ hướng dẫn cho các bạn cách để kiểm tra file *.reg trước khi sử dụng nó nhé. Điều này là rất cần thiết nha các bạn !

#1. File *.reg là gì?

Như mình đã nói ở trên, file *.reg là danh sách tất cả những tùy chỉnh cho Windows Registry để thêm bớt một thành phần nào đó trong hệ thống Windows, đồng thời bạn cũng có thể thêm các phần mềm hoặc dữ liệu từ bên thứ ba.

cach-kiem-tra-file-reg-lieu-co-an-toan-hay-khong (6)

Có những tùy chỉnh mà bạn chỉ có thể chỉnh sửa thông qua Windows Registry (đôi khi vẫn có thể chỉnh sửa thông qua Local Group Policy).

Tuy nhiên, chỉ có các phiên bản cao cấp như Windows Pro, Windows Enterprise hay Windows Education thì bạn mới có thể vào được Local Group Policy. Mà hầu hết các máy tính được tích hợp sẵn bản quyền hiện nay đều chỉ cài sẵn Windows 10 Home mà thôi.

Với Windows Registry, bạn hoàn toàn có thể chỉnh sửa thủ công bằng Registry Editor. Tuy nhiên, cách chỉnh sửa này rất lằng nhằng đối với những người không có nhiều kiến thức về máy tính.

Vì vậy các trang web hướng dẫn sẽ cung cấp các file *.reg để đơn giản hóa việc chỉnh sửa Registry chỉ bằng một vài click chuột.

#2. Vì sao file *.reg lại có thể gây nguy hiểm cho máy tính?

File *.reg chứa danh sách các thiết lập nâng cao trong Registry. Khi khởi chạy file này, Windows sẽ thêm, bớt hoặc chỉnh sửa các key trong hệ thống Windows theo thiết lập sẵn có của file *.reg đó.

Chính vì vậy, nếu file *.reg bị lỗi, hoặc người tạo ra nó cố tình tạo ra một file để phá hoại máy tính thì hậu quả sẽ rất nặng nề 🙂

Nếu như không có kinh nghiệm xử lý thì thường là bạn sẽ phải cài lại Windows do lỗi quá nặng hoặc một thành phần nào đó trong Windows bị hỏng và không hoạt động được đúng cách nữa.

#3. Cách đọc nội dung file *.reg

Để đọc được nội dung file *.reg thì rất đơn giản thôi, bạn bấm chuột phải vào file REG đó => sau đó chọn Edit.

cach-kiem-tra-file-reg-lieu-co-an-toan-hay-khong (1)

Khi đó file REG sẽ được mở lên bằng Notepad. Hoặc nếu bạn đã cài NotePad++ cho máy tính thì bạn có thể mở bằng Notepad++ cho dễ xem hơn.

cach-kiem-tra-file-reg-lieu-co-an-toan-hay-khong (2)

Ở dòng đầu tiên luôn là Windows Registry Editor Version 5.00 giúp nhận biết loại file và định danh file.

Đôi khi ở các dòng tiếp theo, sẽ có những thông tin hoặc comment của người tạo ra file REG đó. Như trong ví dụ là:

? Modified by: Tuan ga
?https://blogchiasekienthuc.com/

Nó không ảnh hưởng gì đến file REG cả, chỉ có tác dụng là để người khác đọc được khi mở file đó bằng notepad. Những comment đó luôn đứng đằng sau kí tự “;”.

Tiếp theo là phần quan trọng nhất của file *.reg, đó là phần nội dung của các chỉnh sửa/ thiết lập cho Windows Registry.

Nếu các bạn có kiến thức về Registry thì có thể đọc và kiểm tra phần này để nhận biết file REG có gây hại gì cho máy tính hay không.

#4. Cách chạy file *.reg trên Windows

+ Bước 1: Đơn giản thôi, bạn nháy đúp chuột vào file REG đó.

cach-kiem-tra-file-reg-lieu-co-an-toan-hay-khong (3)

+ Bước 2: Sau đó sẽ có một cảnh báo xuất hiện, bạn bấm Yes để đồng ý thay đổi.

cach-kiem-tra-file-reg-lieu-co-an-toan-hay-khong (4)

+ Bước 3: Thông báo hoàn thành xuất hiện, bạn bấm OK để kết thúc. Sau đó khởi động lại máy tính để áp dụng các thay đổi.

cach-kiem-tra-file-reg-lieu-co-an-toan-hay-khong (5)

#5. Cách nhận biết file *.reg liệu có an toàn hay không

Để nhận biết một file *.reg có an toàn hay không. Đầu tiên bạn phải biết chắc chắn về cách sử dụng và công dụng của file *.reg đó là để làm gì.

Nếu bạn là một người không hề biết gì về máy tính thì hãy cân nhắc việc chạy file REG đó, trừ khi là làm theo hướng dẫn của những trang web uy tín.

Điều tiên quyết tiếp theo và nó cũng liên quan đến vấn đề mà mình vừa đề cập ở trên đó là tải file REG trên những trang Web uy tín và đã được kiểm duyệt. Một trong số đó tất nhiên là blogchiasekienthuc.com rồi 🙂

Trong trường hợp file REG đó chỉ có trên các trang web là mà bạn chưa biết nhiều về trang web này thì hãy chạy thử file REG đó trên máy tính ảo để thử trước, hoặc chạy trong một môi trường an toàn nào đó.

Nếu bạn không có thời gian hoặc không muốn cài máy ảo thì bạn hãy backup, sao lưu Registry trước khi thực thi file đó. Đồng thời, hãy xác định tâm lý là trong trường hợp xấu nhất sẽ phải cài lại Windows.

Đừng trông chờ vào các phần mềm diệt virus, bởi chúng không thể quét các file *.reg cho dù nó có là file gây lỗi hoặc phá hoại máy tính đi chăng nữa.

#6. Lời kết

Okay, như vậy mình đã hướng dẫn xong cho các bạn cách để kiểm tra file *.reg liệu có an toàn hay không rồi nhé.

Ngoài những kiến thức mà mình chia sẻ bên trên ra, nếu như bạn còn có thêm những kinh nghiệm hay về file REG này thì đừng ngần ngại chia sẻ dưới phần commnet để anh em cùng nhau học hỏi và thảo luận thêm ha 🙂

Chúc các bạn thành công, và đừng quên ghé thăm Blog khi rảnh nhé !

CTV: Hoàng Tuấn – Bài viết gốc tại blogchiasekienthuc.com

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

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

Hướng dẫn cách phục hồi dữ liệu trên iPhone với Coolmuster

Hướng dẫn cách phục hồi dữ liệu trên iPhone với Coolmuster

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

Bằng một lý do nào đó mà dữ liệu trên điện thoại iPhone của bạn đã biến mất, ví dụ như bạn vô tình xóa nhầm, hoặc lỡ tay khôi phục cài đặt gốc… Và bạn đang tìm kiếm một phần mềm hỗ trợ khôi phục dữ liệu đã xóa trên iPhone?

Vậy bạn đã tìm được phần mềm nào ưng ý chưa? Vâng, nếu bạn đang tìm kiếm một giải pháp hiệu quả để cứu vớt dữ liệu trên chiếc điện thoại iPhone của bạn thì có lẽ Coolmuster iPhone Data Recovery sẽ một một lựa chọn phù hợp đấy.

  5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình
  Biến số và kiểu dữ liệu số trong Python

#1. Coolmuster iPhone Data Recovery có những ưu điểm gì?

    • Hỗ trợ phục hồi các file bị mất hoặc bị xóa trên các thiết bị iOS (iPhone, iPad..) và bản sao lưu iTunes.
    • Các bước thao tác để phục hồi dữ liệu là rất đơn giản, ngay cả với những người lần đầu sử dụng.
  • Khôi phục các file quan trọng trực tiếp từ iPhone: Tin nhắn SMS, danh bạ, hình ảnh, video, ghi chú, lịch, Safari,…. Phần mềm sẽ khôi phục dữ liệu từ điện thoại sang máy tính.
  • Khôi phục dữ liệu từ file backup iTrunes:  Phần mềm sẽ hỗ trợ khôi phục lại danh bạ, tin nhắn và file đính kèm tin với nhắn đã xóa, cũng như là các file hiện có từ tệp sao lưu iTunes vào máy tính. Ngoài ra phần mềm cũng hỗ trợ trích xuất lịch sử cuộc gọi hiện có, ghi chú, tệp đính kèm ghi chú, Safari, lịch sử Safari, lịch, ghi nhớ thoại, thư viện ảnh và ảnh từ tệp sao lưu iTunes vào máy tính của bạn. (Lịch sử cuộc gọi và lịch sử Safari không được hỗ trợ trong iOS 10 trở lên)
  • Hỗ trợ xem trước các file dữ liệu hiện có và dữ liệu đã xóa => sau đó chọn file mà bạn muốn phục hồi.
  • Hỗ trợ các dòng điện thoại mới nhất hiện nay như iPhone, iPad và iPod (bao gồm cả iOS 14).
  • Bạn có thể cài đặt phần mềm trên tất cả các phiên bản Windows như: Windows 10/ Windows 8/ Windows 7 / Windows Vista / Windows XP, macOS..

#2. Tải phần mềm Coolmuster iPhone Data Recovery

  • Trang chủ: https://www.coolmuster.com/
  • Link giveaway: Hiện tại phần mềm đang miễn phí 1 năm tại đây ! Bạn hãy nhập thông tin, địa chỉ email => sau đó link tải phần mềm và key bản quyền sẽ được gửi thông qua Email bạn đăng ký nhé.

#3. Hướng dẫn sử dụng Coolmuster iPhone Data Recovery

Sau khi tải phần mềm về bạn hãy tiến hành cài đặt nó vào máy tính, quá trình cài đặt rất dễ nên mình sẽ không hướng dẫn thêm nữa. Đây là giao diện chính của phần mềm.

cach-khoi-phuc-du-lieu-truc-tiep-tu-iphone (1)

2.1. Cách khôi phục dữ liệu trực tiếp từ thiết bị iOS

Bạn hãy kết nối điện thoại cần phục hồi dữ liệu với máy tính bằng cáp điện thoại…

Bạn chọn Trust (tin cậy) nếu được hỏi nhé.

cach-khoi-phuc-du-lieu-truc-tiep-tu-iphone (3)

Okay, sau khi kết nối xong bạn sẽ thấy giao diện như hình bên dưới, bây giờ bạn hãy chọn tab Recovery from iOS Device.

cach-khoi-phuc-du-lieu-truc-tiep-tu-iphone (4)

Okay, bây giờ đến bước xem trước dữ liệu và phục hồi những file cần thiết.  Bạn có thể gạt công tắc sang bên phải của tùy chọn Only display the deleted item(s) để chỉ hiển thị các tệp đã xóa.

Các tập tin đều đã được phân chia rõ ràng trong từng danh mục cụ thể,  bạn có thể truy cập vào từng danh mục để khôi phục những file dữ liệu mà bạn cần.

Ví dụ như mình sẽ chọn tab Contacts để phục hồi danh bạ điện thoại..

cach-khoi-phuc-du-lieu-truc-tiep-tu-iphone (5)

Hoặc là tab Messages để khôi phục các tin nhắn đã xóa..

cach-khoi-phuc-du-lieu-truc-tiep-tu-iphone (6)

Còn đây là tab Photos, nới chứa các hình ảnh đã xóa của bạn..

cach-khoi-phuc-du-lieu-truc-tiep-tu-iphone (7)

Tương tự như vậy với các tab khác, sau khi bạn tìm được các file cần khôi phục => bạn hãy tích chọn các file đó => sau đó chọn Recovery to Computer (góc dưới cùng bên phải) để phục hồi là xong.

2.2. Cách khôi phục dữ liệu từ iTunes backup

Okay, trong trường hợp bạn muốn  khôi phục dữ liệu từ file iTunes backup thì bạn  hãy chuyển qua tab Recovery from iTunes Backup File => tại đây sẽ liệu kê ra tất cả những file mà bạn đã backup trước đó.

=> Bạn hãy chọn file backup mà bạn muốn phục hồi dữ liệu từ nó. Nếu trước đó bạn đã thay đổi vị trí lưu file backup thì bạn hãy nhấn vào nút Select để chọn lại cho phù hợp nhé.

phuc-hoi-du-lieu-tu-itunes-backup (1)

Bước này bạn sẽ chọn kiểu dữ liệu mà bạn muốn khôi phục, nếu bạn muốn khôi phục lại hết thì cứ tích chọn hết như hình bên dưới nhé => sau đó bấm vào nút Start Scan để thực hiện quét.

phuc-hoi-du-lieu-tu-itunes-backup (2)

Hoàn toàn tương tự như trong phần 2.1, chương trình sẽ tìm thấy các file (cả file đã xóa và file hiện có) trong file iTunes backup.

phuc-hoi-du-lieu-tu-itunes-backup (3)

Những tin nhắn mà phần mềm load được..

phuc-hoi-du-lieu-tu-itunes-backup (4)

Và cả hình ảnh nữa….

phuc-hoi-du-lieu-tu-itunes-backup (5)

=> Bạn hãy chọn file hoặc tập tin mà bạn muốn khôi phục => sau đó chọn Recovery to Computer để khôi phục lại dữ liệu là xong.

NOTE: Okay, về cơ bản thì cách sử dụng như vậy. Nếu bạn muốn xem thêm nhiều hướng dẫn khác thì có thể vào trang chủ của họ để xem thêm nhé:

https://www.coolmuster.com/ios-recovery/iphone-data-recovery-guide.html

#3. Lời kết

Một phần mềm hỗ trợ khôi phục dữ liệu iPhone rất đáng để thử. Bạn đang sử dụng phần mềm nào để khôi phục dữ liệu trên iPhone? Hãy chia sẻ kinh nghiệm của bạn cho mọi người cùng tham khảo nhé. Thank you !

Oracle to Postgres, sự trỗi dậy của bầy voi!

Oracle to Postgres, sự trỗi dậy của bầy voi!

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

Nay ngồi buồn nghĩ về quãng thời gian cày bừa với các dự án convert database (từ Oracle sang Postgres). Muốn chia sẻ chút kinh nghiệm nhỏ nhoi trên mặt này tới các bạn.

  Cài đặt PostgreSQL server sử dụng Docker
  Chạy Postgresql trong Docker container

Bản thân mình đã từng làm cho 2 doanh nghiệp CNTT của Nhật Bản, đã kinh qua 6 dự án Convert Database. Nhận thấy:

  • Trong khoảng 5 năm trở lại đây, ngày có càng nhiều doanh nghiệp nhỏ và vừa chuyển đổi các phần mềm, ứng dụng của họ từ Oracle Database sang Postgres Database.
  • Việc chuyển đổi này đa phần đến từ các dự án cũ của doanh nghiệp Nhật Bản với quy mô không quá lớn. Trường hợp này sử dụng Postgres DB là hợp lý. 
  • Dự án convert kiểu này thường không mấy HÀO HỨNG cho lập trình viên (khá chán).
  • Công nghệ sử dụng hầu hết là JDBC, rất hiếm có dự án nào sử dụng MyBatis hay Hibernate.
Đã từng hay chưa?

Nguyên nhân của việc chuyển đổi này là từ đâu?. Không thể bỗng nhiên những doanh nghiệp Nhật (vốn yêu thích sự ổn định, sử dụng phần mềm lâu dài), lại bỗng nhiên thực hiển chuyển đổi Database (việc làm vốn dĩ tiềm ẩn nhiều rủi ro).

Bài viết này sẽ phân tích về nguyên nhân sâu xa của vấn đề này.

1. Oracle – chi phí đắt đỏ.

1.1 Named User Plus (chi phí trên từng user).

Lý do đầu tiên và cũng là lý do quan trọng nhất – ĐẮT. Oracle Database thực sự đắt đỏ, khác hẳn với Postgres Database miễn phí. Nếu ứng dụng hoặc phần mềm của chúng ta chỉ sử dụng để đáp ứng cho một lượng nhỏ người dùng, không yêu cầu realtime, … thì việc bỏ tiền để sử dụng Oracle database là khá đắt đỏ.

The price of acquisition and product support for Oracle database is high and we need to pay in addition for every extra feature we need which is having the high price. So TCO is high for Oracle database.

Giá cả để sử dụng và hỗ trợ đối với Oracle database là tương đối cao, chúng ta cần trả thêm tiền cho việc thêm tính năng. Vì vây, TCO (total cost of ownership) là tương đối cao cho việc sử dụng Oracle database.

Oracle database chi phí đắt đỏ hơn nhiều so với Postgres database.Chỉ với phiên bản tiêu chuẩn (standard edition) và tính theo số lương người dùng (Named User Plus), người sử dụng cũng đã phải bỏ ra 350$ (Thêm support và update là 77$). Đây là một con số không hề nhỏ.

1.2 Customer supprot và security.

Phải chăng bỏ tiền mua support là đã xong. Có vấn đề khi nào thì gọi support khi đó?. Cứ có vấn đề là rên?. Câu trả lời là ĐÉO!.

Customer support for Oracle database is not free; it is almost one-fourth of the license cost and increases 3 to 5 % annually.

Hỗ trợ khách hàng của Oracle database là đéo hề miễn phí. Cỡ khoảng 1/4 chi phí của license, và đm, tăng thêm 3%, 5% mỗi năm. Ẹc.

Trời đụ, vậy chắc OCD phải an toàn hơn rồi!. Tất nhiên, nhưng vẫn phải ói thêm tiền.

Oracle database has more security or advanced security but we need to purchase as part of the editions provided by Oracle corporation which have some features that protect the database.

Oracle database an toàn hơn nhiều, tuy nhiên chúng ta cần thanh toán thêm. Cái này như là một phần tính năng mở rộng. Thêm một vài tính năng để bảo về Database.

Thêm tính năng (advanced security) cho mỗi user sử dụng, cũng đồng nghĩa với 300 cành cọ cất cánh bay.

2. Postgres – miễn phí, ai chả thích.

Ui chà, MIỄN PHÍ. Đối với những doanh nghiệp vừa và nhỏ, tiết kiệm được chi phí phải trả cho database thật là một sự lựa chọn hoàn hảo.

Chính vì vậy, càng ngày có càng nhiều doanh nghiệp Nhật thực hiện chuyển đổi database từ Oracle sang Postgres (hầu hết là các dự án outsource – quy mô dự án không quá lớn).

As PostgreSQL is open-source there is no fee for acquisition and product support which are absolutely free of cost. We can get all the available features of PostgreSQL database for free as it is open-source.

PostgreSQL là mã nguồn mở, vì vậy không có bất cứ chi phí nào , product support cũng hoàn toàn miễn phí. Tất cả các tính năng của PostgreSQL database đều là miễn phí.

Postgres Databse là miễn phí, có thể donate để phát triển hệ cơ sở dữ liệu này.Postgresql Database là miễn phí. Vì vậy, chỉ có thể đóng góp (donate) để phát triển hệ cơ sở dữ liệu này. Theo mình dự đoán thì số lượng tiền donate cho postgresql là không hề nhỏ.

3. Sức mạnh của những chú voi.

Khi phải rời xa Oracle đắt đỏ, các doanh nghiệp thường phải đau đầu lựa chọn giữa Postgres và MySQL. Tất nhiên, hiện tại thì postgres đã có mặt khắp mọi nơi rồi.

3.1 SQL.

  • Windowing functions and analytics (OVER-clause) – Hàm và thống kê (sử dụng OVER)
  • Ordered sets (WITHIN GROUP) – Lựa chọn sắp xếp (với GROUP).
  • Hypothetical aggregates (WITHIN GROUP).
  • Recursive SQL (WITH RECURSIVE) – SQL đệ quy.
  • Partial aggregates (FILTER-clause) – Tách từng phần ra thành tập hợp.
  • Table sampling – Bảng mẫu.

3.1 Performance – Hiệu năng.

  • Parallel queries – Queries đa luồng (nhiều câu query chạy đồng thời).
  • Advanced locking mechanisms – Cơ chế khóa bổ sung cho từng bảng.
  • Many different types of indexes (btree, gist, gin, hash. sp-gist, brin, bloom, etc.) – Rất nhiều kiểu indexs (sử dụng để tăng tốc query).
  • Advanced cost-based query optimization – tối ưu hóa query dự.
  • Tablespaces
  • Partitioned tables – Tạo bảng phân vùng.
  • Synchronous and asynchronous COMMIT – COMMIT dựa trên cơ chế đồng bộ và bất đồng bộ.

Tiện nói luôn chút xíu về cơ chế COMMIT Synchronous (đồng bộ) của postgres. Cơ chế này đảm bảo rằng dữ liệu trước khi thực hiện commit sẽ được lưu vào ÍT NHẤT là 2 nodes. Việc này đảm bảo không xảy ra mất mát dữ liệu. Thực hiện đồng bộ đồng thời cũng phải đánh đổi về mặt hiệu suất (phải chờ để được commit).

Cơ chế commit đồng bộ trên Postgres.

3.3 Security.

  • Users, roles, etc.
  • Full support for SSL – Hỗ trợ cho SSL (Secure Socker Layer).
  • Full database encryption (with “Cybertec PostgreSQL_fde”) – Cơ chế mã hóa an toàn.
  • Support for single-sign-on (ActiveDirectory, LDAP, RADIUS, etc.)

3.4 Store Procedures.

  • Support for stored procedures in various languages.
  • Support for custom aggregates – hỗ trợ tùy chỉnh.
  • Professional triggers – sử dụng triggers (cơ chế bắt sự kiện trên table).

4. Kết luận.

Mong rằng bài viết này đã cho các bài một cái nhìn tổng quan về việc chuyển đổi cơ sở dữ liệu từ Oracle sang Postgres, nguyên nhân của việc chuyển đổi này.

Sẽ còn nhiều vấn đề để bàn về sự khác biệt giữa Oracle DB hay Postgres DB. Tuy nhiên, những vấn đề chuyên sâu này sẽ được viết ở các bài viết tiếp theo.

Hãy cố gắng để sử dụng Postgres một cách thuần thục như cách mà ta trộm nó (trộm gì khi nó là miễn phí =))).

5. Tham khảo.

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 IT hấp dẫn trên TopDev

Code ví dụ typescript, cấu hình eslint với prettier

Code ví dụ typescript, cấu hình eslint với prettier.

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

Code ví dụ typescript, cấu hình eslint với prettier.

eslint đã có sẵn các rules để phân tích code và một số format, tuy nhiên riêng phần format thì prettier làm tốt hơn eslint và cung cấp 1 số tính năng mà eslint ko có.

(xem lại: code ví dụ typescript với eslint)

  7 lý do bạn không nên sử dụng TypeScript
  Các kiểu dữ liệu trong lập trình C/C++ (Data type)

Code ví dụ typescript, cấu hình eslint với prettier

Giả sử bạn đang có sẵn 1 project typescript sử dụng eslint, để kết hợp prettier ta làm các bước sau:

Bước 1: Cài các package

npm install --save-dev eslint-plugin-prettier

npm install --save-dev --save-exact prettier

npm install --save-dev eslint-config-prettier

Trong đó:

  • eslint-config-prettier : Tắt các Eslint rules mà conflict với Prettier
  • eslint-plugin-prettier : Tích hợp Prettier rules với Eslint rules

Bước 2: Sửa lại file .eslintrc.json (hoặc .eslintrc.eslintrc.js)

{

"plugins": ["prettier"],

"extends": ["plugin:prettier/recommended"],

"rules": {

"prettier/prettier": "error"

}

}

Bước 3: Tạo file prettier.config.js để định nghĩa các rule của prettier.

Ví dụ:

module.exports = {

 singleQuote: true,

 trailingComma: 'es5',

 arrowParens: 'always',

 endOfLine: 'lf',

 tabWidth: 2,

 printWidth: 120,

};

Tham khảo thêm các vị trí tuyển dụng Typescript lương cao 3000 USD

Demo:

Giả sử mình đang có 1 project typescript đơn giản đã apply eslint như sau:

Code ví dụ typescript, cấu hình eslint với prettier

Mình thêm file prettier.config.js và sửa lại file .eslintrc.json như sau:

{

“scripts”: {

“lint”: “eslint . –ext .ts”,

“lint-and-fix”: “eslint . –ext .ts –fix”

},

}

{

“env”: {

“browser”: true,

“commonjs”: true,

“es2021”: true

},

“parser”: “@typescript-eslint/parser”,

“parserOptions”: {

“ecmaVersion”: 12

},

“plugins”: [“prettier”],

“extends”: [“plugin:prettier/recommended”],

“rules”: {

“prettier/prettier”: “error”

}

}

module.exports = {

 singleQuote: true,

 trailingComma: 'es5',

 arrowParens: 'always',

 endOfLine: 'lf',

 tabWidth: 2,

 printWidth: 120,

};

Sau đó chạy lệnh:

npm run lint-and-fix

Kết quả:

Code ví dụ typescript, cấu hình eslint với prettierOkay, Done!

Download code ví dụ trên tại đây hoặc tại đây https://github.com/stackjava/typescript-eslint-prettier

References:

https://www.npmjs.com/package/eslint-plugin-prettier

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 IT hấp dẫn trên TopDev

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

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

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

Trong bài này mình sẽ hướng dẫn sao lưu, khôi phục data của mongodb một cách đơn giản nhất.

  Mong đợi gì từ hội nghị lập trình viên Google IO 2016 (P1)
  MongoDB là gì? Cơ sở dữ liệu phi quan hệ

Xem thêm nhiều việc làm MongoDB lương cao trên TopDev

Ví dụ mongodump, mongorestore

Mongo hỗ trợ 2 cách để sao lưu, khôi phục data là mongodump/mongorestore với mongoimport/mongoexport tuy nhiên mongoimport/mongoexport chỉ dùng cho trường hợp data nhỏ nên ở đây mình chỉ đề cập tới mongodump/mongorestore.

1. Ví dụ mongodump

Để sao lưu data thành file .gz ta dùng câu lệnh sau:

mongodump --host={host:port} --authenticationDatabase={authenticationDatabase} -u={username} -p={password} --db={database} --collection={collection} --archive={filename.gz} --gzip --query=<json>

(lệnh mongodump còn nhiều tùy chọn khác, tuy nhiên ở đây mình chỉ đưa ra các lựa chon đơn giản nhất để có thể sao lưu data).

Trong đó:  --host={host:port} --authenticationDatabase={authenticationDatabase} -u={username} -p={password} là thông tin của database mà bạn cần backup lại

  • default host:port sẽ là localhost:27017 nên nếu bạn chạy ở local thì có thể bỏ qua option --host
  • nếu bạn ko cài password cho database thì cũng có thể bỏ qua các option --authenticationDatabase,  -u-p
  • --db: chỉ rõ database bạn muốn backup, nếu ko chọn thì mặc định nó sẽ sao lưu lại tất cả database trên host
  • --collection: chỉ rõ collection bạn muốn backup, nếu bỏ qua thì nó sẽ sao lưu tất cả collection trong database
  • --archive={filename.gz} --gzip: để chọn backup ra file .gz (nếu ko có sẽ lưu lại thành folder với nhiều mục nhỏ)
  • --query=<json>: dùng để tùy chọn các bản ghi được backup, ví dụ chỉ chọn backup các bản ghi có tên là ‘xyz’…

Lưu ý: khi sử dụng --query trên window thường hay bị lỗi parse json nên người ta hay dùng --queryFile=path_file. Với path_file là đường dẫn tới file json chứa thông tin query, cách này vừa hạn chế lỗi, vừa cho phép các câu query nâng cao).

2. Ví dụ mongorestore

Để khôi phục (restore) data từ file .gz được backup bằng lệnh mongodump, ta sử dụng lệnh mongorestore với cú pháp như sau:

mongorestore --host={host:port} --authenticationDatabase={authenticationDatabase} -u={username} -p={password} --db={database} --collection={collection} --archive={filename.gz} --gzip

Nếu bạn ko chỉ rõ --db và --collection thì nó sẽ restore lại tất cả data trong file .gz, theo đúng database name và collection name đã backup

Trường hợp tên database hoặc tên collection ở nơi bạn muốn restore khác với tên lúc backup thì ta sử dụng option --nsFrom và --nsTo như sau:

mongorestore --host={host:port} --authenticationDatabase={authenticationDatabase} -u={username} -p={password} --archive={filename.gz} --gzip --nsFrom={sourceDatabase.sourceCollection} --nsTo={destinationDatabase.destinationCollection}

Demo

Ví dụ mình muốn chuyển data từ collection fruit từ database store_1 sang collection fruit của database store_2

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

Thực hiện backup lại data của collection fruit của của database store_1 thành file fruit.gz

mongodump --db=store_1 -c=fruit --archive=fruit.gz --gzip

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

Thực hiện restore data từ file fruit.gz vào collection fruit của database store_2

mongorestore --archive=fruit.gz --gzip --nsFrom=store_1.fruit --nsTo=store_2.fruit

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

Kết quả:

Hướng dẫn sao lưu, khôi phục data mongo (mongodump, mongorestore)

Okay, Done!

References:

https://docs.mongodb.com/database-tools/mongodump

https://docs.mongodb.com/database-tools/mongorestore

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 IT hấp dẫn trên TopDev

Clean code với Vuejs Anti pattern – Phần 1

Clean code với Vuejs Anti pattern – Phần 1

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

Bắt đầu với lí do tại sao lại có chuỗi bài Vuejs Anti Pattern.

Trong quá trình lead một team làm việc chủ yếu với Nuxtjs và Typescript. Bản thân tôi thấy rất nhiều member bị dính những con bug khá khoai (đại loại như out of control)

Sau khi bỏ time điều tra, hầu hết do các bạn code không theo một quy củ nào. Cũng không có tài liệu nào cho biết cách làm A thì tốt hơn cách làm B. Hoặc cách làm C sẽ gây khó khăn sau này khi maintain

  Clean Architecture: Đứng trên vai những gã khổng lồ
  Clean Code là gì? Tại sao phải CLEAN CODE trong lập trình?

Xem thêm các chương trình tuyển dụng Vuejs hấp dẫn trên TopDev

Chính vì vậy tui viết chuối bài Vuejs Anti Pattern liệt kê những pattern cần tránh khi làm việc với Vuejs

Có 2 phần nha, phần này là phần 1

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

1. Communication – Giao tiếp giữa các component

Communication là giao tiếp, trong Vuejs Anti Pattern thì pattern này khá phổ biến và cũng được biết tới rất nhiều. Hiện nay có vẻ không còn nhiều người còn dính pattern này trong quá trình làm

Giả sử ta cố 2 component, một là Todo List và thứ hai là Todo Item. Component Todo List sẽ render một loạt các component Todo Item. Lúc này việc giao tiếp giữa các component sẽ trở nên quan trọng.

Thông thường Vue sẽ cho phép ta access được tới $parent (component cha) và $child (component) con. Bằng cách này:

BAD  

export default {
props: ['todo'],
methods: {
completeTodo(todo) {
this.$parent.$options.methods.completeTodo(todo);
}
}
}

Cách làm này có một cái dở, 2 component cha con bị dính lấy nhau. Component cha mặc định sẽ phải có method completeTodo

Với emit, giao tiếp giữa 2 component cha con trở nên đơn giản và gọn gàng hơn nhiều

GOOD

methods: {
completeTodo(todo) {
this.$emit('completeTodo', todo)
}
}

Pattern này khá phổ biến và cũng thường xuyên được áp dụng. Anh em có thể đã khá quen với pattern này rồi.

2. Children mutating props – Thay đổi props

Mục đích chính của pattern này là tuyệt đối không thay đổi props khi đã đưa qua component con

Props should be considered the source of truth when passed down to a component and thus, change the value from within a child component is typically bad practice

Props nên được cân nhắc để không thay đổi khi đã gửi qua component, thay đổi props khi gửi qua child component cũng là bad practice

Thay đổi props

BAD

methods: {
completeTodo(todo) {
this.todo = [{id: 1, name: 'Do the dishes.'}];
this.$emit('completeTodo', todo)
}
}

Component props tuyệt đối không nên thay đổi, chỉ được sử dụng

GOOD

export default {
props: {
age: {
type: Number,
}
},
data() {
return {
personAge: this.age
}
},
}

Nếu muốn thay đổi giá trị props thì tạo variable mới, việc thay đổi hoặc change value của props rất dễ gây confuse cho việc sử dụng sau này, cũng như tiềm ẩn nhiều bug out of control.

3. Mutating property arrays

Trong danh sát Vuejs Anti Pattern được liệt kê ở bài viết này, mutating là pattern không được nhiều người để ý tới. Hoặc sau khi có bug ẩn mới phát hiện và chú ý tới. Pattern này cũng liên quan tới props, tuy nhiên cái cần để tâm là liên quan tới arrays

An important consideration to make when passing down arrays and objects as properties within JavaScript is the fact that they are passed by reference

Một điểm quan trọng khi pass props có kiểu dữ liệu array hoặc object thì kiểu gửi này là kiểu gửi tham chiếu (reference)

Chính vì kiểu gửi tham chiếu nên khi thay đổi data ở component con rất có thể sẽ ảnh hưởng tới props truyền vào ở component cha.

BAD

<template>
<div>
<h1>Parent Component</h1>
<ul>
<li v-for="friend in friendList" :key="friend.id">{{friend.name}}</li>
</ul>

<Person :friendList="friendList" />
</div>
</template>

<script>
import Person from './components/Person';

export default {
data() {
return {
friendList: [{ id: 1, name: 'John Doe' }]
}
},
components: {
Person
}
}
</script>

Ở component con, nếu ta thay đổi value của array truyền vào, sẽ ảnh hưởng trực tiếp tới value ở component cha

<template>
<div>
<h1>Child Component</h1>
<ul>
<li v-for="friend in friendList" :key="friend.id">{{friend.name}}</li>
</ul>
<button @click="addFriend">Add Friend</button>
</div> 
</template>

<script>
export default {
props: {
friendList: {
type: Array,
}
},
methods: {
addFriend() {
this.friendList.push({ id: 2, name: 'Sarah Doe' })
}
}
}
</script>

Việc thay đổi mất kiểm soát này có thể phát sinh bug, để tránh những vấn đề không đáng có này, ta có thể tạo variable mới có cùng value với props truyền vào

Vuejs Anti patternComponent con đổi data, thằng cha đổi theo

GOOD

export default {
props: {
friendList: {
type: Array,
}
},
data() {
return {
fList: [...this.friendList]
}
},
methods: {
addFriend() {
this.fList.push({ id: 2, name: 'Sarah Doe' })
}
}
}

4. Using data as an object

Đây là anti pattern cuối trong chuỗi bài Vuejs Anti Pattern. Pattern này nói về cách sử dụng data. Tuyệt đối tránh sử dụng data như là một object

When creating components with Vue, it’s important that the data option is a function that returns a new object holding data, rather than just a plain data object.

Khi tạo component với Vue, điều quan trọng là data option bản thân nó là một function trả về một object mới, không phải là một data object thuần túy

Nếu ta sử dụng data object không phải là một function, tất cả instance của component sẽ dùng chung một data, không tốt.

Mỗi khi data change, tất cả instance của component cũng sẽ thay đổi theo, cái này khá tệ về mặt performance. Để đảm bảo component chỉ quản lý data thuộc về nó, tránh những component khác bị kéo theo. Ta nên sử dụng return

BAD

data: {
recipeList: [],
selectedCategory: 'Desserts'
}

GOOD

data () {
return {
recipeList: [],
selectedCategory: 'Desserts'
}
}

By creating the return statement, it allows each instance created to have its own object rather than a shared one. This then allows the code to be used multiple times without the conflict of shared data.

Bằng cách sử dụng return, việc này cho phép mỗi instance khi được tạo sẽ có data object của riêng nó. Việc này cũng cho phép code được sử dụng nhiều lần mà không gây ra đụng độ do việc chia sẻ data

Component cũng có thể reuse nhiều lần mà không bị đụng độ cũng như tránh việc update data liên tục ở các component khác.

5. Tham khảo thêm về Vuejs Anti Pattern

Thank for your time to read – 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 Việc làm IT hấp dẫn trên TopDev

Đổi tên của một Container trong Docker

Đổi tên của một Container trong Docker

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

Trong bài viết này, mình hướng dẫn các bạn cách đổi tên của một container trong Docker.

  20 trường hợp sử dụng lệnh Docker cho developer
  Cách tạo một Docker đơn giản cho Node.JS

Ví dụ bây giờ, Docker trong máy mình đang chạy một container như sau:

Đổi tên của một Container trong Docker

Đây là container được chạy từ Docker Image của SonarQube, lúc chạy nó mình quên không đặt cho nó một cái tên để dễ phân biệt nếu sau này mình còn chạy thêm những Docker container khác. Hiện tại tên của nó là recursing_ardinghelli, mình sẽ rename nó lại sử dụng câu lệnh sau:

docker rename <container_id> <new_name>

Ví dụ, mình đổi tên của container của mình sử dụng câu lệnh sau:

docker rename 45949b2cc114 SonarQube

Đổi tên của một Container trong Docker

Kết quả:

Đổi tên của một Container trong Docker

Những Nỗi Khổ Của Dân IT Không Phải Ai Cũng Biết

nỗi khổ của dân IT
Những Nỗi Khổ Của Dân IT Không Phải Ai Cũng Biết

Ngành Công nghệ thông tin trong nhiều năm trở lại đây luôn được đánh giá là ngành hot với lực lượng lao động dồi dào cùng mức lương khá hấp dẫn. Nhiều sinh viên lựa chọn theo học ngành này với ước mơ về một mức lương cao và được đón đầu những công nghệ tiên tiến nhất trên thế giới. Những điểm sáng của ngành IT là không thể chối bỏ, nhưng cũng không thể phủ nhận rằng dân IT vẫn phải đối mặt với rất nhiều khó khăn để đạt được thành tựu trong công việc. Có những nỗi khổ của dân IT mà người ngoài ngành không phải ai cũng thấu hiểu.

nỗi khổ của dân IT
Những nỗi khổ của dân IT mà người ngoài ngành có thể chưa biết

1. Thường xuyên stress và khó giao tiếp với thế giới bên ngoài hơn

Trong thực tế, lượng công việc và dự án mà mỗi lập trình viên phải làm việc hằng ngày là khá nhiều. Nguyên nhân chủ yếu là vì hầu hết các công ty ở Việt Nam vẫn đang trong quá trình cập nhật công nghệ và xây dựng tiến trình để phát triển, do đó đầu việc phải đáp ứng cũng nhiều hơn. Việc phải suy nghĩ nhiều, căng thẳng khi làm việc và thiếu ngủ thường xuyên sẽ khiến tình trạng stress ở các lập trình viên dần xuất hiện nhiều hơn. Vậy nên cũng không quá khó hiểu khi dân IT thường xuyên khó chịu hay gắt gỏng.

Bên cạnh đó, vì mỗi ngày phải dành trung bình 8 – 10 tiếng để đối diện với màn hình máy tính và ít khi ra ngoài nên khả năng giao tiếp của các lập trình viên cũng thường giảm đi. Dân IT luôn bị đánh giá là những người ít nói hay thiếu sự linh động trong giao tiếp một phần cũng vì những lý do này.

  TOP 7 Dấu Hiệu Giúp Nhận Biết Một Cuộc Phỏng Vấn Thành Công
  Những Kinh Nghiệm Phỏng Vấn Hữu Ích Cho Sinh Viên Mới Ra Trường

2. Người quen thường xuyên nhờ vả

Đây có lẽ là nỗi khổ quen thuộc của dân IT. Việc bị bạn bè, người thân nhờ vả khi máy tính trục trặc, máy khởi động chậm, cài windows,… là chuyện mà lập trình viên nào cũng từng trải qua. Việc giúp đỡ không quá khó khăn với một người lập trình máy tính, tuy nhiên những lời nhờ vả không chỉ đến 1, 2 lần mà thậm chí là rất thường xuyên. Việc này có thể gây cản trở và làm ảnh hưởng đến luồng công việc đã dày đặc của lập trình viên. Do đó, hãy nói không khi bạn thật sự không thể để không gây trở ngại với công việc của bản thân.

Xem thêm các việc làm IT Service lương cao trên TopDev

3. Vẻ ngoài có thể tàn phai nhanh chóng hơn

Ánh sáng xanh của màn hình máy tính và các thiết bị điện tử không tốt cho sức khỏe, mắt và da của chúng ta. Trong khi đó, dân IT phải tiếp xúc với máy tính thường xuyên và liên tục mỗi ngày. Lâu dần sự tác động của những “chất độc hại” này lên da là rất nguy hiểm và khiến bạn có thể nhanh già hơn nếu không được chăm sóc cẩn thận.

Bên cạnh đó, không tập luyện thể dục thể thao thường xuyên cũng có thể khiến cơ thể dễ mắc bệnh hơn. Đặc biệt, nhiều minh chứng khoa học đã cho thấy người làm việc với máy tính quá nhiều có nguy cơ bị vô sinh cao hơn so với những ngành nghề khác.

Xem thêm Nguyên Tắc 4 KHÔNG Khi Xin Việc Ai Cũng Cần Nhớ

4. Việc tăng lương diễn ra khá chậm

Làm việc trong ngành IT lương khởi điểm của lập trình viên sẽ cao hơn hẳn so với một số ngành khác nhưng tốc độ tăng lương lại khá chậm. Do đó, đây cũng là một trong những nỗi khổ to lớn của dân IT. Nếu tìm được một công việc có mức lương đầu vào hấp dẫn, lập trình viên có thể sẽ thoải mái hơn khi làm việc và gắn bó với công việc đó lâu hơn. Và đa phần, để cải thiện mức lương của mình, cách giải quyết của dân IT là nhảy việc.

5. Khả năng bị tự kỷ cao hơn những ngành khác

Thói quen sinh hoạt thường gặp ở các lập trình viên là làm việc chủ yếu vào ban đêm, nhất là với các lập trình viên hoạt động tự do (freelance developers).

Mỗi khi có dự án mới xuất hiện thì tần suất “hoạt động về đêm” của lập trình viên càng tăng cao. Việc hoạt động như thế này lâu ngày khiến các lập trình viên dễ mắc các bệnh về dạ dày cũng như thần kinh hơn. Kết hợp với việc ít vận động nên cơ thể luôn trong tình trạng mệt mỏi mỗi khi kết thúc công việc. Duy trì lối sinh hoạt với giờ giấc thiếu khoa học là căn nguyên của nhiều căn bệnh nguy hiểm.

6. Làm thêm giờ đã trở thành thói quen

Với công việc của một lập trình viên, làm việc theo khung giờ nhất định và tan ca đúng giờ hiếm khi xảy ra. Lập trình viên sẽ thường xuyên tăng ca thêm 1, 2 tiếng để hoàn thành nốt công việc đang dang dở hoặc làm xong cho kịp deadline. Đây là đặc thù của công việc nên dù muốn hay không thì việc làm thêm ngoài giờ đã trở thành thói quen với nhiều lập trình viên.

Xem thêm TOP 5 Công Việc Freelance Hot Nhất và Có Thu Nhập Cao Nhất Hiện Nay

7. Tỷ lệ độc thân cao hơn hẳn so với các ngành nghề khác

Vì đặc thù của ngành IT nên khi học đại học, số lượng sinh viên nữ rất ít so với các ngành nghề khác. Đến khi ra trường và đi làm thì số lượng nữ giới lại càng giảm đi. Việc ít có cơ hội tiếp xúc với người khác giới cũng là nguyên nhân khiến các lập trình viên luôn trong tình trạng độc thân. Và điều này cũng dẫn đến xác suất lập gia đình với người cùng ngành là rất cao.

Công việc IT có vẻ bề ngoài hào nhoáng nhưng cũng có không ít khó khăn mà người làm trong ngành phải đối mặt. Để thành công, mỗi người phải tự vượt qua chính mình và đương đầu với những thách thức mà ngành nghề đặt ra. Hy vọng với bài viết này, người đọc có thể hiểu thêm phần nào đó những nỗi khổ của dân IT.

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

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

Cách Import dữ liệu từ File Script vào trong SQL Server

Cách Import dữ liệu từ File Script vào trong SQL Server

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

Chào các bạn, trong các bài viết trước thì mình đã cùng với các bạn cài đặt SQL Server, tạo kết nối đến SQL Server thông qua SSMS (SQL Server Management Studio) và tìm hiểu về một số những thao tác cơ bản với SQL Server rồi phải không ạ.

Còn ở trong bài viết tiếp theo này, mình sẽ cùng với các bạn tìm hiểu về cách để mở và chạy một file script (file chứa các câu lệnh SQL) để thực hiện tạo các bảng và Insert dữ liệu mẫu vào SQL Server thông qua SSMS.

  "Làm PM, theo anh không cần biết về code, nhưng phải hiểu về SQL, database, những khái niệm cơ bản của code"
  Các thao tác cơ bản với Database SQL Server (tạo mới database, table,...)

Xem thêm nhiều việc làm SQL hấp dẫn trên TopDev

#1. Thiết kế của cơ sở dữ liệu

Việc hiểu và nắm được thiết kế của cơ sở dữ liệu là một điều rất quan trọng khi các bạn làm việc với các hệ quản trị cơ sở dữ liệu.

Dưới đây chính là thiết kế của cơ sở dữ liệu mẫu mà mình sẽ dùng trong bài viết này. Tất cả đã được viết dưới dạng Script. Các bạn có thể tải file tại đây hoặc tại đây.

cach-tai-du-lieu-tu-file-script-trong-sql-server (1)

#2. Tạo mới cơ sở dữ liệu

Đầu tiên thì anh em kết nối đến cơ sở dữ liệu SQL Server thông qua SSMS như mình đã hướng dẫn trong các bài viết trước.

cach-tai-du-lieu-tu-file-script-trong-sql-server (2)

Sau đó tạo mới một database bằng cách bấm vào Database => và chọn New Database… như hình bên dưới.

cach-tai-du-lieu-tu-file-script-trong-sql-server (3)

Do trong Script mình đã định nghĩa tên cở dữ liệu là BikeStores nên ở mục Database name các bạn nên đặt là BikeStores để tránh trường hợp biên dịch Script bị lỗi.

=> Sau khi đặt tên xong thì bấm OK để tiếp tục.

cach-tai-du-lieu-tu-file-script-trong-sql-server (4)

Okay, vậy là chúng ta đã có một database có tên là BikeStores rồi. Tuy nhiên, lúc này cơ sở dữ liệu của chúng ta vẫn trống và không có gì hết.

cach-tai-du-lieu-tu-file-script-trong-sql-server (5)

#3. Mở và chạy các file Script trong SSML

Tiếp theo chúng ta sẽ mở Script và chạy đoạn Script đó để thêm các bảng và dữ liệu mẫu vào cơ sở dữ liệu vừa tạo.

Thực hiện: Các bạn vào phần File => chọn Open => và chọn File như hình bên dưới. Hoặc bạn có thể sử dụng tổ hợp phím CTRL + O cho nhanh cũng được.

cach-tai-du-lieu-tu-file-script-trong-sql-server (6)

Đoạn Script đầu tiên (Create Objects) sẽ là đoạn Script dùng để tạo các bảng trong cơ sở dữ liệu. Các bạn sẽ mở và chạy file này đầu tiên để tạo các bảng trong cở sở dữ liệu.

cach-tai-du-lieu-tu-file-script-trong-sql-server (7)

Sau khi mở các bạn bấm Execute để thực hiên biên dịch đoạn Script đó.

cach-tai-du-lieu-tu-file-script-trong-sql-server (8)

Và lúc này trong phần Tables các bạn sẽ thấy toàn bộ các bảng như trong thiết kế đã được tạo thành công, ngoài ra sẽ có một thông báo với nội dung Commands completed successfully trong phần Messages.

cach-tai-du-lieu-tu-file-script-trong-sql-server (9)

Các bạn làm tương tự với file thứ 3 (Load data) là file sẽ thêm các dữ liệu mẫu vào trong các bảng của cơ sở dữ liệu.

cach-tai-du-lieu-tu-file-script-trong-sql-server (10)

Tiếp tục bấm Execute để biên dịch đoạn Script.

cach-tai-du-lieu-tu-file-script-trong-sql-server (11)

Các bạn có thể quan sát trong phần Messages trả về như hình bên dưới là đã thêm thành công dữ liệu.

cach-tai-du-lieu-tu-file-script-trong-sql-server (12)

Để kiếm tra lại các bạn có thể mở một bảng bất kỳ để xem dữ liệu đã được thêm vào hay chưa. Ở đây mình mở bảng production.categories

cach-tai-du-lieu-tu-file-script-trong-sql-server (13)

#4. Lời kết

Okay, quá trình Import dữ liệu từ vào trong SQL Server Management Studio cũng tương đối đơn giản phải không các bnạ.

Qua bài viết này thì mình tin là các bạn cũng đã biết cách dùng Script file để tạo ra các bảng cũng như thêm dữ liệu vào cơ sở dữ liệu trong SQL Server rồi phải không!

Trên thực tế khi làm dự án người ta có thể kết xuất một Database (Export) thành file Script để có thể mang sang các máy khác để chạy rất tiện lợi.

Okay, hẹn gặp lại các bạn trong các bài viết tiếp theo về SQL Server nhé.

CTV: Nguyễn Đức Cảnh – Bài viết gốc tại blogchiasekienthuc.com

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

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

Học Haskell không phải trầm trồ – theo cách Pymi.vn

Học Haskell không phải trầm trồ - theo cách Pymi.vn

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

  • Cảnh báo: rất giống Python
  • Chú ý: không cần biết Python

Haskell (/ˈhæskəl/) – visub: ha-s-kồ – 1990 (lớn hơn Python 1 tuổi) Trang chủ: https://www.haskell.org/

Haskell

Haskell là ngôn ngữ functional (lập trình hàm), thuộc nhóm “pure” blah blah blah có thể bỏ qua và gõ cho đến cuối bài, work first, talk is cheap, later.

  Fix Lỗi "RDP Authentication Error Has Occurred – The Function Requested Is Not Supported"
  So sánh tốc độ List collection và HashSet collection trong C#

Cài đặt

Hướng dẫn trang chủ, hỗ trợ cả Windows

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

enter enter enter … rồi mở terminal mới, gõ ghci.

ghci --version
The Glorious Glasgow Haskell Compilation System, version 8.10.5

Trên Ubuntu có thể dùng:

sudo apt-get update && sudo apt-get install -y haskell-stack

REPL

REPL – Read Eval Print Loop, là chương trình nhận code người dùng nhập vào (Read), chạy code đó (Eval), in kết quả ra màn hình (Print), và cứ tiếp tục vậy (Loop).

Khái niệm này bắt nguồn từ ngôn ngữ lập trình cổ thứ 2 thế giới: LISP.

Việc viết code khi dùng các ngôn ngữ có REPL thường theo các bước:

  • bật REPL lên
  • gõ code thử cho tới khi thu được kết quả mong muốn
  • copy code đó vào editor/IDE

Câu lệnh bật REPL của Haskell có tên ghci.

$ ghci
GHCi, version 8.10.5: https://www.haskell.org/ghc/  :? for help
Prelude> 1 + 1
2
Prelude> 2 * 1024
2048

Prelude> :quit
Leaving GHCi.

Haskell Hello world

Prelude> print "Hello Pymier!"
"Hello Pymier!"

Integer

cộng + trừ - nhân * mũ/lũy thừa ^

Prelude> 54 + 5 * (2 + 1)
69
Prelude> 2 ^ 1000
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376

Float

Prelude> 4 / 2
2.0
Prelude> 5 / 2
2.5
Prelude> 5 / 2.5
2.0
Prelude> 0.1 + 0.1 + 0.1
0.30000000000000004

Prelude> 0.1 + 0.1 + 0.1 == 0.3
False
Prelude> 0.1 + 0.1 + 0.1 /= 0.3
True

Tại sao 0.1 + 0.1 + 0.1 /= 0.3

Boolean

Prelude> 2 < 5
True
Prelude> 2 > 5
False
Prelude> 1 + 1 == 2
True
Prelude> 2 - 1 /= 0
True
Prelude> 2 <= 2
True
Prelude> 1/0
Infinity

and

Prelude> True && True
True
Prelude> True && False
False
Prelude> False && True
False
Prelude> False && False
False

or

Prelude> True || True
True
Prelude> True || False
True
Prelude> False || True
True
Prelude> False || False
False

not

Prelude> not True
False
Prelude> not False
True

Haskell boolean có tính short-circuit – dừng lại ngay khi có thể kết luận kết quả biểu thức boolean.

Prelude> error "huhu"
*** Exception: huhu
CallStack (from HasCallStack):
  error, called at <interactive>:2:1 in interactive:Ghci2
Prelude> True || error "huhu"
True
Prelude> False && error "huhu"
False

hay nói cụ thể:

  • || sẽ dừng lại và trả về kết quả ngay khi gặp True
  • && sẽ dừng lại và trả về kết quả ngay khi gặp False

Với các ngôn ngữ khác, boolean có short-circuit hay không thì tùy từng ngôn ngữ quyết định, nhưng với một tính năng nổi bật của Haskell: Lazy, short-circuit là chuyện đương nhiên.

type

Các câu lệnh trong ghci

  • :help
  • :info
Prelude> :info mod
type Integral :: * -> Constraint
class (Real a, Enum a) => Integral a where
  ...
  mod :: a -> a -> a
  ...
    -- Defined in ‘GHC.Real’
infixl 7 `mod`

Prelude> :info (+)
type Num :: * -> Constraint
class Num a where
  (+) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Num’
infixl 6 +

Hiển thị type:

Prelude> :set +t

Prelude> 1
1
it :: Num p => p

Prelude> 0.1
0.1
it :: Fractional p => p

số nguyên 1 có kiểu Num, số float 0.1 có kiểu Fractional

Prelude> True
True
it :: Bool

giá trị boolean True có kiểu Bool

Prelude> "con mèo trèo"
"con m\232o tr\232o"
it :: [Char]
Prelude> length "con mèo trèo"
12
it :: Int

string là 1 list của các Char (character – ký tự)

Prelude> [1..10]
[1,2,3,4,5,6,7,8,9,10]
it :: (Num a, Enum a) => [a]

kiểu list được biểu diễn bởi dấu []

it là biểu thức/kết quả cuối cùng bạn đã gõ. Tương tự _ trong Python interpreter.

Prelude> 1
1
Prelude> it + 2
3

ProjectEuler problem 1

https://projecteuler.net/problem=1

Chú ý: theo chương trình học của Pymi.vn, phần này được học ở buổi số 4. Bạn đọc cần biết Python để hiểu phần này hoặc chỉ cần gõ theo. Có thể đọc thêm tại đây.

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.

Tạo list các số từ 1 đến 5

Prelude> [1..5]
[1,2,3,4,5]

Haskell không dùng % cho phép chia lấy phần dư (modulo/remainder), code Python 10 % 3 tương đương với viết Haskell mod 10 3 hoặc rem 10 3

Haskell dùng || && thay Python or and

Python 2.0 MƯỢN list comprehension từ Haskell

>>> sum([i for i in range(1000) if i % 3 == 0 or i % 5 == 0])
233168

Haskell dùng | thay chữ for, dùng <- thay chữ in, dùng , thay chữ if so với Python

Prelude> sum [i | i <- [1..999], mod i 3 == 0 || mod i 5 == 0]
233168

Bonus: bài PE16:

Tính tổng các chữ số của 2 mũ 1000

Prelude> sum [read [i] :: Integer | i <- show (2^1000)]
1366

Các đặc tính nổi bật của Haskell

Theo wiki Haskell

Haskell is a computer programming language. In particular, it is a polymorphically statically typed, lazy, purely functional language, quite different from most other programming languages. The language is named for Haskell Brooks Curry, whose work in mathematical logic serves as a foundation for functional languages. Haskell is based on the lambda calculus, hence the lambda we use as a logo.

  • polymorphically statically typed
  • lazy
  • purely functional

hoặc xem phần features trên https://www.haskell.org/

lập trình hàm là gì

Haskell là ngôn ngữ thuộc nhóm functional (lập trình hàm).

Trên lý thuyết, có nghĩa nó dựa trên “lambda calculus”, một mô hình/hệ thống tính toán dùng các function (hàm toán học), khác với mô hình Turing Machine mà các ngôn ngữ lập trình C, Java, Python, Go… dựa trên. Hai mô hình này được chứng minh về mặt toán học là có khả năng như nhau.

Về mặt thực hành, code với 1 ngôn ngữ functional thường có nghĩa là:

  • không dùng vòng lặp for/while mà dùng các function có sẵn để làm việc tương tự (vd: map, filter, fold, reduce,…) hoặc viết các recursive function để thu được kết quả tương ứng.
  • Các kiểu dữ liệu thường là immutable, khi thay đổi 1 list, Haskell sẽ tạo ra 1 list mới với những thay đổi đã thực hiện (và bỏ list cũ đi).
  • First class function: quen với việc dùng function này làm đầu vào cho function khác. Ví dụ map map (\x -> x * 2) [1..5] nhận function \x -> x * 2 và 1 list để thực hiện function đó trên tất cả các phần tử trong list.

Haskell purely functional là gì

pure function là một function không có “side effect”, giống hàm toán học, kết quả đầu ra chỉ phụ thuộc đầu vào.

f(x) = 2x + 1
f(30) luôn luôn bằng 61

Side effect là việc function thực hiện 1 thay đổi nào đó (thay đổi phần tử 1 list, đọc ghi 1 file, in ra màn hình, kết nối internet, sleep chương trình, …) hay phụ thuộc vào yếu tố khác với đầu vào (một chương trình phụ thuộc vào thời gian lúc nó chạy) nghe hơi vô lý khi một ngôn ngữ mà không tương tác với thế giới bên ngoài thì… chỉ để học toán. Nhưng Haskell sẽ dựa trên 1 khái niệm/cơ chế hoàn toàn khác để thực hiện các việc nói trên.

Haskell lazy là gì

lazy là chỉ thực hiện tính toán khi thực sự cần tới giá trị. Ví dụ có thể viết code tạo ra list từ 1 tới vô cùng, nhưng vì Haskell lazy, nó chỉ lấy ra phần tử nó cần, chứ không tạo list từ 1 tới vô cùng từ đầu.

Prelude> take 10 [1..]
[1,2,3,4,5,6,7,8,9,10]
Prelude> take 20 [1..]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

Trong Python, khái niệm gần nhất với lazy là generator

Để Haskell bắt buộc phải tính list [1..] tới vô cùng, ta dùng 1 function cần phải duyệt đến phần tử cuối cùng của list – như tính độ dài : length

Prelude> length [1..]
^CInterrupted.

code này sẽ chạy mãi cho tới khi người dùng tắt chương trình hoặc bấm Ctrl-C.

Kết luận

Ngày đầu của Haskell không hề khó hơn ngày đầu học Python. Đừng vì “cộng đồng mạng” nói khó mà chưa thử đã tin!

Tham khảo

  • https://pymi.vn/tutorial/python-integer/
  • https://pymi.vn/tutorial/python-calculation-2/
  • RealWorldHaskell

What next?

Loạt bài viết dự kiến có 6-8 bài, ứng với 6-8 buổi học Python tại pymi.vn

Ủng hộ tác giả viết phần tiếp theo

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 Việc làm IT hấp dẫn trên TopDev

Kinh nghiệm làm framework cho IOS

Kinh nghiệm làm framework cho IOS

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

Đây là 1 số kinh nghiệm cho anh em nào định viết framework hỗ trợ IOS, để anh em đỡ mất thời gian nghiên cứu.

  10 Frameworks tốt nhất hiện nay cho PHP
  .NET core vs ASP.NET core: Phân biệt .NET Framework, .NET Core và Mono

Xem thêm nhiều việc làm iOS lương cao trên TopDev

Giải pháp mình đúc rút ra như sau:

  1. Framework thì nên viết bằng Objective-C:
    – Lý do chọn objective-C là vì nó đã không thay đổi gì nữa, chạy ổn định. Hiện tại mỗi năm Apple lại cho ra đời 1 phiên bản swift mới nên nếu dùng swift để viết thì đau thương lắm, mỗi lần lên là bạn phải update cho cả project đang dùng swift mới. Đây cũng là lý do vì sao mà bạn thấy FireBase hay FacebookCore đều dùng Objective-C để viết framework cho họ. Mặc dù mình biết nhiều người code swift chưa hẳn đã biết Objective-C, cú pháp khó hơn. Nhưng cuộc sống mà, bạn muốn làm Framework thì trình bạn cũng cao, nghĩa là bạn nên biết cả 2 ngôn ngữ.

2. Khi làm framework, thì bạn phải support cả simulator và device. Do vậy bạn phải có script để build cho chúng. Cụ thể là xcframework.

3. Bạn nên tạo 1 cái project demo tách biệt với project framework. Làm như vậy thì việc test chuẩn hơn, đôi khi phát hiện được lỗi dễ hơn.

Tôi sẽ tiến hành tạo 1 framework cho bạn hiểu.

Mở Xcode tạo mới Framework như hình.

Đặt tên là CodeToanBug(hoặc theo ý bạn).

Chỉnh lại version support càng thấp càng tốt, ví dụ mình chọn 9.0:

Tiến hành tạo workspace bằng cách File -> New -> Workspace. Đặt tên là CodeToanBug hoặc tùy ý.

Sau đó tắt project đang mở, nhưng vẫn mở Workspace nhé. Sau đó thì kéo file CodeToanBug.xcodeproj vào Workspace được như hình:

Sau khi kéo thả

Mục đích là để tý mình tạo thêm 1 project demo ở trong Workspace luôn.

Tiếp tục chọn target CodeToanBug rồi vào Organization thêm codetoanbug để định danh bản quyền, và Class Prefix CTB(viết tắt codetoanbug) để nó tự thêm prefix khi tạo mới file.

Bây giờ thêm 1 hàm cộng 2 số để framework có tính năng. Thêm file tên là CTBMath.h như hình:

Viết hàm trong file .h:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface CTBMath : NSObject

- (int)addTwoNumbers:(int)number1 secondnumber:(int)number2;

@end

NS_ASSUME_NONNULL_END

Trong file .m:

#import "CTBMath.h"

@implementation CTBMath

/// Add two numbers
/// @param number1 number1 need add
/// @param number2 number2 need add
- (int)addTwoNumbers:(int)number1 secondnumber:(int)number2 {
    return number1 + number2;
}
@end

Sau đó bấm vào file CTBMath.h rồi chọn như hình:

Hoặc biết kéo thả thì vào target CodeToanBug rồi chọn Build phases thêm file public để cho thằng nào dùng framework này cũng đọc được:

OK vậy là xong framework.

Bước tiếp theo là làm sao để build cho device và simulator.

Tạo universal framework như sau:

Chọn File -> New target -> Other -> Aggregate:

Đặt tên CodeToanBugFramework hoặc tùy ý.

Bây giờ nó xuất hiện thêm target này thì bạn chọn vào nó và chọn Build Phases và chọn New Run Script Phase:

Tiếp theo thêm mã này vào:


# Universal Script

set -e

FRAMEWORK_NAME="CodeToanBug"
IOS_SCHEME_NAME="CodeToanBug"

if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

SIMULATOR_ARCHIVE_PATH="${SRCROOT}/build/${FRAMEWORK_NAME}-iphonesimulator.xcarchive"
DEVICE_ARCHIVE_PATH="${SRCROOT}/build/${FRAMEWORK_NAME}-iphoneos.xcarchive"

OUTPUT_DIR="${SRCROOT}/framework_out_universal/"

# Simulator xcarchieve
xcodebuild archive \
  -scheme ${IOS_SCHEME_NAME} \
  -archivePath ${SIMULATOR_ARCHIVE_PATH} \
  -configuration Release \
  -sdk iphonesimulator \
  SKIP_INSTALL=NO

# Device xcarchieve
xcodebuild archive \
  -scheme ${IOS_SCHEME_NAME} \
  -archivePath ${DEVICE_ARCHIVE_PATH} \
  -sdk iphoneos \
  -configuration Release \
  SKIP_INSTALL=NO

# Clean up old output directory
rm -rf "${OUTPUT_DIR}"

# Create xcframwork combine of all frameworks
xcodebuild -create-xcframework \
  -framework ${SIMULATOR_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework \
  -framework ${DEVICE_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework \
  -output ${OUTPUT_DIR}/${FRAMEWORK_NAME}.xcframework

# Delete the most recent build.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

Chọn như hình rồi bấm run:

Run thành công thì mở thư mục code lên bạn sẽ thấy cái này:

Đây chính là xcframework mà bạn có thể build cho cả 2.

Tạo 1 project demo trong Workspace này bằng cách File -> New -> Target -> App như hình:

Đặt tên là DemoSwift. Nhớ chọn Language là swift.

Sau đó sửa code ở file ViewController.swift như sau:

import UIKit
import CodeToanBug

class ViewController: UIViewController {
    let math = CTBMath()

    override func viewDidLoad() {
        super.viewDidLoad()
        print(math.addTwoNumbers(12, secondnumber: 12))
    }
}

Nhưng muốn nó hiểu thì phải add CodeToanBug.framework vào như hình:

Nếu bạn build app mà nó lên 24 là đã chạy được.

Bây giờ tiến hành test với 1 project độc lập.

Tạo mới 1 project độc lập có tên là TestFramework bằng swift. Sau đó mở thư mục framework_out_universal rồi tiến hành kéo thả CodeToanBug.xcframework như hình(nhớ chọn copy if need):

Và chỉnh Embed & Sign(nếu không sẽ không build được máy thật – lỗi Reason: image not found):

Sau đó lại code như sau:

Nếu chạy app mà ra 25 là Framework đã hoạt động.

Đây là code bạn có thể tải về tham khảo:

https://github.com/codetoanbug/CodeToanBug-IOS

Nếu có góp ý gì xin comment ở dưới. Thank for reading.

Code ví dụ spring boot h2 database (khởi tạo database)

Code ví dụ spring boot h2 database (khởi tạo database)

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

Code ví dụ spring boot h2 database (khởi tạo database)

Trong bài này mình sẽ làm một ví dụ nhúng hệ quản trị cơ sở dữ liệu H2 vào project spring boot.

Việc này đặc biệt hữu ích trong quá trình làm các demo, với H2 chúng ta không cần phải cài các cơ sở dữ liệu phức tạp như MySQL, MSSQL… mà vẫn có thể thực thi các câu lệnh sql với database bình thường với H2.

Với H2 ta có thể nhúng sẵn 1 database, các data cần thiết và khởi tạo nó lúc chạy project.

  "Làm PM, theo anh không cần biết về code, nhưng phải hiểu về SQL, database, những khái niệm cơ bản của code"
  Các thao tác cơ bản với Database SQL Server (tạo mới database, table,...)

1. Code ví dụ spring boot h2 database (khởi tạo database)

Tạo project Spring Boot: File > New > Module

code ví dụ spring boot h2 database (khởi tạo database) code ví dụ spring boot h2 database (khởi tạo database)

Các thư viện sử dụng gồm Spring WebSpring Data JPAH2 Database

code ví dụ spring boot h2 database (khởi tạo database) code ví dụ spring boot h2 database (khởi tạo database)

Cấu trúc project sau khi hoàn thành:

code ví dụ spring boot h2 database (khởi tạo database)

File Application: (giống hệt các project spring boot thông thường)

package stackjava.com.sbh2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootH2Application {

public static void main(String[] args) {
 SpringApplication.run(SpringBootH2Application.class, args);
}

}

File application.properties

#spring.datasource.url=jdbc:h2:file:E:/stackjava/testdb
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

# Enabling H2 Console
spring.h2.console.enabled=true
# Custom H2 Console URL
spring.h2.console.path=/h2
  • spring.datasource.url: url của database, jdbc:h2:mem database sẽ được tạo ở bộ nhớ đệm, sẽ bị mất sau khi project bị tắt. Nếu bạn muốn lưu lại thì có thể lưu database ở file với jdbc:h2:file
  • spring.datasource.username và spring.datasource.password là thông tin xác thực cho database
  • spring.h2.console.enabled=true tức là cho phép truy cập database h2 qua giao diện
  • spring.h2.console.path=/h2 đường dẫn truy cập database h2 qua giao diện là /h2

File schema.sql

DROP TABLE IF EXISTS tbl_user;

CREATE TABLE tbl_user (
 id INT AUTO_INCREMENT PRIMARY KEY,
 username VARCHAR(250) NOT NULL,
password VARCHAR(250) NOT NULL
);

Khi start project, hệ thống sẽ đọc file này để tạo database. (ở đây mình tạo bảng tbl_user với 3 column là id, username, password)

File data.sql

INSERT INTO 
tbl_user (username, password)
VALUES
('stackjava', 'stackjava'),
('admin', 'admin1234'),
('root', 'root');

Sau khi đọc file schema.sql hệ thống sẽ đọc file data.sql để xử lý data (ở đây mình thực hiện insert 3 bản ghi vào bảng t_user)

Demo

Start project và truy cập vào địa chỉ http://localhost:8080/h2

code ví dụ spring boot h2 database (khởi tạo database)

Connect để xem thông tin của database vừa tạo.

code ví dụ spring boot h2 database (khởi tạo database)

Với database này chúng ta có thể dễ dàng demo các ví dụ về spring data jpa, hibernate… có thể chạy thử dễ dàng, ko cần phải cài đặt các database phức tạp.

Okay, Done!

Download code ví dụ trên tại đây hoặc tại https://github.com/stackjava/spring-boot-h2

References: https://docs.spring.io/spring-boot/…/howto-database-initialization.html

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 IT hấp dẫn trên TopDev