Home Blog Page 83

Cài đặt RabbitMQ

rabbitmq

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

Trong bài này, tôi sẽ hướng dẫn các bạn cách cài đặt RabbitMQ Server. Có nhiều cách cài đặt, có thể sử dụng stanalone file, sử dụng package manager/ installer hay Docker.

  Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud
  Giới thiệu RabbitMQ Management Interface

Cài đặt RabbitMQ Server sử dụng Package manager

Cài đặt Erlang

Vì RabbitMQ được viết sử dụng ngôn ngữ Erlang nên để cài đặt nó các bạn cần cài đặt Erlang trước.

Với MacOS, không cần phải cài đặt Erlang bởi vì Homebrew cài đặt RabbitMQ đã bao gồm Erlang runtime dependency.

Cài đặt RabbitMQ trên MacOS

Đầu tiên, các bạn hãy download phiên bản mới nhất của RabbitMQ tại địa chỉ: https://www.rabbitmq.com/download.html.

Nó có nhiều phiên bản cho nhiều môi trường khác nhau nhưng trong bài viết này, hãy lựa chọn phiên bản phù hợp với hệ điều hành của các bạn. Ở đây mình đang sử dụng hệ điều hành macOS, do đó mình sẽ chọn Homebrew dành cho macOS.

Nếu bạn chưa cài HomeBrew (HomeBrew là một package manager dành cho macOS), hãy chạy lệnh sau để cài đặt nó trước:

https://raw.githubusercontent.com/Homebrew/install/master/install.sh

Mở Termial và chạy lệnh sau để cài đặt RabbitMQ: brew install rabbitmq

Thêm rabbitmq vào biến môi trường, chạy lệnh:

export PATH=$PATH:/usr/local/opt/rabbitmq/sbin

Chạy lệnh rabbitmq-server để start RabbitMQ Server.

Sau khi khởi động RabbitMQ, chúng ta có thể theo dõi và quản lý RabbitMQ từ giao diện web ở cổng 15672. Các bạn có thể truy cập vào trang này bằng URL sau: http://localhost:15672/ với username và password là guest/guest.

Trường hợp không thể truy cập Management UI cho RabbitMQ, bạn thực hiện lệnh sau:

rabbitmq-plugins enable rabbitmq_management

Sau khi login sẽ thấy kết quả như sau:

Cài đặt RabbitMQ trên Window

Các bạn tham khảo liên kết bên dưới:

Cài đặt RabbitMQ Server sử dụng Docker

Hãy chắc chắn rằng Docker đã được cài đặt trên máy của bạn:

$ docker -v Docker version 19.03.5, build 633a0ea $ docker-compose -v docker-compose version 1.25.4, build 8d51620a

Bạn có thể sử dụng docker command sau để Start RabbitMQ Server trên docker:

docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management

Hay theo hướng dẫn trên DockerHub.

Trong bài này tôi sẽ hướng dẫn sử dụng docker compose vì nó dễ hiểu và dễ cấu hình hơn. Tạo file docker-compose.yaml với nội dung như sau:

version: "3.7" # https://docs.docker.com/compose/compose-file/ services:   rabbitmq:     image: 'rabbitmq:3.6-management-alpine'     ports:       # The standard AMQP protocol port       - '5672:5672'       # HTTP management UI       - '15672:15672'     environment:       # The location of the RabbitMQ server.  "amqp" is the protocol;       # "rabbitmq" is the hostname.  Note that there is not a guarantee       # that the server will start first!  Telling the pika client library       # to try multiple times gets around this ordering issue.       AMQP_URL: 'amqp://rabbitmq?connection_attempts=5&retry_delay=5'       RABBITMQ_DEFAULT_USER: "guest"       RABBITMQ_DEFAULT_PASS: "guest"     networks:       - network networks:   # Declare our private network.  We must declare one for the magic   # Docker DNS to work, but otherwise its default settings are fine.   network: {}

Chạy lệnh docker-compose up để chạy RabbitMQ trên docker. Bạn sẽ thấy một vài thông tin tương tự như sau:

ptgiang@Phans-MacBook-Pro workspace % docker-compose up WARNING: The Docker Engine you're using is running in swarm mode. Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node. To deploy your application across the swarm, use `docker stack deploy`. Creating network "workspace_network" with the default driver Pulling rabbitmq (rabbitmq:3.6-management-alpine)... 3.6-management-alpine: Pulling from library/rabbitmq cd784148e348: Pull complete 6942394937c2: Pull complete 9b810cb4438e: Pull complete 05c43906cd73: Pull complete fedf5b1b1c33: Pull complete fde114ead4a3: Pull complete 046b8cc56402: Pull complete e2b994cef718: Pull complete d156eba9441a: Pull complete 2cd20e13ffc0: Pull complete 4c5a843376d8: Pull complete Digest: sha256:483745c7faebb33214e0b2630d99c23c725434dd7c388339fc4083217bd004fb Status: Downloaded newer image for rabbitmq:3.6-management-alpine Creating workspace_rabbitmq_1 ... done Attaching to workspace_rabbitmq_1 rabbitmq_1  |  rabbitmq_1  |               RabbitMQ 3.6.16. Copyright (C) 2007-2018 Pivotal Software, Inc. rabbitmq_1  |   ##  ##      Licensed under the MPL.  See http://www.rabbitmq.com/ rabbitmq_1  |   ##  ## rabbitmq_1  |   ##########  Logs: tty rabbitmq_1  |   ######  ##        tty rabbitmq_1  |   ########## rabbitmq_1  |               Starting broker... rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:12 === rabbitmq_1  | Starting RabbitMQ 3.6.16 on Erlang 20.3.4 rabbitmq_1  | Copyright (C) 2007-2018 Pivotal Software, Inc. rabbitmq_1  | Licensed under the MPL.  See http://www.rabbitmq.com/ rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:12 === rabbitmq_1  | node           : rabbit@d1e976e92e15 rabbitmq_1  | home dir       : /var/lib/rabbitmq rabbitmq_1  | config file(s) : /etc/rabbitmq/rabbitmq.config rabbitmq_1  | cookie hash    : Qm0QQJJKqEXRR/3nQigarw== rabbitmq_1  | log            : tty rabbitmq_1  | sasl log       : tty rabbitmq_1  | database dir   : /var/lib/rabbitmq/mnesia/rabbit@d1e976e92e15 rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  | Memory high watermark set to 795 MiB (834314240 bytes) of 1989 MiB (2085785600 bytes) total rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  | Enabling free disk space monitoring rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  | Disk free limit set to 50MB rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  | Limiting to approx 1048476 file handles (943626 sockets) rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  | FHC read buffering:  OFF rabbitmq_1  | FHC write buffering: ON rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  | Database directory at /var/lib/rabbitmq/mnesia/rabbit@d1e976e92e15 is empty. Initialising from scratch... rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:15 === rabbitmq_1  |     application: mnesia rabbitmq_1  |     exited: stopped rabbitmq_1  |     type: temporary rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Waiting for Mnesia tables for 30000 ms, 9 retries left rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Waiting for Mnesia tables for 30000 ms, 9 retries left rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Waiting for Mnesia tables for 30000 ms, 9 retries left rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Priority queues enabled, real BQ is rabbit_variable_queue rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Starting rabbit_node_monitor rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Management plugin: using rates mode 'basic' rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | msg_store_transient: using rabbit_msg_store_ets_index to provide index rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | msg_store_persistent: using rabbit_msg_store_ets_index to provide index rabbitmq_1  |  rabbitmq_1  | =WARNING REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | msg_store_persistent: rebuilding indices from scratch rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Adding vhost '/' rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Creating user 'guest' rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Setting user tags for user 'guest' to [administrator] rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Setting permissions for 'guest' in '/' to '.*', '.*', '.*' rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | started TCP Listener on [::]:5672 rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Management plugin started. Port: 15672 rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Statistics database started. rabbitmq_1  |  completed with 6 plugins. rabbitmq_1  |  rabbitmq_1  | =INFO REPORT==== 5-Apr-2020::17:01:16 === rabbitmq_1  | Server startup complete; 6 plugins started. rabbitmq_1  |  * rabbitmq_management rabbitmq_1  |  * rabbitmq_web_dispatch rabbitmq_1  |  * cowboy rabbitmq_1  |  * rabbitmq_management_agent rabbitmq_1  |  * amqp_client rabbitmq_1  |  * cowlib

Chúng ta có thể theo dõi và quản lý RabbitMQ từ giao diện web ở cổng 15672, và sử dụng port 5672 để nhắn tin thông qua giao thức AMQP.

Các bạn có thể truy cập vào trang này bằng URL sau: http://localhost:15672/ với username và password là guest/guest như đã cấu hình trong file docker-compose.yaml.

Nếu bạn có thể thấy giao diện login và admin như cài đặt thông qua Package Manager nghĩa là chúng ta đã cài đặt thành công.

Tài liệu tham khảo:

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

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

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

Cùng tìm hiểu về Stream trong Java 8

stream
Cùng tìm hiểu về Stream trong Java 8

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

Quay trở lại với chuỗi bài Java Stream, hôm nay do đang không có task nên mình tranh thủ viết bài (kẻo nhàn cư vi bất thiện ).

Lúc đầu thì tính là không viết dài, nhưng vì giật tít bài viết ghê quá, nên mình sẽ cố gắng viết hết tất cả, từ khái quát, bản chất cho tới hiệu năng, ….

Tuy hơi dài nhưng chắc là cũng đáng để đọc, mục tiêu của mình khi viết bài này là mong rằng chỉ đọc only bài này, các bạn đã thật sự hiểu sâu, nắm chắc về mặt bản chất của Stream, qua đó từ từ trở thành Senior Java Developer.

Viết có hay ho gì không mà PR ghê thế?. Bố đọc mà không hiểu lại close mẹ tab bây giờ! 

Úi, đừng close tab mà tội nghiệp em nó, vào bài ngay đây.

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

1. Stream là gì?

1.1 Một câu chuyện nhỏ và định nghĩa.

Chuyện rằng ngày nảy ngày nay, ở phường 3, quận Tân Bình có thằng Tèo, nhà giàu tổ bố, nhà cực nhiều xe, nó có một List 10 chiếc xe với thông tin ngày bảo hành gần nhất.

Đến hạn bảo dưỡng, vì đ*o lành nghề IT nên Tèo nhờ Tồ (kỹ sư công nghệ thông tắc hệ thống thoát nước) kiểm tra xem xe nào đến hạn bảo hành.

Với số lượng 10 chiếc, Tồ nhanh trí sử dụng Iterator next() kiểm tra trên từng chiếc xe, mọi việc đơn giản, Tồ lụm 2 củ.


Qua hôm sau, thằng  kế bên kêu thằng Tồ tới làm vố này to, Tồ nhanh chân đề máy tới nhà Tí, vừa mới xem cái List thằng Tí đưa ra, nó loạng quạng, chân đứng không vững (10.000.000 xe). Hóa ra, bố thằng Tí làm chủ bãi xe phế liệu, bố nó không bảo trì mà muốn kiếm xe chưa hết hạn lưu thông.


Máy yếu, sử dụng Iterator next() thì chắc là không ổn. Đang ngồi suy nghĩ miên man, sực một giọng nói vang lên phía sau lưng Tồ, “lẹ đi mày, tao còn có việc đi nữa”.

Bí quá, làm sao nhanh được?, Tồ tự hỏi. Bỗng nhiên sực nhớ KieBlog có bài về sờ trim, Tồ nhanh trí đọc bài, bật máy lên dùng ngay Parallel Stream. Vụt, kết quả xuất hiện rồi sao?, sao nhanh vậy được?, Tồ tự hỏi.

Kết quả có thật, nhưng xui vl, không còn chiếc nào còn hạn bảo hành, Tí đưa Tồ 20k rồi nói “CÚTTTTTT”

Tồ thật không may, tuy nhiên tồ cũng đã hiểu và biết cách sử dụng sờ trim, tối đó Tồ ngủ ngon lắm. HÃY NHƯ TỒ.

Vậy stream là gì?. Định nghĩa đơn giản như sau:

Stream represents a sequence of objects from a source, which supports aggregate operations.

Stream là đại diện cho mỗi chuỗi các đối tượng từ một nguồn, hỗ trợ các hoạt động tổng hợp.

“Nguồn” ở đây là danh sách xe của Tèo và Tí. còn các “hoạt động tổng hợp” ở đây là phương thức filter (hôm này – ngày bảo hành gần nhất > 10) giúp tìm ra các xe hết hạn lưu thông.

>>> Xem thêm: Tìm hiểu về đối tượng String trong Java

1.2 Các đặc điểm của stream.

  • Source: dữ liệu nguồn có thể là từ Array, List, I/O
  • Tự động lặp lại phương thức đối với các phần tử có được từ collection.
  • Hỗ trợ các phương thức như filter, map, limit, reduce, find, match, …

1.3 Có gì hơn collection?

1. No Storage – không lưu trữ

A stream is not a data structure that stores elements; instead, it conveys elements from a source such as a data structure, an array, a generator function, or an I/O channel, through a pipeline of computational operations.

Stream không phải là cấu trúc dữ liệu lưu trữ các phần tử, thay vào đó, nó truyền tải các phần tử này thành các kiểu dữ liệu khác như mảng, hàm hoặc kênh I/O, thông qua một hệ thống luồng tính toán.

Giải nghĩa: Collection là một cấu trúc dữ liệu (có thể là ArrayList, LinekedList), còn stream thì chỉ như là công cụ xử lí. Nếu ta có danh sách 10 tên tội phạm thì collection sẽ trực tiếp lưu các phần tử vào ArrayList, còn stream chỉ giúp ta filter() những tên tội phạm ma túy, sort() theo thứ tự ngày phạm tội, …

Stream không trực tiếp lưu trữ những phần tử này, nó luôn cần source (dữ liệu đầu vào) để xử lí.

2. Functional in nature.

An operation on a stream produces a result, but does not modify its source.

Stream luôn cho ra kết quả, nhưng không sửa đổi đầu vào.

Giải nghĩa:

Giả sử ta có một colection 10 pornstar name, vì thích hàng còn mới nên ta sử dụng stream để lọc bớt các cô có số lượng phim đóng lớn hơn 5, kết quả stream cho ra 3 cô. Mặc dù kết quả stream là 3, nhưng nó không tác động tới dữ liệu collection, dữ liệu ở trong collection vẫn bất biến là 10. Đây chính là ý muốn nói của functional in nature.

Kể sơ thì 10 cái tên này gồm: R*** takizawa, S*** aoi …. Ẹc, đang nói về stream, lạc cmn đề.

  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java
  10 tips để trở thành Java Developer xịn hơn

3. Lazy seeking – hoạt động trung gian luôn lười biếng

Many streams operations, such as filtering, mapping, or duplicate removal, can be implemented lazily, exposing opportunities for optimization.

Nhiều hoạt động trên streams, chẳng hạn như filtering, mapping hoặc loại bỏ trùng lặp, có thể được triển khai một cách lười biếng, cho thấy cơ hội tối ưu hóa.

Giải nghĩa:

Streams are lazy because intermediate operations are not evaluated unless terminal operation is invoked.

Streams là lười biếng vì các hoạt động trung gian không được xác định cho tới khi hoạt động cuối được gọi.

stream lazy evaluation

Ví dụ:

Sở dĩ ta dùng từ lười biếng vì stream filter lọc ra xe sang chỉ tuần tự gọi ra khi terminal operation (collect()) được gọi. Nếu terminal chưa gọi, các bước như filter chỉ là những bước riêng lẻ, thực hiện trên từng thể hiện của stream.

Nếu vẫn chưa hiểu, các bạn đọc tiếp tới mục 4, tham khảo thêm câu hỏi này.

4. Possibly unbounded – có thể không giới hạn.

While collections have a finite size, streams need not. Short-circuiting operations such as limit(n) or findFirst() can allow computations on infinite streams to complete in finite time.

Collections thì có giới hạn, nhưng stream thì không. Các hoạt động xoay vòng như limit(n) hoặc findFirst() có thể tính toán trên luồng vô hạn trong thời gian hữu hạn.

5. Consumable – Bị hủy sau một lần sử dụng.

The elements of a stream are only visited once during the life of a stream. Like an Iterator, a new stream must be generated to revisit the same elements of the source.

Các elements của stream chỉ được ghé qua một lần duy nhất. Giống như Iterator, một stream mới sẽ cần khởi tạo lại để truy cập lại elemets đó.

2. Khởi tạo stream như thế nào?

Một số cách để khởi tạo một đối tượng stream:

  1. Khởi tạo từ một Collections với số lượng phần tử giới hạn (thông qua stream() và parallelStream()).
  2. Thông qua Array, phương thức Arrays.stream(Object[]);
  3. Thông qua Factory Init như, Stream.of(Object[]), IntStream.range(int, int) or Stream.iterate(Object, UnaryOperator);
  4. Bằng BufferedReader.lines();
  5. Qua Files.
  6. Bằng cách sử dụng phương thức Random.ints();, khởi tạo dãy số ngẫu nhiên.

2.1 Chuyển từ collections sang stream như thế nào?

Ở Java 8, phương thức stream() đã được thêm sẵn vào interface của collection, vì vậy rất dễ dàng để chuyển đổi từ collection sang stream.

Có 2 phương thức chuyển đổi là:

  • stream() : trả về một luồng tuần tự với source là collection.
  • parallelStream() : trả về một luồng song song với source là collection.

Collection sẽ có thêm 2 phương thức này trong interface.

Hình dưới: stream và parallel stream chạy trên 4 cores, thời gian khi sử dụng parallel là ít hơn hẳn.

Nguồn ảnh/ Source: logicbig.com

Tuy nhiên, có một điểm lưu ý để không nhầm lẫn trong việc chuyển đổi này là:

When a collection is transformed into a stream, the original collection is not modified in any ways. Only the memory addresses of each item is acquired, the object is cloned and streamed into the stream one by one.

Được hiểu rằng:

Khi một collections được chuyển thành stream, collections gốc thực sự không thay đổi. Chỉ có địa chỉ nhớ của từng đối tượng được lấy ra, các đối tượng được sao chép, và đưa vào streams từng phần tử một.

3. Một số phương thức chính.

3.1 Intermediate operation (phương thức trung gian).

Stream có 5 phương thức trung gian chính là: filter()map()limit()sorted()distinct()

3.2 Terminal operations (phương thức đầu cuối).

Có 3 phương thức trung gian là: forEach()count() và collect()

Nguồn ảnh/ Source: oracle.com

Tại sao lại có 2 nhóm phương thức này?, có phải sẽ thực hiện hết tất cả các phương thức trung gian rồi mới thực hiện phương thức cuối hay không?. Chi tiết sẽ được giải thích ở mục 4.

>>> Xem thêm: Các phần mềm giả lập Java dành cho máy tính tốt nhất

4. Bản chất stream có gì?

Vì hoạt động theo phương thức pipelined (ống). Stream trong Java chia thành 3 công việc (operations) chính, cũng có thể nói rằng 3 thành phần (components) này giúp stream hoạt động. Ngoài ra, thứ tự thực hiện trong stream cũng cụ thể, rõ ràng và theo tuần tự (sequence).

Ở mỗi (operations) sẽ có một công việc nhất định phải làm, sau khi đã xong ở công đoạn này, sẽ tiếp tục tới công đoạn khác cho tới khi hoàn tất.

4.1 Ba thành phần của stream.

Bất kì công việc nào có liên quan với Java API Stream đều phải có ba thành phần sau:

  • Source (thành phần nguồn – có thể linh động)
  • Intermediate operation (thành phần trung gian – có thể có 1 hoặc nhiều)
  • Terminal operation (thành phần cuối – thường chỉ có một mà thôi)

Ba thành phần này sắp xếp với nhau theo thứ tự để tạo thành một luồng stream.

Nguồn ảnh/ Source: JavaBrahman.com

Với các thành phần như vậy, ta sẽ đi sâu tìm hiểu xem chức năng của từng thành phần như thế nào, thứ tự thực hiện ra sao ở mục kế sau đây.

4.2 Chức năng của từng thành phần là gì?

  1. Source: được hiểu là dữ liệu đầu vào: có thể là một mảng (array), một danh sách (list) hoặc một stream được tạo ra bằng phương thức generate() , đầu vào ở đây có thể linh động theo yêu cầu cụ thể.
  2. Intermediate operation là một hoạt động trung gian, hoạt động này gọi trên từng items của Stream. Như đã nêu ở mục số 3, stream có 5 phương thức trung gian là: Stream.map(), Stream.filter() , Stream.limit(). Sở dĩ gọi là trung gian vì sau bước này, ta chưa thể có stream output, các phương thức này chỉ là phương thức hỗ trợ xử lí để có output. Ví dụ như 2 method filter() và sorted() chỉ giúp lọc và sắp xếp chuỗi stream đầu vào, nếu không có bước cuối cùng (terminal), ta chưa thể có một stream hoàn chỉnh.
  3. Terminal operation, là hoạt động cuối cùng của đường ống (pipelined). Sở dĩ gọi nó là terminal vì sau khi thực hiện, ta không thể sử dụng lại stream. Bước cuối cùng này có trách nhiệm trả về ‘output’. Bước cuối cùng này có thể trả về từng đối tượng (forEach())độ dài stream (count()) hoặc một collections (collect()).

Một khi đã thực hiện tới bước cuối cùng (terminal), không thể quay trở lại thực hiện một hoạt động trung gian nào khác.

Tiện đây trích luôn câu nói nổi tiếng của thanh niên Heraclitus:

You never step into the same river twice.

Bạn không thể tắm tiên hai lần trên một dòng sông .


Tới giờ mình vẫn chưa hiểu được ý nghĩa thâm sâu của câu nói này. Mình nghĩ có 3 khả năng:

  • Thứ nhất: Có thể là cha này viết cho tương lai (hiện tại ô nhiễm môi trường bây giờ – tắm lần 1 là ghẻ đầy người vào da liễu).
  • Thứ hai: Cũng có khi là lời dặn dò cho các chị em thích tắm tiên (lần thứ 2 có thể bị hiếp).
  • Cuối cùng: Cha này lần đầu tiên tắm sông bị đuối nước tưởng đâu chết, may nhờ có người cứu, từ đó ai rủ đi tắm sông cũng không dám nữa. Để che mắt thiên hạ thì viết ra câu này.

Thôi chết, lại lạc cmn đề . Quay trở lại, sau đây sẽ là ví dụ minh họa dễ hiểu về stream.

4.3 Ví dụ minh họa.

Lý thuyết là vậy, đọc buồn ngủ quá, vì vậy, để có cái nhìn khách quan và thực tiễn, ta sẽ thử xem xét ví dụ:

Hình dung Stream như một dây chuyền lắp ráp ô tô, với đầu vào là 10 khung xe, nếu ta viết Stream:

// Danh sách xe
List < String > danhsachXe = Arrays.asList("Lamborghini reventon",
    "Toyota mazda cx 5",
    "Roll royce phantom drophead coupe",
    "Hyundai grand i 10",
    "SLR McLaren Mansory Renovatio");

// Convert list to stream
List < String > xeSang = danhsachXe.stream()
    // Chỉ lấy siêu xe
    .filter(xe - > isXeSang(xe))
    // Lấy 2 xe
    .limit(2)
    // Convert streams to a List
    .collect(Collectors.toList());
// Lamborghini reventon, Roll royce phantom drophead coupe
xeSang.forEach(System.out::println); 

Intermediate operation có 2 bước:

  • Bước 1: Lọc ra các xe là xe sang, thông qua Stream.filter() và function isXeSang, hàm này có thể kiểm tra giá tiền > 3 tỷ chẳng hạn.
  • Bước 2: Giới hạn số xe lấy ra là 2. Terminal operation trường hợp này lại trả về từng đối tượng (item) trong Stream (Stream.forEach()), in ra danh sách 2 xe (Lamborghini reventon và Roll royce phantom drophead coupe).

5. Parallel stream là gì?. Nghe đồn xử lí đa luồng ghê lắm!

5.1 Parallel stream là gì?

Mình sẽ trích dẫn một đoạn nhỏ từ cuốn Java 8 in Action

A parallel stream is a stream that splits its elements into multiple chunks, processing each chunk with a different thread.

Parallel stream là stream chia các phần tử của nó vào các chunks (solid piece of something), xử lí từng chunk với các thread khác nhau.

Giải nghĩa:

Lấy ví dụ khi thực hiện phép cộng: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8. Khi sử dụng parrallel stream sẽ chia thành 2 chunks, mỗi chunk sẽ chạy trên một thread riêng biệt. Thứ tự thực hiện như sau:

Nguồn ảnh/ Source: Java 8 in Action – page 205

5.2 Có gì hơn sequential stream và iterator?

Java 8 So sánh tốc độ Parallel Stream và Sequential StreamSo sánh tốc độ Parallel và Sequential

Cùng xem hình sau:

Bảng thời gian xử lí, so sánh giữa Parralel Stream, Sequential Stream, Iterator

Đầu tiên, khi xử lí dữ liệu không quá lớn (<15000 elements), sự khác biệt giữa Iterator, Sequential Stream và Parallel Stream là quá ít (chỉ chừng 0.1s), quá nhanh để có thể cảm nhận. Tuy nhiên, khi dữ liệu (>40000 elements), sự khác biệt về thời gian xử lí có thể thấy rõ (chênh nhau 0.5s).

Vì vậy, khi xử lí với dữ liệu lớn, sử dụng Parallel Stream sẽ tăng hiệu năng đáng kể.

6. Một số câu hỏi mở

  • Có thật sự có khác biệt về peformance giữa Sequential Stream và Iterator hay không?
  • Luôn dùng Parallel Stream có phải là phương án tốt?
  • Tại sao Stream lại là lazy, không lazy thì ảnh hường gì?
  • Nếu xử lí đã luồng ở Parallel Stream có hiệu năng tốt, có thể ứng dụng nó vào đâu? – có thể là dùng khi JDBC query dữ liệu.

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

JMeter: Sử dụng Regular Expression với Sessions ID và Tokens – P3

jmeter
Sử dụng Regular Expressions làm việc với Session IDs và Tokens

Bài viết được sự cho phép của BQT Kinh nghiệm lập trình

Chào mọi người, cùng quay lại chuỗi bài viết về cách sử dụng Jmeter nào.
Ở bài viết trước, mình đã giới thiệu tới các bạn các bước chi tiết để thiết kế và thực thi 1 kịch bản test hiệu quả. Các bạn có thể xem lại ở Đây.

  Công cụ performance test Jmeter
  Hướng dẫn sử dụng JMeter test hiệu năng website - Phần 1

Mình xin nhắc lại chuỗi bài viết của mình gồm 4 phần sau:
Phần 1: Giới thiệu và cài đặt
Phần 2: Hướng dẫn xây dựng kịch bản test
Phần 3: Sử dụng Regular Expressions làm việc với Session IDs và Tokens
Phần 4: Mở rộng – Tạo lập Scripts tự động bằng HTTP(S) Test Script Recorder.
Trong bài viết này, chúng ta sẽ đi tìm hiểu cách để sử dụng Tokens và Session IDs cho các request trong kịch bản test hoạt động.

Tại sao lại là Session IDs và Tokens?

Trong 1 số hệ thống phần mềm, ngoài các params mà ta có thể tự định nghĩa trước và đưa vào request từ file *.csv, 1 số request khi thực hiện yêu cầu đòi hỏi thêm tham số Session ID của phiên đăng nhập đó. Tất nhiên ID này thì ta không thể tự định nghĩa trước được và cho dù bằng cách nào đó, bạn tạo ra được chuỗi này, thì nó cũng không còn tính khách quan của việc giả lập 1 người sử dụng bình thường nữa.
Chính vì thế, Jmeter cung cấp phương tiện để ta ghi nhận lại các thông số Session ID và Tokens của từng phiên đăng nhập như 1 biến, để ta sử dụng cho các request trong kịch bản test.

Lấy Token bằng Regular Expression Extractor

Làm theo hướng dẫn như hình bên dưới để tạo 1 Regular Expression Extractor:

Và cài đặt như sau:

Cài đặt tham số như sau:

Selecting the options:
Field to check: Response Header, bởi vì mình sẽ lấy dữ liệu từ Response Header của request trước đó.
Name of created variable: XSRF-TOKEN (Bạn có thể đặt tên tùy ý, phụ thuộc vào logic phần mềm bạn đang test, quan sát ở header trong developer tool – F12).
Regular Expression: Set-Cookie: XSRF-TOKEN=(.*?);
Template: $1$ để biết nhóm biểu thức sẽ lưu, ở đây ta chỉ có 1 nhóm.
Match No: 1. Số lượng dữ liệu biến mình sẽ lưu, ở đây ta lưu duy nhất 1 giá trị.
Default Value: NOT FOUND. Bạn có thể nhập giá trị khác, ở đây mình chọn thông báo Not found cho dễ nhận dạng.

Như vậy, bạn có thể sử dụng giá trị này trong các requests của mình (bodies and headers). Bạn chỉ cần gọi biến bình thường trong Jmeter, bằng cách ${XSRF-TOKEN}.

Extracting Session ID

Chúng ta vừa cài đặt và lấy giá trị token ra sử dụng như 1 biến, tiếp theo sẽ là Session ID. Hoàn toàn tương tự như Tokens. Theo dõi các bước dưới đây nhé.

Tiếp tục thêm 1 Regular Expression Extractor và config như sau:

Sau khi hoàn tất, bạn đã có thể sử dụng giá trị này bằng cách gọi biến bình thường trong Jmeter: ${ci_session}.

Trên đây là hướng dẫn cơ bản để thao tác và sử dụng Regular Expression Extractor trong Jmeter để lấy Session ID và Token cho phiên làm việc của user. Bên cạnh đó, các bạn cũng có thể tìm hiểu thêm về các Extractor khác mà Jmeter cung cấp sẵn trong Post Processors: CSS Selector Extractor, JSON Extractor…

Các bạn có thắc mắc gì, vui lòng để lại bình luận, mình cùng trao đổi giúp đỡ nhau nhé. Phần tiếp theo mình sẽ hướng dẫn các bạn tạo 1 kịch bản test 1 cách tự động bằng Jmeter.

Tham khảo:
https://www.blazemeter.com/blog/using-regular-expressions-to-extract-tokens-and-session-ids-to-variables

https://jmeter.apache.org/usermanual/component_reference.html#Regular_Expression_Extractor

kinhnghiemlaptrinh.com

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

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

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

6 cách mở Services Management Console trên Windows 10

Services Management Console
6 cách mở Services Management Console trên Windows 10

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

Services hay còn gọi là các dịch vụ có trên hệ điều hành Windows là một trong những thành phần thiết yếu và cốt lõi của hệ thống, chúng hoạt động một cách thường xuyên và liên tục (tức là luôn chạy ngầm, hoặc tự động kích hoạt khi cần thiết).

Các dịch vụ này thực chất cũng là một ứng dụng, nhưng vì không có giao diện người dùng (User-Interface – UI) nên chúng ta phải nhờ đến một công cụ khác để quản lý các hoạt động của chúng. Vâng, và đó chính là Services Management Console.

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

Tuy nó đóng một vai trò quan trọng như vậy nhưng mình biết, vẫn có rất nhiều bạn không biết cách mở và sử dụng Services Management Console như thế nào.

Vậy nên trong bài viết này mình sẽ tổng hợp lại những cách đơn giản nhất để mở công cụ Services Managment Console trên Windows 10 nhé !

  5 điều cần nhớ khi làm việc với service worker
  6 ví dụ để bạn yêu luôn observable

I. Cách mở Services Management Console trên Windows 10

Nói sơ qua về chức năng chính của Services Management Console, nó cho phép bạn xem, bật, tắt và cài đặt chế độ của hầu hết các dịch vụ có trên hệ điều hành Windows 10.

Trong đó có một số là dịch vụ của hệ thống nên bạn không thể can thiệp vào được và cũng chẳng có lí do gì để can thiệp vào chúng cả, vì nó là một phần của hệ thống mà.

Oke, bên dưới đây là tổng hợp những cách mở Services Management Console đơn giản nhất mà mình biết:

#1. Sử dụng Windows Run để mở Services Management Console

Windows Run là một công cụ rất đắc lực có trên hệ điều hành Windows, mà mình tin chắc là nó đã quá quen thuộc với nhiều bạn ở đây rồi.

Nhất là với những bạn thường xuyên theo dõi những bài hướng dẫn có trên blogchiasekienthuc [dot] com. Và tất nhiên, với Windows Run thì bạn có thể làm rất nhiều thứ.

Mình tin là bạn sẽ thích bài viết này đấy: Cách mở hộp thoại RUN và 90+ lệnh thường dùng trên Windows

Và trong bài viết này, không có lý do gì mà chúng ta không sử dụng Windows Run để mở Services Management Console cả 🙂

Thực hiện:

Bạn mở Windows Run lên bằng cách sử dụng tổ hợp phím Windows + R => rồi nhập vào lệnh services.msc hoặc dán lệnh %windir%\system32\services.msc => và bấm OK là có thể mở được Services Management Console.

cach-mo-services-management-console-tren-windows-10 (11)

Bạn cũng có thể chạy những lệnh trên bình thường trong Windows PowerShell và Command Prompt (CMD) của hệ điều hành Windows nhé !

#2. Sử dụng Windows Search để mở Services Management Console

Windows Search trên hệ điều hành Windows 10 được Microsoft trang bị rất nhiều tính năng mạnh mẽ, độc đáo và rất hữu ích nữa, với nó bạn có thể tìm mọi thứ như: ứng dụng, file, cài đặt… trên Windows 10. Đặc biệt là tốc độ tìm kiếm rất nhanh.

Và tất nhiên là không ngoại trừ cả cái mà chúng ta đang cần: Services Manangement Console

Bạn hãy sử dụng tổ hợp phím Windows + S hoặc là Windows + Q để mở Windows Search =>  sau đó nhập vào từ khóa services hoặc services.msc => cuối cùng chọn Services (App) trong danh sách kết quả tìm kiếm.

Nhớ nhé, cái gì không thấy thì cứ Windows Search mà tìm nha các bạn 🙂

cach-mo-services-management-console-tren-windows-10 (1)

#3. Sử dụng Task Manager để mở Services Management Console

Task Manager là công cụ quen thuộc giúp bạn quản lý các tiến trình, chương trình đang hoạt động trên hệ thống Windows, và tất nhiên là cũng quản lý được cả các dịch vụ nữa.

Bạn hãy mở Task Manager lên bằng cách sử dụng tổ hợp phím Ctrl + Shift + Esc, hoặc là click chuột phải lên thanh Taskbar của Windows => và chọn Task Manager là được.

cach-mo-services-management-console-tren-windows-10 (2)

Tại Task Manager bạn hãy chuyển qua tab Processes, sau đó bạn hãy click vào dấu mũi tên sổ xuống bên cạnh một Services Host bất kỳ => sau đó click chuột phải lên một trong các dịch vụ trong đó =>và chọn Open Services là xong.

Xong đừng vội đóng Task Manager đi nhé, còn cách khác nữa ở bên dưới.

cach-mo-services-management-console-tren-windows-10 (3)

____ᵔᴥᵔ____

Ngoài ra còn có một cách khác nữa đơn giản hơn thế nhiều, nếu bạn thấy cách trên hơi phức tạp thì nên dùng cách này nhé !

Cũng trong Task Mananger này luôn, bạn hãy chuyển sang tab Services, đây là nơi bạn có thể xem toàn bộ tên, mô tả cũng như trang thái của từng dịch vụ có trên hệ thống.

Và ở ngay góc dưới màn hình, cạnh chữ Fewer Details thì ta có thể thấy ngay dòng Open Services, bấm vào đó để mở nhanh công cụ Services Management Console.

cach-mo-services-management-console-tren-windows-10 (4)

#4. Sử dụng Menu Start trên Windows 10

Tất cả những ứng dụng có sẵn và những phần mềm bạn cài từ bên ngoài vào thì chúng đều được Windows gom vào trong Menu Start để bạn dễ truy cập và tìm kiếm, tuy nhiên lại không nhiều người để ý điều đó.

Và tất nhiên là công cụ Services Management Console cũng không phải ngoại lệ, bạn hãy bấm vào nút Start trên bàn phím hoặc trên thanh Taskbar của Windows => kéo xuống đến ký tự W => và click vào thư mục Windows Administrative Tools.

=> Sau đó bạn nhìn xuống dưới tí nữa bạn sẽ thấy ngay Services, bây giờ thì bạn biết phải làm gì rồi đấy 🙂

cach-mo-services-management-console-tren-windows-10 (5)

#5. Sử dụng lối tắt (shortcut) trong Control Panel

Control Panel trên Windows 10 chứa rất nhiều cài đặt mà chúng ta thường xuyên sử dụng đến. Bản thân mình cũng rất hay sử dụng công cụ này.

Bạn cũng có thể truy cập được Services từ đây bằng cách thêm lối tắt của nó vào Control Panel theo hướng dẫn trong bài viết cùng tên của mình.

cach-mo-services-management-console-tren-windows-10 (6)

#6. Tạo shortcut để mở nhanh Services Management Console

Màn hình Desktop, thanh Taskbar cho phép chúng ta đặt các lối tắt, biểu tượng của các ứng dụng thường xuyên sử dụng để việc truy cập được dễ dàng, nhanh chóng và tiết kiệm thời gian nhất !

Để tạo shortcut cho Services Management Console, bạn click chuột phải lên màn hình desktop hoặc bất cứ nơi nào mà bạn muốn tạo lối tắt cho nó => chọn New => chọn Shortcut.

cach-mo-services-management-console-tren-windows-10 (7)

Trong cửa sổ Create Shortcut, ô Type the location of the item bạn sao chép và dán dòng lệnh bên dưới vào => rồi bấm Next để tiếp tục.

%windir%\system32\services.msc

cach-mo-services-management-console-tren-windows-10 (8)

Cuối cùng là nhập tên của lối tắt này vào ô Type the name for this shortcut, tên thì bạn đặt cái gì cũng được – miễn sao dễ nhớ dễ nhìn là được => xong bấm Finish để hoàn thành quá trình tạo lối tắt.

cach-mo-services-management-console-tren-windows-10 (9)

Bây giờ bạn đã có một lối tắt của Services ở ngoài màn hình Desktop rồi đấy, double-click lên lối tắt đó là mở được ngay rồi.

Ngoài bạn, bạn có thể kéo nó vào thanh Taskbar để sử dụng cho tiện, sau đó có thể xóa luôn lối tắt ở màn hình Desktop cho gọn, cái này tùy bạn nhé..

cach-mo-services-management-console-tren-windows-10 (10)

II. Lời kết

Vâng, trên đây là 6 cách đơn giản nhất để mở công cụ Services Management Console trên Windows 10. Bạn cũng có thể áp dụng những cách này với hầu hết các phiên bản hệ điều hành Windows khác nữa..

Đây chỉ là những cách mà mình sưu tầm được và biết đến, vậy nên có thể sẽ còn thiếu, nếu bạn biết thêm cách nào khác thì đừng ngại để lại bình luận ở dưới để chia sẻ cho mọi người nhé 🙂 Chúc các bạn thành công !

CTV: Nguyễn Thanh Tùng – 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

Chu Kỳ Phát Triển Phần Mềm (SDLC)

phát triển phần mềm
Chu Kỳ Phát Triển Phần Mềm (SDLC)

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

Một trong những kiến thức cần thiết của một kỹ sư kiểm thử phần mềm chuyên nghiệp đó là hiểu biết và nắm rõ SDLC (Software Development Life-cycle/chu kỳ phát triển phần mềm), bởi vì kiểm thử phần mềm (software testing) là 1 phần và liên quan chặt chẽ, mật thiết đến SDLC.

  "Vì sao mình chọn start-up sau Facebook?" Hiếu Phạm - Software Engineer tại ROCKSET
  10 Công cụ Go-To Tech dành riêng cho các Software Developer

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

SDLC là một cách tiếp cận có hệ thống và có trật tự để giải quyết các vấn đề liên quan đến hệ thống phần mềm hay nói cách khác, nó là một cấu trúc đối với sự phát triển của một sản phẩm phần mềm. Tuỳ thuộc vào các loại mô hình phát triển phần mềm khác nhau mà các giai đoạn (phase) sau có thể được sắp xếp và tổ chức khác nhau.

Chu kỳ phát triển phần mềm, software development life-cycle (SDLC)

Nguồn: http://en.wikipedia.org/wiki/File:SDLC_-_Software_Development_Life_Cycle.jpg

Domain Analysis: Giai đoạn này rất quan trọng. Mục tiêu của giai đoạn này là khai thác và thu thập các yêu cầu. Các nhà phân tích sẽ đưa ra và thu thập các yêu cầu từ các chuyên gia và các bên liên quan. Bạn càng hiểu rõ các yêu cầu bao nhiêu, công việc của bạn sẽ càng nhẹ nhàng và dễ dàng bấy nhiêu.

Requirement Analysis: Nhiệm vụ quan trọng nhất trong việc tạo ra một sản phẩm phần mềm là phải tách được các yêu cầu. Khách hàng thường biết những gì họ muốn, nhưng đó không phải là những gì phần mềm nên làm nếu các yêu cầu này không đầy đủ, không rõ ràng hoặc mâu thuẫn. Những yêu cầu này cần được công nhận/xác nhận bởi các kỹ sư phần mềm có kỹ năng và kinh nghiệm.

Scope Analysis: Một khi các yêu cầu được thu thập từ khách hàng, phân tích phạm vi của sự phát triển nên được xác định và được ghi rõ. Điều này thường được gọi là một tài liệu phạm vi.

Specification: Đó là nhiệm vụ mô tả chính xác phần mềm sẽ được viết. Trong thực tế, đặc tả thành công nhất được viết để hiểu và tinh chỉnh các ứng dụng đã được phát triển hoàn thiện, mặc dù theo lý thuyết các đặc tả này nên được quy định một cách cẩn thận trước khi phát triển ứng dụng. Đặc tả quan trọng nhất cho các đối tác bên ngoài tổ chức (stakeholder, client, partner) và phải ổn định (ít thay đổi). Một cách tốt để xác định xem các đặc tả có đủ chính xác là phải có một bên thứ ba xem xét các tài liệu và đảm bảo rằng các yêu cầu là hợp lý.

Software Architecture/Design: Kiến trúc liên quan đến việc bảo đảm rằng hệ thống phần mềm sẽ đáp ứng đầy đủ các yêu cầu của sản phẩm, cũng như đảm bảo rằng các yêu cầu trong tương lai có thể được giải quyết. Nó cũng liên quan đến việc giao tiếp giữa các hệ thống phần mềm và các sản phẩm phần mềm khác, cũng như các phần cứng cơ bản hoặc các hệ điều hành chủ.

Coding: Thiết kế phải được dịch sang một dạng máy tính có thể đọc/hiểu được. Giai đoạn viết mã (code) sẽ thực hiện nhiệm vụ này. Nếu thiết kế được thực hiện một cách chi tiết, việc viết mã có thể được thực hiện mà không có nhiều phiền phức, khó khăn. Các công cụ lập trình như trình biên dịch (compilers), phiên dịch (interpreters), gỡ rối (debuggers) vv .. được sử dụng để tạo mã hoá. Các ngôn ngữ lập trình cấp cao khác nhau như C, C + +, Pascal, Java được sử dụng để viết mã. Tuỳ theo từng loại ứng dụng mà ngôn ngữ lập trình phù hợp sẽ được lựa chọn.

Testing: Một khi các mã được tạo ra, thử nghiệm phần mềm bắt đầu. Các phương pháp kiểm thử khác nhau có thể được sử dụng để làm sáng tỏ những lỗi đã được cam kết trong các giai đoạn trước. Các công cụ kiểm thử tự động cũng có thể được sử dụng để tăng hiệu quả của kiểm thử phần mềm. Một số công ty tự xây dựng các công cụ kiểm thử để phục vụ cho các hoạt động phát triển của họ.

Implementation/deployment: Sau khi mã được kiểm tra một cách thích hợp và được chấp thuận, nó sẽ được đưa vào sử dụng trong thực tế.

Documentation: Một nhiệm vụ quan trọng là viết và lưu trữ tài liệu thiết kế nội bộ của phần mềm với mục đích duy trì và tăng cường trong tương lai.

Software Training and Support: Như một phần của giai đoạn triển khai, các lớp đào tạo cho người sử dụng phần mềm là rất quan trọng. Người sử dụng sẽ có rất nhiều câu hỏi và vấn đề phần mềm dẫn đến giai đoạn tiếp theo của phần mềm.

Maintenance: Duy trì/bảo trì và nâng cấp phần mềm để đối phó với các vấn đề mới được phát hiện hoặc yêu cầu mới có thể tốn nhiều thời gian hơn so với việc phát triển ban đầu của phần mềm.

Tham khảo:

http://www.softwaretestingstuff.com

http://en.wikipedia.org/wiki/Systems_development_life-cycle

Bài viết gốc được đăng tải tại vntesters.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ài đặt mail server với Postfix, Dovecot, ViMbAdmin, RoundCube trên Centos 7

mail server
Hướng dẫn cài đặt mail server với Postfix, Dovecot, ViMbAdmin, RoundCube trên Centos 7

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

Lý do bạn áp dụng cài đặt mail server:

  1. Hỗ trợ nhiều domain như lcdung.top, rtcamp.com, google.com, …
  2. Hỗ trợ quản lý nhiều tài khoản mail ảo như admin@lcdung.top, rahul@apple.com, steve@rtcamp.com, … Tài khoản ảo này chỉ login mail server để gửi mail chứ không dùng như tài khoản ftp nhé.
  3. Hỗ trợ quản lý alias  như mail gửi cho you@example.com cũng sẽ forward tới admin@lcdung.top)
  4. Hỗ trợ giao diện web để quản lý tài khoản mail, domain mail, alias và nhiều thứ nửa bới Vimbadmin.
  5. Hỗ trợ giao diện webmail để người dùng có thể đăng nhập gửi mail, nhận mail, đổi password một cách dễ dàng bời Round Cube.
  App User Centricity: Làm sao tăng tỷ lệ duy trì lên 66%?
  Cài đặt ConfigServer Security and Firewall (CSF) và Webmin trên CentOS 7

1. Cài đặt các packed postfix, dovecot, mysql

yum -y install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql mysql-server dovecot-sieve dovecot-managesieved

Nếu mail server của bạn đã cài đặt packed nào thì bạn có thể bỏ qua những packed đó. Lưu ý là server của mình đã cài đặt PHP-FPM và Nginx

2. Cấu hình Postfix

Bạn có thể kiểm tra version của mình bằng command:

postconf mail_version

Version mình đang cài là mail_version = 2.10.1

Cấu hình Postfix tại folder “/etc/postfix/” qua 2 file: main.cfmaster.cf. Và một số file cấu hình virtual

2.1 Cấu hình Postfix master.cf

File: /etc/postfix/master.cf

Nếu bạn sử dụng với SSL thì dùng smtp port 465, với TLS thì dùng smtp port 587. Bạn cần bỏ comment và cấu hình theo các dòng sau:

# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       n       -       -       smtpd
#smtp      inet  n       -       n       -       1       postscreen
#smtpd     pass  -       -       n       -       -       smtpd
#dnsblog   unix  -       -       n       -       0       dnsblog
#tlsproxy  unix  -       -       n       -       0       tlsproxy
submission inet n       -       -       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
#smtps     inet  n       -       -       -       -       smtpd
#  -o syslog_name=postfix/smtps
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING

Lưu ý: Mail server của mình không mã hóa SSL và TLS nên đã comment smtps. Nếu dùng thì bạn bỏ comment nhé

2.2 Cấu hình Postfix main.cf

File: /etc/postfix/main.cf

Bạn có thể xóa hết và cấu hình theo chuẩn của mình:

# Change postfix TLS parameter to use dovecot 
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
#smtpd_tls_cert_file=/etc/ssl/certs/dovecot.pem
#smtpd_tls_key_file=/etc/ssl/private/dovecot.pem
#smtpd_use_tls=yes
#smtpd_tls_auth_only = yes

#Handle SMTP authentication using Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes

smtpd_recipient_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        reject_unauth_destination

# other destination domains should be handled using virtual domains 
mydestination = localhost

# using Dovecot's LMTP for mail delivery and giving it path to store mail
virtual_transport = lmtp:unix:private/dovecot-lmtp

# virtual mailbox setups
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = mysql:/etc/postfix/mysql/virtual_alias_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql/virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf

# DKIM lcdung.top
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

milter_protocol = 2

Lưu ý:

1. Mail server của mình không mã hóa SSL và TLS nên đã comment

#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
#smtpd_tls_cert_file=/etc/ssl/certs/dovecot.pem
#smtpd_tls_key_file=/etc/ssl/private/dovecot.pem
#smtpd_use_tls=yes
#smtpd_tls_auth_only = yes

Nếu mail server bạn có hỗ trợ thì bỏ comment ra và sửa đường dẫn theo đúng folder của bạn.

2. Bạn sẽ thấy dòng

virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

5000 là tên group và user dùng trong dovecot. Khi đến bước cài đặt dovecot bạn sẽ thấy

3. Virtual mailbox để lưu trữ và quản lý nhiều domain, alias, tài khoản mail trong database mysql

virtual_alias_maps = mysql:/etc/postfix/mysql/virtual_alias_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql/virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf

2.3 Cấu hình Postfix Virtual Mailbox

Trước tiên tạo folder để lưu file cấu hình postfix-mysql:

mkdir /etc/postfix/mysql

Virtual Alias Mapping

File: /etc/postfix/mysql/virtual_alias_maps.cf

user = vimbadmin
password = password
hosts = 127.0.0.1
dbname = vimbadmin
query = SELECT goto FROM alias WHERE address = '%s' AND active = '1'

Virtual Domain Mapping

File: /etc/postfix/mysql/virtual_domains_maps.cf

user = vimbadmin
password = password
hosts = 127.0.0.1
dbname = vimbadmin
query = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '0' AND active = '1'

Virtual Mailbox (user) Mapping

File: /etc/postfix/mysql/virtual_mailbox_maps.cf

user = vimbadmin
password = password
hosts = 127.0.0.1
dbname = vimbadmin
query = SELECT maildir FROM mailbox WHERE username = '%s' AND active = '1'

Lưu ý: user và password là tài khoản để quản lý database của Vimbadmin trong Mysql. Bạn nên tạo 1 tài khoản và 1 dabatase rỗng nhé.

Cuối cùng để start Postfix trên Centos 7 dùng command sau:

Systemctl start postfix

Tuy nhiên nếu dùng nhân Linux khác hoặc phiên bản Centos khác thì có lệnh khác tuy nhiên cũng là start postfix

3. Cấu hình Dovecot

Bạn có thể kiểm tra version của mình bằng command:

dovecot --version

Version mình sử dụng là 2.2.10

Tạo user trong linux – vmail

Như ghi chú trong cấu hình Postfix cần tạo tài khoản người sở hữu vùng lưu trữ email

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/vmail -m

Cấu hình Dovecot

Cấu hình Dovecot bạn cần cấu hình một số file sau:

Bật protocols

File: /etc/dovecot/dovecot.conf

# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap pop3 lmtp

Cấu hình nơi lưu trữ khi nhận mail

File: /etc/dovecot/conf.d/10-mail.conf

mail_location = maildir:/var/vmail/%d/%n

Cấu hình chứng thực

File: /etc/dovecot/conf.d/10-auth.conf

#!include auth-deny.conf.ext
#!include auth-master.conf.ext
passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
    driver = static
    args = uid=5000 gid=5000 home=/var/vmail/%d/%n allow_all_users=yes
}
#!include auth-system.conf.ext
#!include dovecot-sql.conf.ext
#!include auth-ldap.conf.ext
#!include auth-passwdfile.conf.ext
#!include auth-checkpassword.conf.ext
#!include auth-vpopmail.conf.ext
#!include auth-static.conf.ext

Cấu hình mysql parameters trong dovecot

File: /etc/dovecot/dovecot-sql.conf.ext

driver = mysql
connect = host=127.0.0.1 dbname=vimbadmin user=yyyyy password=xxxxxx
password_query = SELECT username AS user, password, homedir AS userdb_home, uid AS userdb_uid, gid AS userdb_gid FROM mailbox WHERE username = '%u'
iterate_query = SELECT username AS user FROM mailbox

Cấu hinh hình  master

File: /etc/dovecot/conf.d/10-master.conf

Tùy nhu cầu mà bạn có thể thay đổi cho hợp lý hoặc theo toàn bộ cấu hình này.


service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
    #port = 993
    #ssl = yes
  }

}

service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
    #port = 995
    #ssl = yes
  }
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
   mode = 0600
   user = postfix
   group = postfix
  }
}

service imap {

}

service pop3 {
  
}

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }

  unix_listener auth-userdb {
    mode = 0600
    user = vmail
  }

  user = dovecot
}

service auth-worker {
  user = vmail
}

Cấu hình Logging

File: /etc/dovecot/conf.d/10-logging.conf

log_path = /var/log/dovecot.log

Cấu hình Debug logging

Nếu bạn muốn ghi nhận debug khi chứng thực thì bật lên theo đoạn code sau:

#debuggign authentication requests
auth_debug = yes

#debugging other mail related stuff
mail_debug = yes

Doveconf

Để track xem những cấu hình đã thay đổi và kiểm tra có bug phát sinh không

doveconf -n

Tương tự xem tất cả cấu hình của các file

doveconf -a

Cuối cùng để start Dovecot trên Centos 7 dùng command sau:

# Start Dovecot
systemctl start dovecot
# Restart dovecot
systemctl restart dovecot

Tuy nhiên nếu dùng nhân Linux khác hoặc phiên bản Centos khác thì có lệnh khác tuy nhiên cũng là start dovecot

4. ViMbAdmin – Virtual Mail Server Administration

ViMbAdmin là giải pháp tối ưu nếu server bạn đang sử dụng PHP để phát triển ứng dụng hay website. Còn nếu  đang sử dụng sẳng ruby/rails thì bạn nên sử dụng posty để quản trị.

Cài đặt ViMbAdmin v3

Để cài Vimbadmin cần cài đặt composer trước.

curl -sS https://getcomposer.org/installer | php

Sau đó

cd /usr/local
# Dùng lệnh cài đặt git
yum install subversion git-core
# Hoặc lệnh
yum install git

# clone mã nguồn về
git clone git://github.com/opensolutions/ViMbAdmin.git vimbadmin

cd /usr/local/vimbadmin
# Dùng lệnh cài đặt composer
php composer.phar install
# Hoặc lệnh
composer instal

Tạo database hoặc user cho vimbadmin

Bạn có thể chạy lệnh sau hoặc tự custom theo ý mình

CREATE DATABASE `vimbadmin`;
GRANT ALL ON `vimbadmin`.* TO `vimbadmin`@`127.0.0.1` IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

Cấu hình vimbadmin

Backup file cấu hình

cp application/configs/application.ini.dist application/configs/application.ini

Sau đó chỉnh file cấu hình: application/configs/application.ini

securitysalt = "superadmin-password"
defaults.mailbox.uid = 5000
defaults.mailbox.gid = 5000
defaults.mailbox.homedir = "/var/vmail/"
resources.doctrine2.connection.options.driver   = 'pdo_mysql'
resources.doctrine2.connection.options.dbname   = 'vimbadmin'
resources.doctrine2.connection.options.user     = 'vimbadmin'
resources.doctrine2.connection.options.password = 'password'
resources.doctrine2.connection.options.host     = 'localhost'

Lưu ý: đảm bảo đúng cấu hình MySQL

Memcache glitch

Nếu bạn dùng memcache thì comment dòng session  này lại

;resources.session.save_path = APPLICATION_PATH "/../var/session"

Tạo bảng trong MySQL tự động

Như đã cấu hình trên Postfix và Dovecot dùng database tên Vimbadmin  nên cần chạy lệnh sau:

./bin/doctrine2-cli.php orm:schema-tool:create

Chnage Ownership

chown -R www-data:www-data /usr/local/vimbadmin

set timezone in php

Vào file: /etc/php.ini

Thêm timezone

date.timezone = "UTC"

Restart PHP-FPM

systemctl restart php-fpm

Cấu hình Nginx chạy web mail server

server {
	server_name vma.example.com;

	access_log   /var/log/nginx/vma.example.com.access.log;
	error_log    /var/log/nginx/vma.example.com.error.log;

	root /usr/local/vimbadmin/public;
	index index.php;

	location / {
		try_files $uri $uri/ /index.php?$args;
	}

	location ~ \.php$ {
		try_files $uri =404;
		include fastcgi_params;
		fastcgi_pass 127.0.0.1:9000;
	}

}

Bạn có thể thay đổi vma.example.com thành sub domain của bạn.

Sau khi cài đặt lần chạy đầu tiên sẽ yêu cầu bạn cài đặt mã salt, user và password đề vào hệ thống quản lý domain, virtual mail-users,… bằng tài khoản ViMbAdmin.

5. Cài đặt Round Cube – Giao diện quản lý mail box

Sau khi chắc chắn việc cài đặt mail server thành công và kiểm thử gửi mail cũng thành công trên IMAP hoặc POP3 thì tiến hành cài Round Cube để sử dụng web mail.

yum -y install roundcubemail

Sau khi cài đặt Round Cube được lưu tại đây: /usr/share/roundcubemail

Cấu hình Round Cube để chạy cài đặt tại đây: /etc/roundcubemail/defaults.inc.php

$config['enable_installer'] = true;

Chỉnh file cấu hình kết nối với database roundcube đã tạo tại đây: /etc/roundcubemail/config.inc.php

<?php

$config = array();

$config['db_dsnw'] = 'mysql://root:password@localhost/roundcube';

$config['default_host'] = 'localhost';

$config['smtp_server'] = 'localhost';

$config['smtp_port'] = 25;

$config['smtp_user'] = '%u';

$config['smtp_pass'] = '%p';

$config['support_url'] = '';

// Name your service. This is displayed on the login screen and in the window title
$config['product_name'] = 'Roundcube Webmail';

$config['des_key'] = 'rcmail-!24ByteDESkey*Str';

$config['plugins'] = array(
    'archive',
    'zipdownload',
);

$config['skin'] = 'larry';

Cấu hình Nginx để chạy Webmail Round Cube

server {
	server_name mail.example.com;

	access_log   /var/log/nginx/mail.example.com.access.log;
	error_log    /var/log/nginx/mail.example.com.error.log;

	root /usr/share/roundcube;
	index index.php;

	location / {
		try_files $uri $uri/ /index.php?$args;
	}

	location ~ \.php$ {
		try_files $uri =404;
		include fastcgi_params;
		fastcgi_pass 127.0.0.1:9000;
	}

}

Sau khi chạy mail.example.com trên trình duyệt và sử dụng tài khoản mail được tạo ra từ Vimbadmin để login vào và sử dụng.

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

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

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

Nghề Tester Và Những Triển Vọng Trong Tương Lai

tương lai nghề tester
Nghề Tester Và Những Triển Vọng Trong Tương Lai

Cùng với sự phát triển của thời đại công nghệ thông tin, nghề Tester – kiểm thử phần mềm được xem là một trong số các vị trí cần thiết để hoàn thành bất cứ sản phẩm công nghệ nào. Dù không còn là công việc quá xa lạ nhưng tương lai nghề Tester sẽ như thế nào vẫn là đề tài còn khá mơ hồ với nhiều người. Cùng tìm hiểu thêm một số chi tiết về ngành nghề này cũng như nắm được phần nào xu hướng phát triển của nó trong tương lai.

tương lai nghề tester
Triển vọng của Kiểm thử phần mềm trong thời gian tới

1. Những điều cần biết về Tester và công việc của một Tester

Nghề Tester hay còn được biết đến là công việc kiểm thử phần mềm. Vai trò chính của một Tester là sau khi sản phẩm phần mềm được hoàn thành, họ sẽ có vai trò kiểm tra lại toàn bộ hệ thống, ứng dụng, kịp thời phát hiện các lỗi (bug) còn xuất hiện trong phần mềm để báo devs fix trước khi bàn giao sản phẩm cho khách hàng. Nhiệm vụ của một Tester cực kỳ quan trọng vì họ sẽ là công đoạn cuối cùng đảm bảo chất lượng cho một phần mềm và suốt quá trình hoạt động của nó sau này.

Với sự phát triển mạnh mẽ hiện nay của công nghệ và phần mềm, yêu cầu nhân lực với vị trí Tester vẫn chưa có dấu hiệu chững lại. Lực lượng lao động với vai trò là Tester nói riêng cũng như đội ngũ nhân lực IT của Việt Nam nói chung hiện nay vẫn chưa đáp ứng được yêu cầu của thị trường (vẫn còn thiếu đến 30%). Do đó, thị phần công việc của vị trí này vẫn đang phát triển rất dồi dào, mở ra cơ hội rộng lớn cho bất cứ ai có đam mê với công việc kiểm thử phần mềm.

  TOP 7 Ngành Nghề Thu Hút Nhân Lực Trong Tương Lai
  Cơ Hội Việc Làm Cho Sinh Viên CNTT Mới Ra Trường

Công việc Testing hiện nay được chia thành 2 hướng chính là Manual TestingAutomation Testing.

  • Manual Testing:lựa chọn của hầu hết những ai vừa mới bắt đầu công việc kiểm thử phần mềm. Vị trí này không đòi hỏi quá nhiều kiến thức chuyên sâu về lập trình mà Tester chỉ cần nắm vững các vấn đề về định nghĩa, có tư duy và năng lực tìm bug tốt cũng như vững vàng về kỹ thuật test manual.
  • Automation Testing: Có xuất phát điểm khá khác so với Manual Testing, Automation testing thường là lựa chọn của các lập trình viên muốn chuyển hướng sang làm Tester. Công việc chính của một Automation Tester là viết code để kiểm tra một cách tự động phần mềm và lặp đi lặp lại để phát hiện ra bug.

Công việc của họ cũng gắn với code khá nhiều so với một manual tester. Nhờ sử dụng kiến thức lập trình trong kiểm thử, công việc testing sẽ diễn ra nhanh chóng hơn và thực hiện được với cả các trường hợp khó không thể phát hiện bằng tay. Automation Tester thường được yêu cầu có hiểu biết về một số ngôn ngữ lập trình khác nhau như Python, C#, C++, Java,… để phục vụ cho công việc và dự án thực tế.

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

2. Kỹ năng cần có của Tester là gì?

Như các vị trí khác liên quan đến công nghệ thông tin, muốn trở thành một Tester, bạn sẽ cần phải dành nhiều thời gian để tìm hiểu về các kiến thức lập trình nói chung cũng như luyện tập nhiều hơn để phát huy khả năng tư duy và phát hiện lỗi. Bên cạnh đó, để tìm hiểu và tiếp cận sớm được các kiến thức liên quan đến ngành nghề tester, có khả năng đọc hiểu tài liệu tiếng Anh cũng là một yêu cầu khá cần thiết.

kỹ năng của tester
Một tester giỏi cần sự kết hợp của nhiều kỹ năng khác nhau

Để trở thành một Tester giỏi và chuyên nghiệp, bạn cũng cần có khả năng phân tích và hiểu rõ ứng dụng cũng như công năng của từng phần mềm khác nhau. Ngoài ra, tính cách cẩn thận, tỉ mỉ và khả năng quan sát nhạy bén cũng là yếu tố khá quan trọng. Tầm nhìn và khả năng phán đoán với các xu hướng phát triển trong tương lai cũng là điều cần thiết với một Tester giỏi.

3. Để làm Tester cần học những gì?

Để trở thành một Tester, bạn cần có những kiến thức cơ bản về lập trình và khoa học máy tính, nắm được các vấn đề liên quan đến phần mềm cũng như cài đặt phần mềm. Kiến thức nền tảng luôn là yếu tố cực kỳ quan trọng nếu bạn muốn trở thành tester chuyên nghiệp trong tương lai. Ba kiến thức căn bản được đánh giá là rất cần thiết gồm SQL, HTML và CSS. Những kiến thức này giúp bạn đọc hiểu code cũng như chỉnh sửa code đơn giản.

Xem thêm Ngành Bảo Mật Thông Tin Và Những Cơ Hội Việc Làm Đầy Hấp Dẫn

Một phần chắc chắn không thể thiếu là các kiến thức tổng quan về kiểm thử phần mềm. Nội dung cần tìm hiểu liên quan đến các định nghĩa cơ bản, các thuật ngữ cũng như quy trình phát triển phần mềm và các giai đoạn kiểm thử phần mềm. Tìm hiểu tốt các vấn đề này sẽ giúp bạn nắm rõ những gì mình cần làm trong tương lai và có sự chuẩn bị tốt nhất.

Không chỉ có cơ hội việc làm cực kỳ hấp dẫn mà mức lương cho các vị trí Tester hiện nay cũng được đánh giá là khá cao so với thị trường. Mức lương trung bình của một Tester có khoảng 3 năm kinh nghiệm hoàn toàn có thể nằm trong khoảng từ 12 – 15 triệu/tháng. Do đó, nếu có sự đầu tư một cách nghiêm túc, bạn hoàn toàn có thể làm tốt công việc này và có được mức thu nhập trong mơ. Đón đọc thêm nhiều bài viết hấp dẫn khác cùng TopDev nhé!

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

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

Prototype của object

Prototype của object
Prototype của object

Bài viết được sự cho phép của tác giả Lưu Bình An

Khi chúng ta console.log một object của JS, sẽ thấy một property ẩn đặc biệt [[Prototype]], nó có thể là null hoặc là trỏ đến một object khác

object a => [[Prototype]] => prototype object b

Điều này có nghĩa là object a kế thừa từ object b, b có gì thì a sẽ có đó

  Javascript prototype chuyên sâu
  Nếu vỗ ngực xưng tên là một javascript developer sành sỏi, mà không giải thích được prototype inheritance thì thật là kỳ

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

Chúng ta không thể truy xuất trực tiếp thông qua [[Prototype]], mà thông qua các phương pháp khác

let animal = {
    eats: true,
    walk() {
        alert("Animal walk");
    }
}

let rabbit = {
    jumps: true,
    __proto__: animal}

// hoặc khai báo bằng
rabbit.__proto__ = animal;
console.log(rabbit.eats);
// => true;

rabbit.walk();

__proto__ != [[Prototype]]

Về bản chất, __proto__ không phải là property [[Prototype]], chính xác thì nó là getter/setter của [[Prototype]]

Thời điểm hiện tại, không khuyến khích dùng __proto__, thay vào đó dùng Object.getPrototypeOf/Object.setPrototypeOf

let user = {
    name: "John",
    surname: "Smith",
    
    set fullName(value) {
        [this.name, this.surname] = value.split(" ");
    },
    
    get fullName() {
        return `${this.name} ${this.surname}`;
    }
}

let admin = {
    __proto__: user,
    isAdmin: true
}

alert(admin.fullName);
// => John Smith

admin.fullName = "Alice Cooper";

alert(admin.fullName);// => Alice Cooper

alert(user.fullName);// => John Smith

Khi dùng prototype, không trực tiếp thay đổi property ở object cha từ object con, việc này cần thông qua một hàm setter để đảm bảo dữ liệu sẽ độc lập trên từng object.

Như ví dụ trên, this lúc này đang trỏ đến object phía trước dấu ., nên dữ liệu hoàn toàn độc lập, trong khi các phương thức thì share với nhau

Vòng lặp for...in

let animal = {
  eats: true
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

alert(Object.keys(rabbit));// jumps

for(let prop in rabbit) alert(prop); // jumps, then eats

Nếu không muốn chạy qua các property kề thừa qua __prototype__, sử dụng obj.hasOwnProperty(key) để xác định 1 property của được kế thừa hay không

for(let prop in rabbit) {
  let isOwn = rabbit.hasOwnProperty(prop);
  if (isOwn) {
    alert(`Our: ${prop}`);
    // Our: jumps
  } else {
    alert(`Inherited: ${prop}`);
    // Inherited: eats
  }
}

Một điều thú vị, nếu để ý chúng ta không hề khai báo rabbit.hasOwnProperty, vậy nó từ đâu mà có? và nó cũng không xuất hiện bên trong vòng lặp for...in?

Đây là một property kế thừa từ Object chúa, và nó đã được khai báo decriptor với giá trị enumerable: false

Đọc lại bài decriptor

Tóm tắt

  • Mỗi object sẽ chứa một property đặc biệt [[Prototype]], giá trị là null, hoặc trỏ đến một object khác
  • Sử dụng obj.__proto__ để truy cập
  • this luôn trỏ đến obj hiện tại thay vì prototype object
  • for..in sẽ chạy qua tất cả property chính chủ và property được kế thừa

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

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

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

Tìm hiểu kỹ hơn về tiến trình Service Host trên Windows

service host
Tìm hiểu kỹ hơn về tiến trình Service Host trên Windows

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

Task Manager là một trong những công cụ cực kỳ hữu ích và quen thuộc với những người sử dụng hệ điều hành Windows nói chung.

Với Task Manager thì chúng ta có thể dễ dàng theo dõi các tiến trình hệ thống đang chạy, các chương trình đang hoạt động, hay lượng tài nguyên phần cứng mà hệ điều hành cũng như phần mềm đang sử dụng.

  13 web hosting miễn phí dành cho lập trình viên
  Bí kíp để host apps hoàn toàn miễn phí

Và nếu bạn là một người dùng Windows có chút kinh nghiệm thì bạn sẽ thấy, đôi khi mở Task Manager lên bạn sẽ phát hiện ra là có hàng tá các tiến trình với tên Service Host đang chạy, mặc dù bạn chẳng mở phần mềm nào cả.

Microsoft đã mang đến cho chúng ta một hệ điều hành Windows 10 đẹp mắt, hiện đại, được nâng cấp và trang bị rất nhiều tính năng mới lạ, thú vị và cực kỳ hữu ích. Trong đó thì Service Host cũng là một trong những tính năng/ dịch vụ mới có trên Windows 10.

Nếu bạn chưa biết Service Host là gì thì mời các bạn cùng mình tìm hiểu về tiến trình Service Host có trên hệ điều hành Windows nhé!

#1. Service Host trên Windows là gì?

tim-hieu-ve-tien-trinh-service-host-tren-windows (3)

Service Host là một tiến trình cực kỳ quan trọng của hệ thống Windows, vì vậy bạn không thể xóa nó đi được.

Hiểu theo một cách đơn giản thì đúng như cái tên của nó, Service Host đóng vai trò như một máy chủ đảm bảo cho các dịch vụ (services) , như Windows Update, Windows Defender, Windows Superfetch,…, của Windows hoạt động một cách ổn định nhất.

Các dịch vụ của hệ thống Windows phải luôn chạy nền (chạy ngầm) để bạn có thể sử dụng hệ điều hành một cách ổn định, nhưng chúng lại không có khả năng chạy độc lập, thế nên mới cần đến các Service Host này đứng ra làm máy chủ để giúp nó hoạt động được.

Trên hệ điều hành Windows thì chỉ có vài loại tập tin có khả năng chạy độc lập, ví dụ như là file .EXE chẳng hạn, còn lại những file như DLL, Serivces thì phải nhờ đến Service Host.

#2. Tại sao lại xuất hiện nhiều Service Host trên Windows như vậy?

Rất dễ hiểu thôi, mỗi Service Host sẽ đảm nhận trách nhiệm về một dịch vụ riêng biệt của hệ thống, từ đó giảm được nguy cơ “ngỏm củ tỏi” của hệ điều hành Windows 10, tránh mất các dữ liệu công việc đang làm dở do nó được chia ra nhiều Service Host riêng biệt.

Vậy nên trong trường hợp một dịch vụ hay là một Service Host bất kỳ bị lỗi, hoặc không có phản hồi thì chỉ có 1 đến 2 chức năng của Windows bị vô hiệu hóa mà thôi.

Chứ nó không sập được cả hệ điều hành như khi gom tất cả các dịch vụ vào một Service Host duy nhất. Đó cũng là lý do chính mà Microsoft chia ra thành nhiều Service Host như vậy.

tim-hieu-ve-tien-trinh-service-host-tren-windows (4)

Tuy nhiên, vẫn có một vài trường hợp, Windows OS sẽ gộp nhiều dịch vụ vào cùng một nhóm khi chúng có liên quan tới nhau (Ví dụ là về Antivirus chẳng hạn).

Lúc này sẽ chỉ có một service host duy nhất đứng ra làm máy chủ cho chúng như các bạn có thể thấy ở hình bên trên. Và tất nhiên là khi service host này đổ bệnh, gặp lỗi thì mấy dịch vụ đó cũng ngủm theo 🙂 đi cả chùm luôn.

tim-hieu-ve-tien-trinh-service-host-tren-windows (5)

Cuối cùng là câu hỏi xóa/ tắt những Service Host này thì liệu có sao không?

Vâng, không những không có sao mà còn rất nhiều sao đấy các bạn à, vì như mình đã nói ở trên, nó là một tiến trình hệ thống nên khi bạn cố tắt nó thì Windows cũng sẽ sập theo.

Thêm vào đó, nó chẳng phải là virus hay gì cả, nó chạy để giúp cho hệ thống hoạt động trơn tru và ổn định hơn, vậy nên không có lí do gì để chúng ta tắt nó đi cả 🙂

#3. Lời kết

Như vậy là mình vừa giải thích xong cho các bạn về sự xuất hiện của Service Host trên hệ điều hành Windows rồi ha.

Đang còn rất nhiều bài viết tìm hiểu về các thành phần trên Windows 10 nữa, mời các bạn cùng đón chờ nhé. Hy vọng nó có ích cho các bạn. Chúc các bạn thành công !

CTV: Nguyễn Thanh Tùng – 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

Giới thiệu RabbitMQ Management Interface

RabbitMQ Management Interface
Giới thiệu RabbitMQ Management Interface

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

RabbitMQ Management là một giao diện thân thiện với người dùng cho phép chúng ta giám sát và xử lý RabbitMQ Server của mình từ trình duyệt web.

  • Có thể quản lý queue, connection, channel, exchange, users and user permission.
  • Có thể được xử lý: tạo, xóa và xem trong trình duyệt.
  • Có thể theo dõi tốc độ tin nhắn và gửi / nhận tin nhắn theo cách thủ công.

Trong bài viết này tôi sẽ giới thiệu về giao diện của phần mềm RabbitMQ Management Interface, chi tiết nhất về các chế độ xem khác nhau mà chúng ta có thể tìm thấy trong RabbitMQ Management.

Truy cập RabbitMQ Management

Ở bài viết trước tôi đã hướng dẫn các bạn Cài đặt RabbitMQ và cách start RabbitMQ Server.

Sau khi khởi động RabbitMQ, chúng ta có thể theo dõi và quản lý RabbitMQ từ giao diện web ở cổng 15672. Các bạn có thể truy cập vào trang này bằng URL sau: http://localhost:15672/ với username và password là guest/guest.

Sau khi login sẽ thấy kết quả như sau:

RabbitMQ Management Interface
RabbitMQ Management Interface

Trang Overview

Overview

Trang Overview (Tổng quan) hiển thị 2 biểu đồ, một cho các Message (tin nhắn) trong Queue (hàng đợi) và một với tốc độ tin nhắn (Message rate). Bạn có thể thay đổi khoảng thời gian hiển thị trong biểu đồ bằng cách nhấn văn bản (last minute) phía trên biểu đồ. Thông tin về tất cả các trạng thái khác nhau cho tin nhắn có thể được tìm thấy bằng cách nhấn (?).

Queued messages: Biểu đồ hể hiện tổng số tin nhắn được xếp hàng cho tất cả các Queue.

  • Ready: hiển thị số lượng tin nhắn có sẵn để được gửi.
  • Unacked: là số lượng tin nhắn mà máy chủ đang chờ xác nhận.
  • Total: tổng số tin nhắn được xếp hàng cho tất cả các Queue.

Messages rate: Bểu đồ thể hiện tỷ lệ xử lý các tin nhắn.

  • Publish: hiển thị tốc độ tin nhắn gửi đến máy chủ.
  • Publisher confirm: hiển thị tốc độ mà máy chủ đang xác nhận.
  • Deliver (manual ack)/ Deliver (auto ack): hiển thị tốc độ gửi tin nhắn ack theo cách thủ công và tự động.
  • Get (manual ack)/ Get (auto ack): hiển thị tốc độ nhận tin nhắn ack theo cách thủ công và tự động.
  • Redeliverd: hiển thị tốc độ gửi lại tin nhắn.
  • Disk read/ write: hiển thị tốc độ đọc ghi dữ liệu lên đĩa.

Global Count: Tổng số Connection, Channel, Exchage, Queue và Consumer cho TẤT CẢ các virtual host mà người dùng hiện tại có quyền truy cập.

Nodes

Hiển thị thông tin về các Node khác nhau trong cụm RabbitMQ (cụm là một nhóm các Node hay một nhóm máy tính). Ở đây có thể thấy thông tin về bộ nhớ máy chủ (Memory), số lượng quá trình Erlang trên mỗi Node, dung lượng ổ đĩa (Disk space), thời gian start server (Uptime), …

Churn statistics

Hiển thị tỷ lệ tạo mới (created) hoặc đóng (closed) các connection, channel, queue.

Ports and contexts

Các port (cổng lắng) nghe cho các protocol (giao thức) khác nhau có thể được tìm thấy ở đây.

Import export definitions

Có thể import và export definition (định nghĩa) cấu hình toàn bộ thông tin về RabbitMQ.

Khi export các definition, chúng ta nhận được một file JSON đại diện cho broker (RabbitMQ). Điều này có thể được sử dụng để khôi phục Exchange, Queue, virtual host, policy, user, … Tính năng này có thể được sử dụng như một bản sao lưu. Mỗi khi bạn thay đổi cấu hình, bạn có thể lưu giữ các cài đặt cũ để khôi phục lại khi cần.

Một số thông tin của file export definition:

{     "rabbit_version": "3.8.3",     "rabbitmq_version": "3.8.3",     "users": [         {             "name": "admin",             "password_hash": "DTJsIFUX+ZufUuomOCV7U4r/tHKTcQwQRgQ2VrpirFg54V8c",             "hashing_algorithm": "rabbit_password_hashing_sha256",             "tags": "administrator"         },         {             "name": "guest",             "password_hash": "KlAfeUhw5bovgF2KYUR8Nwu4MCvZMCb5tzAzTx+Hy9ASsYvU",             "hashing_algorithm": "rabbit_password_hashing_sha256",             "tags": "administrator"         }     ],     "vhosts": [         {             "name": "/"         }     ],     "permissions": [         {             "user": "admin",             "vhost": "/",             "configure": ".*",             "write": ".*",             "read": ".*"         },         {             "user": "guest",             "vhost": "/",             "configure": ".*",             "write": ".*",             "read": ".*"         }     ],     "topic_permissions": [         {             "user": "admin",             "vhost": "/",             "exchange": "",             "write": ".*",             "read": ".*"         }     ],     "parameters": [],     "global_parameters": [         {             "name": "cluster_name",             "value": "rabbit@Phans-MacBook-Pro"         },         {             "name": "internal_cluster_id",             "value": "rabbitmq-cluster-id-O9MD_G6YuGvhRlj0rsUbAA"         }     ],     "policies": [],     "queues": [         {             "name": "QGeneral",             "vhost": "/",             "durable": true,             "auto_delete": false,             "arguments": {}         },         {             "name": "QManager",             "vhost": "/",             "durable": true,             "auto_delete": false,             "arguments": {}         }     ],     "exchanges": [         {             "name": "GPCoderHeadersExchange",             "vhost": "/",             "type": "headers",             "durable": true,             "auto_delete": false,             "internal": false,             "arguments": {}         },         {             "name": "GPCoder.DirectExchange",             "vhost": "/",             "type": "direct",             "durable": true,             "auto_delete": false,             "internal": false,             "arguments": {}         }     ],     "bindings": [         {             "source": "GPCoder.DirectExchange",             "vhost": "/",             "destination": "QDeveloper",             "destination_type": "queue",             "routing_key": "devGroup",             "arguments": {}         }     ] }

Trang Connections

Connection là kết nối TCP giữa ứng dụng và broker RabbitMQ. Một Channel là một kết nối ảo bên trong một Connection.

Trang Connection hiển thị các kết nối được thiết lập đến máy chủ RabbitMQ.

  • Overview hiển thị địa chỉ IP, tên người dùng được liên kết với kết nối, trạng thái Connection.
  • Channels cho biết số lượng kênh sử dụng kết nối.
  • SSL / TLS cho biết liệu kết nối có được bảo mật bằng SSL hay không.

Nếu click vào một trong các kết nối, ta sẽ có cái nhìn tổng quan về kết nối cụ thể đó. Có thể xem các kênh trong kết nối và tốc độ dữ liệu. Có thể thấy các thuộc tính của Client và ta có thể đóng kết nối nếu muốn (Force Close).

 

Trang Channels

Trang Channels hiển thị thông tin về tất cả các Channel hiện tại.

  • Hiển tên người dùng mà người dùng liên kết với kênh, trạng thái kết nối, xác nhận, …
  • Tỷ lệ trao đổi Message.

Nếu click vào một trong các Channel, ta sẽ có được cái nhìn tổng quan chi tiết về Channel thể đó.

Trang Exchanges

Một Exchange sẽ nhận được tin nhắn từ các Producer và đẩy chúng đến Queue. Exchange phải biết chính xác những gì cần làm với một tin nhắn mà nó nhận được. Tất cả các Exchange có thể được liệt kê từ trang Exchange.

  • Name: Hiển thị tên Exhange được tạo.
  • Type: là loại Exchange như direct, topic, fanout và header.
  • Feature: hiển thị các tham số cho Exchange (ví dụ: D là durable, và AD là auto-delete).
  • Message rate in/ out: Tỷ lệ xử lý Message chuyển đến và đi.
  • Trong danh sách này có một số Exchange amq.* và Default Exchange (trao đổi mặc định – không tên), chúng được tạo theo mặc định.

Có thể thêm một Exchange mới:

Bằng cách click vào tên Exchange, một trang chi tiết về Exchange được hiển thị.

Có thể xem và thêm các ràng buộc cho Exchange.

Cũng có thể publish một tin nhắn đến Exchange:

Hoặc xóa Exchange.

Trang Queues

Queue có các tham số và đối số khác nhau tùy thuộc vào cách chúng được tạo.

  • Name: Hiển thị tên Queue được tạo.
  • Feature: hiển thị các tham số cho Queue (ví dụ: D là durable, và AD là auto-delete).
  • Message Ready: hiển thị số lượng tin nhắn có sẵn để được gửi.
  • Message Unacked: là số lượng tin nhắn mà máy chủ đang chờ xác nhận.
  • Message Total: tổng số tin nhắn được xếp hàng trong Queue.
  • Message rate in/ out: Tỷ lệ xử lý Message chuyển đến và đi.

Có thể thêm một Queue mới:

Bằng cách click vào tên Queue, một trang chi tiết về Queue được hiển thị.

Consumer: hiển thị consumers/ channels đang được kết nối đến Queue.

Có thể xem và thêm các ràng buộc cho Queue.

Cũng có thể publish một tin nhắn đến Queue:

Có thể xoá Queue bằng cách click vào button Delete Queue hoặc xoá tất cả Message trong Queue bằng cách click vào button Purge Messages.

Trang Admin

Từ trang Admin, ta có thể thêm user, thay đổi user permission, set up vhost, policy, giới hạn số lượng connection hay thay đổi cluster name.

Click vào menu Virtual Hosts bên trái để xem danh sách hoặc thêm Virtual Hosts mới:

Có thể thêm hoặc cập nhật Policy ở sub-menu Policies bên trái:

Tương tự click vào sub-menu Limits để giới hạn số lượng Connection, Queue của một Virtual Host.

Mặc định, RabbitMQ đặt tên cho cluster là rabbit@<computer name>, chúng ta có thể đổi tên này ở sub-menu cluster:

Bài viết này chủ yếu giới thiệu với các bạn các tính năng mà chúng ta có thể sử dụng từ RabbitMQ Management Interface. Trong các bài viết tiếp theo, chúng ta sẽ cùng tìm hiểu các giao tiếp với RabbitMQ thông qua code và các bạn có thể sử dụng công cụ này để theo dõi các thông tin về Exchange, Queue, Connection, … được tạo ra từ code của chúng ta.

Tài liệu tham khảo:

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

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

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

Var, let và const – 3 quý cô xinh đẹp nhà Javascript

Var, let và const
Var, let và const – 3 quý cô xinh đẹp nhà Javascript

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

1. Con nhà danh giá.

Tiếp tục chuỗi bài về Javascript, hôm nay sẽ là bài viết về gái. Không phải một mà là 3 đứa Var, Let và Const.

Từ kỷ ES6, giới anh hùng trong giang hồ đã không ngừng bàn luận tới 3 cô nàng tuyệt sắc giai nhân của nhà Javascript. Tuy nhiên, không phải cô nào cũng giống nhau, cũng đều thích hợp cho tất cả các chàng developer.

3 chị em var,let và const. Cuộc chiến không khoan nhượng.
Nguồn ảnh/ Source: deadcoderising.com

Tính khí các cô khác nhau, vì vậy phải hiểu thật rõ để có chiến thuật cưa cẩm phù hợp. Hãy cùng tìm hiểu qua bài viết dưới đây.

  10 trình quản lý file hàng đầu trong JavaScript
  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết

Xem thêm các chương trình tuyển dụng JavaScript lương cao trên TopDev

2. Các quý cô xinh đẹp.

2.1 Angelina VAR

Hình ảnh chả liên quan.
Để các ông ngắm đọc bài đỡ chán.

2.1.1 Phạm vi hoạt động.

Phạm vi của var là FUNCTION SCOPE, nghĩa rằng khi ta khai báo var trong một function, biến var đó chỉ tồn tại và có giá trị trong phạm vi function nó khai báo.

var varGirl = "Mặt em là mặt mộc";

function after_tay_trang() {
var varGirl = "Đây là ai?, tao ở đâu?, con nào đang đứng trước gương thế này";

console.log (varGirl); 
}
after_tay_trang(); // output: Đây là ai?, tao ở đâu?, con nào đang đứng trước gương thế này
console.log(varGirl); // output: Mặt em là mặt mộc

Hoặc là:

function myFunc() { 
var name = 'Luke'
console.log(name); // 'Luke'
}
myFunc();

console.log(name); // name is not defined

2.1.2 Lật mặt như bánh tráng

Từ ES2015 (ES6) thì vẻ đẹp của cô nàng VAR đã là bất tử, tuy nhiên không phải cứ đẹp là được tất cả. Trời cho var cái đẹp, nhưng cũng lấy hết m* mấy cái nết na của nàng ta.

  var logicGái = "em chỉ yêu mỗi mình anh";
var logicGái = "đéo có tiền thì anh cút";

Trường hợp có sử dụng vòng for, sử dụng var là cực kì nguy hiểmVí dụ sau đây cho thấy điều đó.

  // Running a for loop with var:
for(var i = 0; i < 10; i++){
console.log(i);
}
// Mong muốn có output: 0,1,2,3,4,5,6,7,8,9.
// Sự thật thì đắng lòng thay:
Output: 10

Tại sao?. Nguyên nhân nằm ở scope của var. Mỗi lần vòng for chay, biến i đều được khởi tạo mới (redeclared), việc này dẫn tới kết qủa cuối cùng là 10.

2.1.3 Ảnh hưởng bởi chức quyền?.

Var đẹp, nhưng yếu vía vl. Cứ có ai gây áp lực thì var xoay nhanh hơn cả spinner.

function fuckingKiddingMe(){ 
var cô_giáo = "tôi không biết chữa sốt rét đâu thầy"; 
// Thầy giáo bảo phải cởi quần áo mới ấm người kẻo rét quá mà chết.
var cô_giáo = "vậy thôi, vì tình đồng nghiệp, nằm tí cho ấm";

console.log(cô_giáo); // Thầy đùa em chăng?
}

2.2 Emma LET.

Ngắm gái nhưng vẫn phải tập trung đọc bài.

2.2.1 Phạm vi hoạt động (Scope).

Quận 10, Tân Bình, từ 9h -> 23h, không qua đêm.

Gì ba?. Vừa viết bài vừa lướt thiend*a à?.

Trường hợp được khai báo let là global và khai báo lại một lần nữa ở điều kiện if thì giá trị của let là không đổi.

let MrJokes = yeuemA;

if(Age > 40) {
let MrJokes = yeuemB; // Trẻ hơn
}

// Liệu rằng có thích gái trẻ:
MrJokes

// Không, vẫn chung thủy: 
yeuemA

Tại sao?. Nguyên nhân là do scope của 2 biến let là khác nhau (bất chấp có cùng tên khai báo).

// Scope của window (globally). 
let MrJokes = yeuemA;

if(Age > 40) {
// Scope của block (trong phạm vi {})
let MrJokes = yeuemB; // Trẻ hơn
}

Để rõ ràng và dễ nhớ hơn: var thì luôn là function scope, còn let là block scope.

2.2.2 Chung thủy điềm đạm.

Khác hẳn với cô nàng varlet lại là người vô cùng chung thủy. Trường hợp sử dụng let trong vòng for. Do là block scope (scope vòng for) nên giá trị sẽ không redeclared hoặc được gán lại sau mỗi lần chạy.

for(let i = 0; i < 10; i++) {
console.log(i);
setTimeout(function() {
console.log('The number is ' + i);
}, 1000);
}

// This returns 0 through 9 in the console, then after one second logs:
The number is 0
The number is 1
The number is 2
The number is 3
The number is 4
The number is 5
The number is 6
The number is 7
The number is 8
The number is 9

Rõ ràng, trong tình yêu cũng vậy, phàm cứ phải chạy tới chạy lui như for thì nên chọn cô em thứ 2 (let).

2.2.3 Ảnh hưởng bởi chức quyền?.

Câu trả lời là không. Cố tình khai báo 2 biến let cùng 1 block scope sẽ cho ra syntax error.

 function vongMotSizeBaoNhieu() { 
let a = 60; 
let a = 90; //throws syntax error
console.log(a); 
// Của trời cho, không to lên được.
}

2.3 Alexandra CONST.

Mỹ nhân với đôi mắt tuyệt đẹp.

2.3.1 Phạm vi hoạt động.

 function vongMotSizeBaoNhieu(){ 
let a = 60; 
let a = 90; //throws syntax error
console.log(a); 
// Của trời cho, không to lên được.
}

Nhà có 3 chị em, let và const có phạm vi hoạt động giống nhau, là BLOCK SCOPE.

2.3.2 Tuyệt đối chung thủy.

Với các thanh niên tin vào tình yêu vĩnh cmn cửu thì const là một cô nàng không thể bỏ qua. Giá trị đã gán cho const chỉ được gán một lần và không bao giờ được gán lại.

2.3.2 Khác gì với cô chị LET.

Không giống với cô chị Let, nếu chỉ khai báo đơn thuần biến const, giá trị const không thể redeclare.

 // Định nghĩa const:
const key = 'xyz123';
// Cố gắng redeclare:
key = 'xyz1234'
// Lỗi:
Uncaught TypeError: Assignment to constant variable.

Tuy nhiên, có một lưu ý nhỏ ở đây là nếu khai báo const như là một object, thì các attributes của object này lại có thể thay đổi.

Xem xét ví dụ sau:

 // Tạo object emma:
const emma = {
name: 'Watson',
age: 23
}
// Call emma ở console:
emma
// Kết quả:
{name: "Watson", age: 13}
// Tác động thay đổi attribute age:
emma.age = 14 // Tù mọt gông
// Gọi:
emma
// Kết quả:
{name: "Watson", age: 14}

Nếu vẫn muốn const chung thủy tuyệt vời, ta có thể sử dụng “freeze”.

 // Dùng freeze:
const emmaW = Object.freeze(emma);

3. Kết luận.

Bận lên thiend*a rồi nên bài này không có kết luận nha anh em.

javascript-su-khac-biet-var-let-va-constBảng so sánh scope của var, let và const.

4. Tài liệu tham khảo.

  1. Var, let, or const.
  2. Difference between let, const and var.

Nếu thấy hay có thể tham khảo thêm bài viết Javascript Prototype ở Kieblog nha. Cũng khá ổn!.

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

Tạo thư viện cocoapod trên github

thư viện cocoapod
Tạo thư viện cocoapod trên github

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

Bài này mình dùng 1 thư viện sửa rich text trên textview, có hình ảnh như sau:

Thư viện gốc nằm ở đây:

https://github.com/aryaxt/iOS-Rich-Text-Editor

Và vì thư viện này không hỗ trợ cài qua cocoapod nên mình sẽ tiến hành tạo pod cho nó. Mình sẽ lấy tên là QRichTextView và mong muốn sẽ cài bằng lệnh:

  pod 'QRichTextView'

Nào cùng tiến hành nhé.

  15 thư viện slider jquery miễn phí cho dự án website của bạn
  5 công cụ nguồn mở các thư viện cần biết

Đầu tiên bạn cần tải sources code này về bằng dòng lệnh:

https://github.com/aryaxt/iOS-Rich-Text-Editor

Bây giờ ta thấy source code như sau:

Sau khi phân tích thì mình nhận thấy các vấn đề sau:
  • Source code này không có ARC – tự động dọn dẹp bộ nhớ, vì nó tạo cách đây 8 năm, cái thời xcode còn chưa hỗ trợ -> nên cần xóa toàn bộ các lệnh release, retain hay autorelease..
  • Source đang để nhiều thư mục. Muốn tiến hành làm library và viết bớt script thì đưa vào 2 thư mục chính là Classes(chứa files .h và .m) và Assets(chứa các file ảnh).
  • Có bug không đọc được ảnh khi chuyển sang project lib của mình.

Vậy chúng ta sẽ tiến hành tạo mới 1 framework bằng Xcode như sau:

  • file -> new project -> Framework

Đặt tên nó là QRichTextView(hoặc tên gì tùy bạn).

Tiếp theo tạo 2 thư mục chính Classes và Assets như hình:

Sau đó sang source code của họ để copy toàn bộ các file .h và .m từ các thư mục Source, Categories, iphone Popover vào thư mục Classes của chúng ta. Làm tương tự với các file .png vào thư mục Assets.
  • Bấm build thì được 1 đống lỗi. Những đoạn sau sẽ sinh ra lỗi:

Xóa và sửa lại đơn giản hơn:

Các bạn tiến hành xóa và sửa hết, rồi build thành công. Tuy nhiên khi dùng framework này sẽ phải sửa thêm 1 đoạn code như sau để nó đọc được hình ảnh từ thư mục Asset sang:

 // Load image from framework
    NSBundle *frameWorkBundle = [NSBundle bundleForClass:[self class]];
    UIImage* tempImage = [UIImage imageNamed:image inBundle:frameWorkBundle compatibleWithTraitCollection:nil];
    ;

Đoạn code trên cần chỉ rõ đọc ảnh từ framework bundle, nếu không hình ảnh sẽ không load được.

Bây giờ làm sao để build cho cả simulator và device? Mình sẽ tạo thêm 1 target gọi tên là universal như sau:

  • Chọn file -> new target -> Aggregate và đặt tên là QRichTextView-Univesal như hình:

Tiếp theo bạn vào target này và chọn build Phases -> new run script phases và copy đoạn code dưới đây:

# Sets the target folders and the final framework product.
FMK_NAME=QRichTextView
FMK_VERSION=1.0

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

# Creates and renews the final product folder.
mkdir -p "${INSTALL_DIR}"
mkdir -p "${INSTALL_DIR}/Versions"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers"

# Creates the internal links.
# It MUST uses relative path, otherwise will not work when the folder is copied/moved.
ln -s "${FMK_VERSION}" "${INSTALL_DIR}/Versions/Current"
ln -s "Versions/Current/Headers" "${INSTALL_DIR}/Headers"
ln -s "Versions/Current/Resources" "${INSTALL_DIR}/Resources"
ln -s "Versions/Current/${FMK_NAME}" "${INSTALL_DIR}/${FMK_NAME}"

# Copies the headers and resources files to the final product folder.
cp -R "${DEVICE_DIR}/Headers/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/"

# Removes the binary and header from the resources folder.
rm -r "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/Headers" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/${FMK_NAME}"

# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}"

rm -r "${WRK_DIR}"

Sau đó bạn build và tạo ra 1 framework có tên là QRichTextView.framework như hình:

Bạn có thể kéo thả vào project của bạn và dùng thoải mái.

Đến đây chúng ta vẫn chưa thực sự tạo ra thư viện trên CocoaPod.

Bạn hãy lên github tạo 1 repository có tên là QRichTextView, sau đó tiến hành upload toàn bộ code của bạn lên:

> git init
> git remote add origin git@github.com:{USERNAME}/QRichTextView.git
> git add .
> git commit -m "Initial project setup"
> git push -u origin master

Repository của bạn cần có 2 file README and MIT License. Bạn làm như hình:

Sau đó thêm tên là README và LICENSE. Github sẽ gợi ý bạn chọn MIT license..

Viết unit test cho project

Cái này mình không có thời gian nên không làm.

Configure Travis CI

Ở đây bạn có thể vào trang chủ Travis CI để làm theo hướng dẫn. Có thể bỏ qua nếu chưa cần thiết.

Public thư viện

Bạn cần cài đặt CocoaPod để đẩy lên. Nếu chưa cài hãy gõ lệnh:

gem install cocoapods

Sau đó gõ lệnh:

pod spec create QRichTextView

File này chứa thông tin về version, tên thư viện, các source code, Asset, thông tin tác giả… để public thư viện lên cho cộng đồng. Bạn có thể sửa như sau:

#
#  Be sure to run `pod spec lint QRichTextView.podspec' to ensure this is a
#  valid spec and to remove all comments including this before submitting the spec.
#
#  To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html
#  To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#

Pod::Spec.new do |spec|

  # ―――  Spec Metadata  ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  These will help people to find your library, and whilst it
  #  can feel like a chore to fill in it's definitely to your advantage. The
  #  summary should be tweet-length, and the description more in depth.
  #

  spec.name         = "QRichTextView"
  spec.version      = "0.0.3"
  spec.summary      = "Pod version for https://github.com/aryaxt/iOS-Rich-Text-Editor.git"

  # This description is used to generate tags and improve search results.
  #   * Think: What does it do? Why did you write it? What is the focus?
  #   * Try to keep it short, snappy and to the point.
  #   * Write the description between the DESC delimiters below.
  #   * Finally, don't worry about the indent, CocoaPods strips it!
  spec.description  = "Pod version for https://github.com/aryaxt/iOS-Rich-Text-Editor.git. You can the rich text view."

  spec.homepage     = "https://github.com/lexuanquynh/QRichTextView"
  # spec.screenshots  = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"


  # ―――  Spec License  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Licensing your code is important. See https://choosealicense.com for more info.
  #  CocoaPods will detect a license file if there is a named LICENSE*
  #  Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
  #

  spec.license      = { :type => "MIT", :file => "LICENSE" }
  # spec.license      = { :type => "MIT", :file => "FILE_LICENSE" }

  # ――― Author Metadata  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Specify the authors of the library, with email addresses. Email addresses
  #  of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
  #  accepts just a name if you'd rather not provide an email address.
  #
  #  Specify a social_media_url where others can refer to, for example a twitter
  #  profile URL.
  #

  spec.author             = { "Le Xuan Quynh" => "le-xuan-quynh@goodcycle.net" }
  # Or just: spec.author    = "Le Xuan Quynh"
  # spec.authors            = { "Le Xuan Quynh" => "le-xuan-quynh@goodcycle.net" }
  # spec.social_media_url   = "https://twitter.com/Le Xuan Quynh"

  # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  If this Pod runs only on iOS or OS X, then specify the platform and
  #  the deployment target. You can optionally include the target after the platform.
  #

  # spec.platform     = :ios
  # spec.platform     = :ios, "5.0"

  #  When using multiple platforms
  spec.ios.deployment_target = "9.0"
  # spec.osx.deployment_target = "10.7"
  # spec.watchos.deployment_target = "2.0"
  # spec.tvos.deployment_target = "9.0"


  # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Specify the location from where the source should be retrieved.
  #  Supports git, hg, bzr, svn and HTTP.
  #

  spec.source       = { :git => "https://github.com/lexuanquynh/QRichTextView.git", :branch => "main", :tag => "#{spec.version}" }


  # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  CocoaPods is smart about how it includes source code. For source files
  #  giving a folder will include any swift, h, m, mm, c & cpp files.
  #  For header files it will include any header in the folder.
  #  Not including the public_header_files will make all headers public.
  #

  spec.source_files  = "QRichTextView/Classes/*.{h,m}"
  # spec.exclude_files = "Classes/Exclude"

  spec.public_header_files = "QRichTextView/Classes/*.h"


  # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  A list of resources included with the Pod. These are copied into the
  #  target bundle with a build phase script. Anything else will be cleaned.
  #  You can preserve files from being cleaned, please don't preserve
  #  non-essential files like tests, examples and documentation.
  #

  # spec.resource  = "icon.png"
  spec.resources = "QRichTextView/Assets/*.png"

  # spec.preserve_paths = "FilesToSave", "MoreFilesToSave"


  # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Link your library with frameworks, or libraries. Libraries do not include
  #  the lib prefix of their name.
  #

  # spec.framework  = "SomeFramework"
  # spec.frameworks = "SomeFramework", "AnotherFramework"

  # spec.library   = "iconv"
  # spec.libraries = "iconv", "xml2"


  # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  If your library depends on compiler flags you can set them in the xcconfig hash
  #  where they will only apply to your library. If you depend on other Podspecs
  #  you can include multiple dependencies to ensure it works.

  # spec.requires_arc = true

  # spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
  # spec.dependency "JSONKit", "~> 1.4"

end

Trong đó:

  • spec.name là tên thư viện
  • spec.version: phiên bản thư viện
  • spec.summary: mô tả ngắn của thư viện
  • spec.homepage: trang chủ của thư viện
  • spec.license: License thư viện
  • spec.author: Thông tin tác giả
  • spec.ios.deployment_target: minimum os hỗ trợ
  • spec.source: source code khi cài
  • spec.source_files: để build
  • spec.public_header_files: Các header có thể sử dụng sau khi build thành công
  • spec.resources: Hình ảnh sử dụng trong thư viện

Sau đó các bạn tiến hành commit và đẩy code lên nhánh trên git của mình:

git commit -am "add all"
git add .
git commit -m "add all files"
git push origin master

Mỗi thư viện cần đánh số version. Ở đây do lần đầu tạo nên tôi đánh số 0.0.1. Lưu ý là số này ở spec.version và trên project setting phải giống nhau:

Sau đó bạn đẩy tag này lên git:

git tag 0.0.1
git push origin 0.0.1

Tiến hành build thư viện bằng lệnh và bỏ qua các cảnh báo do mình chưa fix hết:

pod lib lint --allow-warnings

Và gõ tiếp lệnh sau để đăng ký trên git org tương tự lệnh sau:


pod trunk register quynhlxbkhn@gmail.com 'Codetoanbug' --description='macbook pro'

Và cuối cùng gõ lệnh để public thư viện của bạn:

pod trunk push --allow-warnings

Khi nhận được thông báo như sau là bạn đã public thành công:

May be an image of textBạn đợi tầm 30 phút đến vài tiếng để pod có thể index lại thư viện. Sau đó bạn gõ lệnh sau để update pod của bạn:
pod repo update

Đây là thư viện tôi vừa tạo:

https://github.com/lexuanquynh/QRichTextView

Bạn có thể cài bằng pod với lệnh sau:

pod 'QRichTextView'

Hoặc xem thêm ở file Readme để hiểu cách dùng.

Update: Cho các lần fix bug sau, bạn chỉ cần làm theo các bước:

  1. Fix bug và commit lên master
  2. Thay đổi version trong bundle version và file podspec, ví dụ 0.0.x(x phải tăng lên 1 so với version cũ).
  3. Tạo version mới bằng cách gõ:
git tag 0.0.x
git push origin 0.0.x

Với x là số tăng lên 1 đơn vị cho các thay đổi nhỏ. Để hiểu thêm cách đặt tên tag các bạn có thể google.

Sau đó là các lệnh sau để build và update lên CocoaPod:

pod lib lint --allow-warnings
pod trunk push --allow-warnings

Nếu có lỗi hãy comment ở dưới bài viết nhé. Gook luck.

Xem thêm tại https://www.facebook.com/codetoanbug

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

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

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

Tổng hợp 50+ thẻ HTML phổ biến nhất

html là gì
HTML là gì? Các thẻ HTML cơ bản và ứng dụng

Bài viết được sự cho phép của BQT Kinh nghiệm lập trình

HTML là ngôn ngữ đánh dấu được sử dụng để tạo cấu trúc và định dạng cho các trang web. Đối với cả những lập trình viên mới học lẫn những người chuyên nghiệp, việc hiểu rõ và sử dụng thành thạo các thẻ HTML cơ bản không chỉ giúp xây dựng trang web một cách hiệu quả mà còn hỗ trợ đắc lực trong việc tối ưu hóa công cụ tìm kiếm (SEO). Dưới đây là tổng hợp các thẻ HTML quan trọng và thông dụng, cùng ví dụ minh họa chi tiết.

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

Khái quát lại về HTML

HTML là gì? HTML làm từ viết tắt của cụm tiếng Anh HyperText Markup Language, có nghĩa là “ngôn ngữ đánh dấu siêu văn bản”. Đây là một dạng ngôn ngữ đặc biệt, khác với các ngôn ngữ ký tự hay ngôn ngữ kịch bản thi hành tác vụ. HTML là ngôn ngữ được thiết kế với mục đích tạo lập trang web từ các nguồn thông tin có trên World Wide Web – mạng lưới toàn cầu. Chúng có khả năng giúp người dùng tạo và cấu trúc thành phần trong trang web hoặc có thể ứng dụng phân chia đoạn văn hay heading, links, blockquotes…

HTML còn được biết đến như một ứng dụng đơn giản của hệ thống chức và gắn thẻ yếu tố của một tài liệu. Đồng thời chúng còn được sử dụng trong các tổ chức cần yêu cầu xuất bản phức tạp. Và việc sử dụng HTML là một trong những kỹ năng cơ bản của người phát triển website. Làm thế nào để tạo ra nội dung trang web bằng HTML luôn là bài toán trước tiên để bồi đắp kỹ năng tạo Web.

Và thêm một điều quan trọng cần lưu ý, HTML không phải là một dạng ngôn ngữ lập trình, có nghĩa chúng không thể tạo ra các chức năng “động” được. Vì vậy HTML chỉ có chức năng tương tự như Microsoft Word với khả năng dùng để bố cục và định dạng trang web.

Các thẻ HTML cơ bản nhất hiện nay

Thẻ cơ bản của một cấu trúc HTML

Mọi trang web HTML đều bắt đầu từ một cấu trúc cơ bản. Đây là khung sườn giúp trình duyệt hiểu được cách trình bày nội dung trên trang.

  • <!DOCTYPE>: Khai báo kiểu tài liệu, giúp trình duyệt hiểu phiên bản HTML mà trang web đang sử dụng.
  • <html>: Thẻ bao bọc toàn bộ nội dung của trang web, xác định rằng tài liệu là HTML.
  • <head>: Chứa các thẻ meta, liên kết tài nguyên, tiêu đề và các thông tin không hiển thị trên trang.
  • <title>: Thẻ tiêu đề trang, rất quan trọng đối với SEO, hiển thị trên thanh tiêu đề của trình duyệt và trong kết quả tìm kiếm.
  • <meta>: Chứa các thông tin về trang web như charset, mô tả, từ khóa (keywords), và viewport.
  • <body>: Chứa toàn bộ nội dung hiển thị trên trang web, bao gồm văn bản, hình ảnh, liên kết, bảng, và đa phương tiện.

Ví dụ về cấu trúc HTML cơ bản:

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="description" content="Giới thiệu các thẻ HTML cơ bản và thông dụng.">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Các thẻ HTML cơ bản</title>
</head>
<body>
    <!-- Nội dung của trang web -->
</body>
</html>

Thẻ định dạng thành phần Web

Các thẻ này định nghĩa các phần tử chính trên trang web, giúp tạo ra cấu trúc trực quan và dễ sử dụng.

  • <header>: Định nghĩa phần đầu của trang hoặc phần giới thiệu.
  • <footer>: Định nghĩa phần chân trang, thường chứa thông tin liên lạc hoặc bản quyền.
  • <nav>: Định nghĩa thanh điều hướng cho các liên kết chính trên trang web.
  • <section>: Định nghĩa một phần nội dung chính, có thể bao gồm nhiều đoạn văn, hình ảnh hoặc bảng.
  • <article>: Định nghĩa một bài viết độc lập hoặc phần nội dung có thể tái sử dụng.
  • <aside>: Định nghĩa phần nội dung phụ, chẳng hạn như thanh bên (sidebar).
  • <div>: Thẻ phân chia các thành phần, giúp sắp xếp và định dạng nội dung theo khối.

Thẻ định dạng nội dung văn bản (Text Content)

Thẻ HTML trong nhóm này định dạng và hiển thị văn bản, giúp tổ chức và trình bày nội dung dễ đọc hơn.

  • <p>: Thẻ đoạn văn bản.
  • <h1> đến <h6>: Các thẻ tiêu đề, từ cấp 1 đến cấp 6, giúp phân cấp nội dung.
  • <strong>: Nhấn mạnh nội dung với ý nghĩa quan trọng, có tác dụng SEO.
  • <em>: Nhấn mạnh nội dung, tạo nét nghiêng.
  • <span>: Định dạng một phần nội dung nhỏ trong văn bản, thường được dùng để gán các kiểu CSS.
  • <blockquote>: Định nghĩa một đoạn trích dẫn.
  • <pre>: Hiển thị văn bản dạng đã định sẵn, giữ nguyên khoảng trắng và xuống dòng.
  • <code>: Định dạng đoạn mã nguồn trong văn bản.

Thẻ định dạng bảng (Table)

Thẻ bảng được sử dụng để hiển thị dữ liệu có cấu trúc, chẳng hạn như biểu đồ, bảng thống kê.

  • <table>: Thẻ bao bọc toàn bộ nội dung của bảng.
  • <tr>: Định nghĩa một hàng trong bảng.
  • <td>: Định nghĩa một ô dữ liệu trong bảng.
  • <th>: Định nghĩa ô tiêu đề trong bảng, giúp làm nổi bật nội dung.
  • <thead>, <tbody>, <tfoot>: Định nghĩa các phần đầu, thân và chân của bảng.
  • <caption>: Định nghĩa tiêu đề của bảng.

Thẻ danh sách (List tag)

Danh sách giúp tổ chức nội dung thành các mục dễ theo dõi, thường được dùng cho các bước hướng dẫn hoặc danh mục sản phẩm.

  • <ul>: Định nghĩa danh sách không có thứ tự, với các mục được đánh dấu bằng ký tự (thường là dấu chấm tròn).
  • <ol>: Định nghĩa danh sách có thứ tự, với các mục được đánh số.
  • <li>: Định nghĩa một mục trong danh sách, có thể xuất hiện trong cả danh sách có thứ tự và không có thứ tự.
  • <dl>: Định nghĩa danh sách mô tả, sử dụng khi cần hiển thị một danh sách các thuật ngữ và định nghĩa.
  • <dt>: Định nghĩa một thuật ngữ trong danh sách mô tả.
  • <dd>: Định nghĩa phần mô tả cho một thuật ngữ.

Thẻ Multimedia

Thẻ đa phương tiện giúp chèn và hiển thị nội dung đa phương tiện như hình ảnh, âm thanh, video trên trang web.

  • <img>: Định nghĩa hình ảnh, thuộc tính alt giúp tối ưu SEO hình ảnh.
  • <audio>: Định nghĩa âm thanh, có thể nhúng các tệp âm thanh vào trang web.
  • <video>: Định nghĩa video, cho phép phát video trực tiếp trên trình duyệt.
  • <source>: Định nghĩa các tệp nguồn cho âm thanh hoặc video, hỗ trợ nhiều định dạng khác nhau.
  • <iframe>: Cho phép nhúng nội dung từ một trang web khác vào trang hiện tại, thường dùng để chèn video từ YouTube.

Thẻ liên kết (Links)

Các thẻ liên kết giúp tạo các liên kết giữa các trang web hoặc tài nguyên bên ngoài.

  • <a>: Định nghĩa liên kết đến một tài nguyên khác, rất quan trọng trong SEO. Văn bản liên kết (anchor text) nên chứa từ khóa liên quan.
  • <link>: Liên kết đến tài nguyên ngoài, thường dùng cho việc nhúng tệp CSS hoặc biểu tượng trang web.
  • <nav>: Định nghĩa khu vực điều hướng chứa các liên kết chính.

Thẻ Programming

HTML hỗ trợ các thẻ lập trình, cho phép tương tác với ngôn ngữ lập trình khác hoặc chèn mã lệnh trực tiếp.

  • <script>: Định nghĩa mã JavaScript, giúp tăng cường tính năng động cho trang web.
  • <noscript>: Hiển thị nội dung nếu trình duyệt không hỗ trợ hoặc đã tắt JavaScript.
  • <canvas>: Cho phép vẽ đồ họa, ảnh động hoặc trò chơi thông qua JavaScript.

Các thẻ trong HTML khác

Ngoài các thẻ thông dụng nêu trên, còn rất nhiều thẻ HTML khác phục vụ cho những mục đích chuyên biệt hơn:

  • <form>, <input>, <button>: Định nghĩa biểu mẫu và các trường nhập liệu.
  • <meta>: Định nghĩa các siêu dữ liệu của trang.
  • <progress>, <meter>: Hiển thị các thanh tiến độ và các giá trị đo lường.

Việc hiểu và nắm vững các thẻ HTML cơ bản không chỉ là nền tảng cho việc xây dựng trang web mà còn là yếu tố quan trọng giúp cải thiện trải nghiệm người dùng và tối ưu hóa SEO. Từ các thẻ định dạng văn bản, hình ảnh, liên kết đến các thẻ đa phương tiện, mỗi thẻ đều đóng vai trò thiết yếu trong việc tạo ra một trang web trực quan, dễ truy cập và tối ưu hóa cho công cụ tìm kiếm. Hi vọng qua bài viết này của TopDev đã giúp bạn nắm được các thẻ html cơ bản.

Để học và sử dụng html tags dễ dàng hơn, bạn cũng có thể truy cập w3school.com

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

Những thiệt thòi của một lập trình viên

thiệt thòi của lập trình viên
Những thiệt thòi của một lập trình viên

Bài viết được sự cho phép của tác giả Võ Quang Huy

1. Ở những ngành khác thì nữ vừa nhiều vừa xinh đẹp, ngành IT thì …

Điều này ai đã và đang học CNTT ở các trường ĐH đều có thể biết , gái đã ít mà xinh lại càng hiếm. Bản thân mình không phải là dân IT mà học về kĩ thuật , thậm chí số lượng nữ giới còn thấp hơn (Như ở lớp mình thì những ngày 8/3 hay 20/10 chẳng bao giờ tốn tiền hoa cả :v). Mặc dù vậy thì dưới góc độ bản thân cũng là 1 lập trình viên , ở đây mình muốn nói đến những nỗi khổ thầm kín mà nhiều coder phải trải qua trên quan điểm cá nhân + tham khảo chọn lọc.

  Những Nỗi Khổ Của Dân IT Không Phải Ai Cũng Biết
  10 năm đã qua, tại sao vẫn chưa có một ứng dụng nổi bật nào dành cho Blockchain?

2. Khả năng cao phải lập gia đình với người cùng ngành

Nghe có vẻ như hơi mâu thuẫn, đã ít nữ thì làm sao xác suất này cao được. Thế nhưng với những người làm IT thì kể từ lúc đi làm thường nhìn máy tính nhiều hơn giao tiếp với người thật nên thông thường ăn nói kém, giao tiếp kém , (mình không nói 1 số ngoại lệ) , cơ hội gặp phụ nữ khác ngành cũng ít hơn nên thôi thì thế nào cũng xong , có là được (mà gái CNTT thì như đã nói ở trên ) .

3. Sức khỏe giảm sút

Điều này không có gì phải bàn cãi. Thứ nhất ngồi nhiều thì bụng và mông sẽ to. Bụng to thì khó đi lại , chạy nhảy , và khó làm nhiều thứ :v . Ngồi nhiều còn có thể gây ra nhiều bệnh tế nhị khác . Ngoài hai bệnh đằng trước và đằng sau thì còn bệnh ở mắt do nhìn quá nhiều. Đa số người làm IT xung quanh ta đều bị cận thị (mình suýt :v). Gõ máy tính thường xuyên sẽ ảnh hưởng đến tim, rê chuột thường xuyên sẽ thoái hóa cổ tay. Ngoài ra cột sống sẽ bị chai hoặc mọc gai do tật ngồi nhiều hơn đứng của công việc này .

Ngoài ra, dân IT thường có thói quen làm việc, sinh hoạt ban đêm. Cái giờ đáng lẽ những người khác đang ngủ (hoặc làm gì đấy k biết :3) thì các coder lại liên tục luyện tay và thường gây ra bệnh đau bao tử (nói chung là rất nhiều bệnh :v). Tay chân ít hoạt động nên con người thường cảm thấy mỏi mệt, lười vận động, thậm chí cả lười tắm (nên đừng có thắc mắc kiểu 10 vạn câu hỏi tại sao. Nói chung làm cái nghề này nếu ko chịu sinh hoạt… điều độ thì đừng mong thọ và có gấu :v

Vì vậy khuyên ae coder cũng như các thanh niên hay hoạt động về đêm chăm chỉ rèn luyện thể dục thể thao để một người khỏe hai người vui nhá =))

4. Tâm lí không ổn định

Nguyên nhân chính là do stress với công việc . Đặc thù ngành này đòi hỏi phải suy nghĩ nhiều, thức đêm nhiều ,áp lực nhiều , dần dần khiến cơ thể mệt mỏi, thiếu ngủ cộng với căng thẳng khi làm việc sẽ khiến nhiều người bị stress. Theo một số điều tra, thủ phạm gây stress nhiều nhất là email.

Do nhu cầu công việc , khi phải đọc khoảng 100 email một ngày thì người hiền lành cũng trở nên gắt gỏng. Bởi vậy những người làm IT thường hay khó chịu đột xuất.

5. Thường xuyên bị làm phiền bởi người quen

Đây là một trong những điều chắc chắn bạn sẽ gặp phải. Những người quen của bạn: bạn bè, bà con, cô dì chú bác, bạn bố bạn mẹ , họ hàng xa 2 bên nội ngoại ,…  có thể sẽ gọi điện nhờ bạn giúp khi họ cần sửa tivi, máy tính khởi động chậm,  không biết đăng hình lên face =)) … Và phổ biến nhất đó là đi cài win dạo :3 (cái này chắc ai cũng dính) . Kiểu hỗ trợ kỹ thuật miễn phí này nên cẩn thận vì nó sẽ thường xuyên lặp đi lặp lại. Một hai lần thì không sao , nhưng khi đã nhiều lần và cũng nhiều người thì bạn sẽ phát mệt và cảm thấy bị làm phiền , mặc dù toàn là những thứ chẳng liên quan đến công việc của lập trình viên :/  Vì vậy đừng nên việc gì cũng nhận và hãy tập nói không khi có thể .

6. Thường xuyên tăng ca free

Đặc thù của ngành IT là công việc thường không thể tính chính xác bằng giờ. Có nghĩa là không phải cứ một lượng thời gian nào đó thì sẽ làm xong một công việc. Thường chúng ta sẽ phải ở lại thêm 1 giờ, 2 giờ để làm nốt công việc của mình nếu bạn là người có trách nhiệm. Nhưng dù có trách nhiệm hay không thì khi công việc chưa xong mà đã gần đến deadline thì bạn vẫn phải ở lại để hoàn thành những gì còn dở dang, tất nhiên không có xu nào cả .

7. Không phải lúc nào cũng được làm công việc ưa thích

Nhiều sinh viên từng nghĩ ừ thì thôi kệ , thiệt thòi thế , mệt mỏi thế , nhưng khi ra trường được làm việc đúng với đam mê , sở thích , sẽ được áp dụng những kỹ thuật tiên tiến nhất , làm việc với những ngôn ngữ , những công nghệ framework quen thuộc , phù hợp với bản thân , thế là đủ  . Nhưng đời không như mơ :v . Bạn không được quyết định việc sử dụng công nghệ mà mình thích mà phải phụ thuộc hoàn toàn vào dự án , vào công ty (Thức tỉnh thôi :3). Đó là một trong những khó khăn thường gặp nữa của dân CNTT .

8. Nhảy việc không đơn giản

Lương bạn hiện không cao trong khi lương tụi bạn đã gấp hai mình. Đề nghị sếp tăng lương thì sao, liệu sếp có chịu tăng cho mình gấp rưỡi không chứ đừng nói gấp hai. Tại sao không nhảy việc khi vừa có thể có lương cao hơn lại có thể học hỏi nhiều cái mới và làm quen nhiều con người mới. Nhưng khi nhảy việc là lúc bạn phải chấp nhận có thể làm lại từ đầu . Có thể bạn có nhiều kinh nghiệm từ công ty cũ nhưng với đặc thù ngành thì mỗi công ty , mỗi dự án lại có thể sử dụng những công nghệ phát triển khác nhau . Bạn phải bắt đầu lại với công nghệ mới , con người mới , môi trường mới , ban đầu chẳng thể dễ dàng. Vì vậy , nếu tìm được công việc mới với lương gấp rưỡi trở lên thì hãy nhảy, còn không ở lại cho lành và chờ thời cơ. Còn nếu bạn có khả năng và đủ tự tin , có thể tự tách ra và phát triển theo hướng freelancer (làm tốt thì tiền như nước :v nghe nói thế thôi chứ mình cũng chưa đủ trình :v ).

=> Đó là những khó khăn, thiệt thòi, gian khổ của ngành IT dựa vào những gì mình đã trải qua và tìm hiểu được . Làm IT không đơn giản và không sướng chút nào, càng không dễ làm giàu. Thế nên những ai nghĩ  làm IT sướng và lương cao thì nên xem lại và cân nhắc nếu như đang chọn nghề cho mình. Nói chung em cũng còn đang là sinh viên , chém gió chút vui thế thôi , mong ít gạch

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

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

Tìm việc IT lương cao, đãi ngộ tốt trên TopDev

Sửa lỗi .NET Runtime Optimization Services ngốn nhiều CPU, RAM trên Windows

sửa lỗi
Sửa lỗi .NET Runtime Optimization Services ngốn nhiều CPU, RAM trên Windows

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

.NET Framework là một trong những thành phần rất quan trọng có trên hệ điều hành Windows, được phát triển bởi chính Microsoft.

Nếu bạn muốn sử dụng các phần mềm quen thuộc để làm việc với hệ điều hành này thì bắt buộc phải cài đặt đầy đủ .NET Framework.

Vâng, nguyên nhân chính là bởi hầu hết các phần mềm chạy trên Windows hiện nay đều được xây dựng dựa trên nền tảng .NET này.

  Các thành phần trong hệ sinh thái .NET
  List các thuật ngữ căn bản .NET- Bách khoa toàn thư

Tất nhiên, .NET Framework 3.0 thường sẽ được đi kèm khi bạn cài đặt hệ điều hành Windows rồi, vậy nên trong quá trình sử dụng nếu có xảy ra lỗi gì liên quan đến .NET Framework thì bạn chỉ việc cài thêm phiên bản 4.0 nữa là có thể sử dụng được bình thường.

Nhưng đó là trên lý thuyết chứ dạo gần đây Windows 10 của mình hay bị giựt lag do một tiến trình có tên .NET Runtime Optimization Services liên tục chạy và chiếm rất nhiều tài nguyên phần cứng của máy tính (CPU, RAM..).

Vậy .NET Runtime Optimization Services là gì, nó có phải là virus không? Mời các bạn hãy cùng mình đi tìm câu trả lời thông qua bài viết bên dưới đây nhé !

sua-loi-net-runtime-optimization-services-ngon-nhieu-cpu-ram-tren-windows (1)

#1. .NET Runtime Optimization Services là gì? Nó có phải Virus không?

Nếu bạn đã sử dụng Windows 10 từ lâu thì tình trạng đơ, lag máy là chuyện thường xuyên như cơm bữa đúng không, nhất là mấy máy tính còn sử dụng ổ cứng HDD.

Và khi bạn mở Task Manager lên, bạn giật mình thấy một tiến trình có tên .NET Runtime Optimization Services hay mscorsvw.exe đang ngốn rất nhiều CPU và RAM.

Mình thì vừa mới bị xong và sau khi tìm hiểu thì đã quyết định viết ra bài này để chia sẻ, cũng như hướng dẫn các bạn cách khắc phục vấn đề này !

sua-loi-net-runtime-optimization-services-ngon-nhieu-cpu-ram-tren-windows (2)

Giống như .NET Framework được cài sẵn trên Windows 10, .NET Runtime Optimization Services (mscorsvw.exe) cũng là một tiến trình của hệ thống mà người dùng không thể xóa nó đi được.

Vì vậy chúng ta có thể đưa ra kết luận: mscorsvw.exe không phải là một virus hay mã độc gì cả => vấn đề này thì bạn có thể yên tâm rồi nhá !

Còn về chức năng của nó thì chỉ cần nhìn qua cái tên mà Microsoft đặt thôi là chúng ta cũng đủ hiểu rồi, nó có tác dụng là để tối ưu và tăng tốc .NET Framework cùng các ứng dụng dựa trên nền tảng .NET này…

Nó sẽ tối ưu bằng cách biên dịch trước các tập tin của .NET Runtime, từ đó bạn có thể mở và sử dụng các ứng dụng này nhanh hơn.

Bình thường thì .NET Runtime Optimization chỉ chạy nền (chạy ngầm) và chiếm rất ít tài nguyên của hệ thống, nhưng chỉ cần bạn treo máy một lúc (không sử dụng) là ứng dụng này sẽ thừa cơ sử dụng hết sức mạnh phần cứng cho việc biên dịch các tập tin .NET.

Và một khi quá trình này kết thúc, tiến trình này sẽ bị tự tắt đi.

Quá trình biên dịch, tối ưu của .NET Runtime Optimization nhanh hay chậm sẽ phụ thuộc vào số phần mềm sử dụng .NET Framework, kích thước của chúng.. và cái quan trọng nhất vẫn sẽ là cấu hình máy tính của bạn.

Nếu bạn có máy chạy chip i9 9900K + card màn hình RTX2080 + 64GB RAM + ổ cứng SSD NVMe thì quá trình náy sẽ diễn ra rất nhanh (trong tích tắc), nhưng đối với các máy tính cấu hình thấp, sử dụng ổ cứng HDD thì đây đúng là cơn ác mộng, bạn sẽ chẳng làm được gì vì nó cứ giật giật, đơ đơ.

Xem ngay tin tuyển dụng .NET tại các doanh nghiệp hàng đầu trên TopDev

#2. Cách khắc phục tình trạng .NET Runtime Optimization Services ngốn nhiều tài nguyên máy tính

Cách đơn giản để khắc phục tình trạng này đó chính là tắt nó đi, tuy nhiên mình không khuyến khích các bạn làm như vậy, vì việc tắt .NET Runtime Optimization Services sẽ gây hại cho Windows cũng như máy tính của bạn.

Nhưng nếu máy tính bạn cấu hình thấp và chẳng thể làm được gì khác khi nó đang chạy thì buộc phải làm vậy thôi.

Không giống như Antimalware Services Excutable hay một số tiến trình khác, bạn vẫn có thể click chọn mscorsvw.exe => rồi chọn End Task như bình thường để dừng tiến trình này.

Nhưng ngay sau khi bạn vừa bấm End Task thì lại có một tiến trình mới mang tên tương tự nổi lên, và cứ lặp lại như thế cho đến khi nào quá trình tối ưu .NET kết thúc thì nó dừng lại.

Việc bạn liên tục End Task sẽ chỉ làm cho việc tối ưu diễn ra lâu hơn bình thường vì bị gián đoạn liên tục.

sua-loi-net-runtime-optimization-services-ngon-nhieu-cpu-ram-tren-windows (3)

Vậy nên, để tắt hẳn tiến trình .NET Runtime Optimization Services đi thì bạn hãy làm theo hướng dẫn sau đây.

Thực hiện:

+ Bước 1: Đầu tiên, bạn mở hộp thoại Run ra bằng tổ hợp Windows + R => nhập vào lệnh services.msc => rồi bấm vào nút OK để mở công cụ quản lý các dịch vụ trên Windows Services Management Console.

sua-loi-net-runtime-optimization-services-ngon-nhieu-cpu-ram-tren-windows (4)

+ Bước 2: Trong cửa sổ Services này, bạn kéo xuống chữ M và tìm một dịch vụ có tên Microsoft .NET Framework NGEN v2xxxx => rồi double-click chuột lên nó để mở cửa sổ thiết lập dịch vụ trên Windows 10.

Mình phải quay về Windows 7 viết bài hướng dẫn vì sau khi cài mới lại Windows 10 thì tình trạng này của mình đã mất nên không ví dụ cho các bạn được

sua-loi-net-runtime-optimization-services-ngon-nhieu-cpu-ram-tren-windows (5)

+ Bước 3: Ở đây, bạn hãy giữ nguyên ở tab General và nhìn xuống phần Startup-type sẽ thấy nó để mặc định là Manual.

Tức là dịch vụ này sẽ khởi động khi nào hệ thống cần được tối ưu sử dụng .NET Runtime Optimization Services mà thôi, chứ không tự động khởi động cùng Windows.

Bạn hãy click lên menu sổ xuống trong Startup-type và thiếp lập lại thành Disabled => rồi bấm OK để tắt hẳn nó luôn nha.

Bạn có thể bấm luôn nút Stop để dừng dịch vụ này nếu nó đang chạy ngốn tài nguyên của máy tính. Vậy là xong rồi !

sua-loi-net-runtime-optimization-services-ngon-nhieu-cpu-ram-tren-windows (6)

#3. Lời kết

Như vậy là mình vừa hướng dẫn cho các bạn cách khắc phục tình trạng .NET Runtime Optimization Services ngốn RAM và CPU trên hệ điều hành Windows rồi nhé.

Mình cũng không khuyến khích các bạn tắt nó đi đâu nha, mà thay vào đó bạn chỉ cần treo máy một lúc cho nó làm xong nhiệm vụ là được, ngoài ra thì bạn cũng không nên cài quá nhiều phần mềm nếu không thực sự cần thiết nhé.

Hy vọng là bài viết này sẽ có ích cho bạn. Chúc các bạn thành công !

CTV: Nguyễn Thanh Tùng – Bài viết gốc tại blogchiasekienthuc.com

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

Kiến trúc JVM – kiến thức không thể bỏ qua

kiến trúc jvm
Kiến trúc JVM – kiến thức không thể bỏ qua

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

Đã là lập trình viên Java thì không thể không biết về JVM (Java Virtual Machine). Một chương trình Java sẽ được biên dịch ra byte code và thực thi với JRE (Java runtime environment)

  JVM là gì? Định nghĩa JVM
  10 điều mọi nhà phát triển ứng dụng Android nên biết về kiến trúc Architecture

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

1. WORA – HAHA

Tất nhiên, chỉ WORA là có nghĩa WRITE ONE, RUN ANYWHERE. Một chương trình Java sau khi viết có thể chạy ở khắp mọi nơi. Chính Virtual Machine đã giúp ta điều này. Tất cả các class Java đều được compiler thành byte code, quẳng cho JVM thực thi.

2. JVM Architecture Diagram

JVM-architecture-kien-truc Cái wth gì đây vậy?. Rối bùi nhùi lên thế!.

Rất xin lỗi bạn đọc, những ai chưa từng tìm hiểu về kiến trúc JVM. Thề, mới đầu mình nhìn hình cũng ngộp cmn luôn. Ngáo ngơ bm.

Tuy nhiên, sau khi chia nhỏ thành các components để tìm hiểu và liên kết lại với nhau, kiến trúc JVM lại không quá phức tạp và khó hiểu. Hãy cùng tìm hiểu chứng năng và mục đích của từng components nhé.

3. Trời, vậy nó hoạt động như thế nào?

Như hình vẽ ta thấy 3 cục to to, đó chính là ba thành phần cơ bản nhất của JVM. Với tên như sau:

  • Class Loader Subsystem
  • Runtime Data Area
  • Execution Engine
Nhìn thì rối rắm nhưng JVM thực chất được chia thành 3 components chính.

Kiến trúc này tương đương với kiến trúc “xay thịt heo”. Cũng 3 bước thuận theo lẽ tự nhiên.

  • Class Loader Subsystem – chuẩn bị thịt (cạo lông, thui,).
  • Runtime Data Area – chặt, thêm hành, tiêu, tỏi ớt, bla blo.
  • Execution Engine – nấu.

Cách này có vẻ xem ra dễ hiểu và nhớ lâu hơn. Số ba, số ba, mỗi lần thắp hương 3 cây là có thể nhớ ngay tới kiến trúc JVM với 3 components chính.

Tiếp theo đây, hãy cùng phân tích sâu hơn về chức năng của từng thành phần này:

3.1 Class Loader Subsytem

3.1.1 Loading

Tất nhiên, nó là subsytem, chứ không phải sub thì đã là module lớn. =))). Việc loader này trong Java cũng có thứ tự ưu tiên nhất định. Rõ rồi, một application chúng ta làm cũng đủ thứ trong đó (extension, lib, jar, vân vân). Đây chính là lý do chúng ta cần Class Loader. Cũng giải thích luôn tại sao nó lại là bước đầu tiên.

Hãy cùng tìm hiểu bé đầu tiên.

3.1.1.1 Boot Strap ClassLoader

Responsible for loading classes from the bootstrap classpath, nothing but rt.jar. Highest priority will be given to this loader.

Boot Strap ClassLoader chỉ đơn giản là một bộ nạp các class core của Java (java.util, java.lang, …).

Không cần phải nhớ chi quá phức tạp. Boot Strap ClassLoader là nơi các class căn bản nhất được nạp vào. Những lớp này là một phần môi trường thực thi JRE. Tuy nhiên, những thành phần được nạp vào có thể khác nhau tùy thuộc vào JRE.

3.1.1.2 Extension ClassLoader.

Thằng này cũng đơn giản không kém. Nó thực hiện đúng như tên gọi. Extension (những thành phần mở rộng). Trong quá trình làm việc, ta sẽ cần thêm các file jar của các framework khác. Khi bỏ vào thư mục JAVA_HOME/jre/lib/ext , Extension ClassLoader sẽ chịu trách nhiệm load các class này.

3.1.1.3 Application ClassLoader.

Xong, khi load xong thành phần core, load xong extension thì việc cuối cùng là Load Application, những cái chúng ta viết ra.

Vậy là đã xong bước load. Sau khi load xong thì sẽ phải kiểm tra. Cùng tìm hiểu tiếp bước thứ 2: Linking.

3.1.2 Linking.

3.1.2.1 Verify.

Tên gọi y như chức năng, đây là nơi JVM sẽ kiểm tra bytecode đã được load từ bước thứ nhất. Tất nhiên, nếu kiểm tra có lỗi, sẽ trả ra lỗi ngay tại bước này (verification error).

3.1.2.2 Prepare.

Sau khi đã pass qua bước verify, bước tiếp theo sẽ load ra tất cả các biến static được khai báo, các giá trị này sẽ có giá trị default của chúng.

3.1.3 Initialization.

Đây là bước cuối cùng trong việc load class, tất cả các biến được khai báo là static sẽ được gán giá trị, các đoạn code được khai báo static sẽ thực thi.

Công việc khởi tạo class đã xong. Tiếp theo sẽ tới khu vực Runtime Data.

3.2 Runtime Data Area

Tới khu vực quan trọng rồi. Runtime Data chia thành 5 thành phần chính (components)

3.2.1.1 Method Area

3.2.1.2 Heap Area

All the class level data will be stored here, including static variables. There is only one method area per JVM, and it is a shared resource.

Tất cả các lớp (ở bất kì cấp nào) đều được lưu trữ ở đây, bao gồm luôn cả biến static. Method giống với heap, chỉ có duy nhất một phân vùng này trong JVM. Chia sẻ cho nhau.

JVM architecture-kien-trucKiến trúc JVM chia method và method native thành 2 stack riêng biệt nhau.

Tất nhiên, khu vực heap sẽ lưu toàn bộ instance của biến (instance variables). Khai báo mảng (arrays) cũng được lưu trữ tại đây. Một điều đặc biệt là trong kiến trúc JVM thì chỉ có duy nhất một vùng heap.

Dữ liệu lưu ở heap được chia sẻ cho các luồng khác nhau. Do tính chất đa luồng truy cập của heap (multi threads), dữ liệu lưu ở đây không an toàn (có thể bị ghi đè, bị mất mát). Tựu chung, nếu muốn an toàn cho luồng (thread safe), hãy chú ý những gì được lưu ở khu vực này.

Since the Method and Heap areas share memory for multiple threads, the data stored is not thread-safe.

Cả method và Heap đều được chia sẻ cho nhiều threads, dữ liệu được lưu trữ ở đây không an toàn.

3.2.1.3 Stack Area

For every thread, a separate runtime stack will be created. For every method call, one entry will be made in the stack memory which is called as Stack Frame. All local variables will be created in the stack memory.

Đối với tất cả thread, khi runtime chương trình, stack sẽ được khởi tạo. Các method được gọi tới, nó sẽ được cung cấp một frame trên stack. Tất cả các biến địa phương (local variables) cũng sẽ được khởi tạo ở stack.

Đây chính là điểm khác biệt giữa Stack và Heap, xét về độ an toàn dữ liệu. Khi lưu ở Stack, sẽ ít có sự can thiệp, đơn giản ta có thể an tâm hơn khi làm việc với những gì được lưu ở stack.

3.2.1.4 PC Registers

Each thread will have separate PC Registers, to hold the address of current executing instruction once the instruction is executed the PC register will be updated with the next instruction.

Mỗi thread sẽ được lưu trữ ở PC Register, giữ địa chỉ thực thi hiện tại sau khi một lệnh khác đã được thực thi. Thông tin lệnh thực thi cũng sẽ được cập nhật.

3.2.1.5 Native Method stacks

Native Method Stack holds native method information. For every thread, a separate native method stack will be created.

Native Method Stack là nơi dữ toàn bộ thông tin của method. Đối với mỗi thread, nó sẽ tạo ra các method stack riêng biệt cho từng luồng.

3.3 Execution Engine

3.3.1 Interpreter

Tên nghe quen quá, hồi học kỹ thuật lập trình đây mà. Trình thông dịch –

Tất nhiên trình thông dịch (interpreter) cũng có điểm yếu của nó:

The disadvantage of the interpreter is that when one method is called multiple times, every time a new interpretation is required.

Điểm yếu của trình thông dịch là cứ mỗi lần method được gọi thì lại cần phải thông dịch lại.

3.3.2 IT Compiler

Vì đã học cả rồi nên mình không muốn nói sâu. Chỉ muốn phân tích thêm chút xíu về hiệu năng (performance) của compiler.

Trình biên dịch (compiler) khắc phục được điểm yếu của trình biên dịch. Một đoạn mã Java sau khi đã được biên dịch thì lần gọi sau sẽ không phải biên dịch mới.

This native code will be used directly for repeated method calls, which improve the performance of the system.

Đoạn chương trình đã được biên dịch sẽ được tái sử dụng khi method được goi, điều này giúp cải thiện hiệu năng của hệ thống.

3.3.3 Garbage Collector

Cuối cùng, thanh niên dọn rác. Cuộc đời chỉ có một nhiệm vụ cao cả là loại bỏ các object không được sử dụng (unreferenced objects). Ta có thể kích hoạt garbage bằng cách gọi System.gc ()

3.4 Java Native Interface (JNI)

Interface gốc này cung cấp cách thức giao tiếp, hỗ trợ JVM biên dịch bằng cách gọi các Native Method Libraries (phương thức gốc) của Java.

3.5 Native Method Libraries

This is a collection of the Native Libraries which is required for the Execution Engine.

Cuối cùng, Native Method Libraries là một tập các thư viện được yêu cầu cho trình thực thi (Execution Engine).

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

Database migration sử dụng Flyway

database migration
Database migration sử dụng Flyway

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

Mình đã giới thiệu với các bạn về database migration sử dụng Liquibase. Flyway cũng làm được điều tương tự nhưng cách hoạt động đơn giản hơn nhiều. Nó không cần phải sử dụng đến một table lock trong quá trình chạy migration. Cụ thể như thế nào? Hãy cùng nhau tìm hiểu trong bài viết này, các bạn nhé!

  "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 các việc làm Database lương cao trên TopDev

Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:

Database migration sử dụng Flyway

với Flyway và PostgreSQL JDBC driver dependencies như sau:

<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>7.12.0</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.23</version>
</dependency>

Mình cũng sử dụng Java 8 cho ví dụ này:

<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>

Với Flyway thì chúng ta có thể sử dụng tập tin SQL hoặc code Java để hiện thực database migration, thông thường thì mình sử dụng tập tin SQL vì đơn giản hơn rất nhiều. Trong bài viết này, mình sẽ sử dụng tập tin SQL để làm ví dụ, các bạn muốn sử dụng code Java thì có thể đọc thêm ở đây nhé.

Với tập tin SQL thì Flyway, sau khi có connection tới database, sẽ đọc các tập tin SQL này ở một thư mục mà chúng ta cấu hình, mặc định là thư mục src/main/resources/db/migration để làm migration.

Tên của các tập tin SQL cần phải đặt theo một naming convention nhất định các bạn nhé!

Flyway hỗ trợ chúng ta có thể migrate với một version mới cho database structure bằng một tập tin SQL mới hoặc có thể sử dụng chỉ duy nhất một tập tin SQL với repeatable migration hoặc undo một version nào đó. Lưu ý là undo migration chỉ available cho phiên bản Flyway Teams edition các bạn nhé! Các bạn cũng có thể khai báo một tập tin mới và viết SQL script để remove những thông tin mà mình muốn remove, không cần sử dụng undo migration cũng được.

Dưới đây là một ví dụ về tên của tập tin SQL:

  • V2021.07.31.00000__Init nếu thêm version mới
  • R__People_view.sql nếu là repeatable migration
  • U2__Add_people.sql nếu là undo version.

Tên tập tin sẽ bắt đầu với ký tự V hoặc R hoặc U tuỳ theo cách mà các bạn muốn làm migration như ví dụ trên. Tiếp theo sẽ là version, naming convention cho version thì các bạn có thể tham khảo tại đây, mình thì thường sử dụng version theo ngày tháng năm như ví dụ trên.

Ngăn cách giữa 2 phần trong tên của tập tin SQL là 2 ký tự gạch dưới “__”, phần phía sau 2 dấu gạch dưới này là mô tả về thay đổi mà các bạn làm trong tập tin SQL này.

Để làm ví dụ cho bài viết này, mình sẽ tạo mới một tập tin SQL với tên là V2021.08.07.00000__Init với nội dung tạo mới table student như sau:

CREATE TABLE student (
ID INT PRIMARY KEY,
name VARCHAR(250) NOT NULL
);

Bây giờ, mình sẽ tạo mới một main class để xem cách làm việc của Flyway như thế nào các bạn nhé.

Nội dung của class này ban đầu như sau:

package com.huongdanjava.flyway;

public class Application {

public static void main(String[] args) {

}

}

Chúng ta sẽ sử dụng đối tượng của class Flyway, khởi tạo nó cùng với thông tin Datasource kết nối tới database để chuẩn bị làm migration, như sau:

Flyway flyway = Flyway.configure()
.dataSource("jdbc:postgresql://localhost:5432/student", "postgres", "123456")
.load();

Nếu các bạn đã có thông tin Datasource rồi thì cũng có thể sử dụng một phương thức overload khác để sử dụng Datasource này:

Database migration sử dụng Flyway

không cần phải khai báo databaseURL, username và password như mình.

Để chạy migration, chúng ta sẽ gọi phương thức migrate() của đối tượng Flyway như sau:

flyway.migrate();

Bây giờ, nếu chạy ví dụ này, rồi kiểm tra database, các bạn sẽ thấy kết quả như sau:

Database migration sử dụng Flyway

Ngoài table student mà chúng ta đã khai báo trong tập tin SQL, Flyway còn tạo một table khác tương tự như Liquibase để quản lý tất cả các version mà chúng ta đã chạy. Table này tên là flyway_schema_history, dùng để keep track history:

Database migration sử dụng Flyway

Như các bạn thấy, Flyway extract thông tin về version từ tên của tập tin SQL. Nó còn sử dụng một column để lưu trữ checksum của tập tin SQL để kiểm tra tập tin SQL nào đã chạy, tập tin nào chưa. Các bạn không được thay đổi nội dung của những tập tin mà Flyway đã chạy migration, nếu có bất kỳ thay đổi nào thì Flyway sẽ báo lỗi ngay.

Nếu các bạn muốn thêm một version mới thì cứ tạo mới tập tin SQL theo naming convention mà mình đã nói ở trên là được nhé!

Ví dụ mình thêm mới cột address cho student thì mình sẽ tạo mới tập tin SQL với tên V2021.08.07.00001__add_student_address và nội dung như sau:

ALTER TABLE student 
ADD COLUMN address VARCHAR(255);

Kết quả:

Database migration sử dụng Flyway

Các cách lock một property hay object của JS

lock property
Các cách lock một property hay object của JS

Bài viết được sự cho phép của tác giả Lưu Bình An

1. Khóa property của object

Set giá trị một object trong js, chúng ta chỉ cần biết đến property: value

Vậy nếu muốn khóa property này không cho phép chỉnh sửa thì sao?

Mỗi property trong object sẽ được khuyến mãi thêm 3 flag attribute đặc biệt – descriptor

let user = {
    name: "John"
};

let descriptor = Object.getOwnPropertyDescriptor(user, 'name');

console.log(JSON.stringify(descriptor, null, 2));

// kết quả
{
    "value": "John",
    "writable": true,
  	"enumerable": true,
  	"configurable": true
}
  • writable: = true thì chúng ta cập nhập được value
  • enumerable: = true thì khi loop chúng ta sẽ thấy nó
  • configurable: = true thì có thể delete được, các attribute writableenumerable có thể chỉnh sửa
  10 câu hỏi javascript để nâng cao trình độ
  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết

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

Để thay đổi giá trị cho các attribute này, chúng ta thực hiện thông qua hàm Object.defineProperty(obj, propertyName, descriptor)

let user = {}

Object.defineProperty(user, "name", {    value: "John",
    writable: false,    enumerable: false,    configurable: false})

// không còn change giá trị của name được nữa
user.name = "Peter"; 
// Error: Cannot assign to read only property 'name'

// không còn thấy khi loop
for (let key in user) console.log(key)

Ví dụ một property có attribute configurable=false

// tự động gán false hết cho các attribute
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');

/*
{
  "value": 3.141592653589793,
  "writable": false,
  "enumerable": false,
  "configurable": false
}
*/

Math.PI = 3; 
// Error, because it has writable: false

// ko thể thay đổi attribute writable nữa
Object.defineProperty(Math, "PI", { writable: true });
// Error, because of configurable: false

Nếu chỉ set configurable = false thì vẫn thay đổi giá trị được, nó chỉ không cho thay đổi attribute và delete

let user = {
  name: "John"
};

Object.defineProperty(user, "name", {
  configurable: false
});

user.name = "Pete"; // vẫn được
delete user.name; // Error

Nếu muốn khai báo nhiều property cùng lúc, dùng Object.defineProperties()

Object.defineProperties(obj, {
  prop1: descriptor1,
  prop2: descriptor2
  // ...
});

// Ví dụ
Object.defineProperties(user, {
  name: { value: "John", writable: false },
  surname: { value: "Smith", writable: false },
  // ...
});

Lấy tất cả descriptor, Object.getOwnDescriptors(obj)

let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));

2. Khóa toàn bộ object

Để khóa hẳn một object, chúng ta có đến tận 3 phương thức

  • Object.preventExtension(obj) không cho thể các property mới
  • Object.seal(obj) không cho thêm/xóa các property, configurable: false
  • Object.freeze(obj) không cho thêm/xóa/thay đổi property, configurable: false, writable: false

https://javascript.info/

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

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

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

Cần chuẩn bị gì khi phỏng vấn vị trí kỹ sư kiểm thử phần mềm? Trích lọc và trả lời

phỏng vấn kỹ sư kiểm thử phần mềm
Cần chuẩn bị gì khi phỏng vấn vị trí kỹ sư kiểm thử phần mềm? Trích lọc và trả lời

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

Cách đây không lâu tác giả VNTesters có đăng một bài viết với chủ đề “Cần chuẩn bị gì khi phỏng vấn vị trí kỹ sư kiểm thử phần mềm?” và được nhiều bạn đọc quan tâm và thắc mắc sao không có câu trả lời kèm theo. Hôm nay mình xin trích lọc một số câu hỏi thú vị và đưa ra câu trả lời. Những câu hỏi khác không phải là không hay nhưng các bạn hoàn toàn có thể tìm hiểu trên Google. Các bạn có thể đọc toàn bộ câu hỏi ở đây.

  Bí kíp luyện Kỹ sư phần mềm: Đọc code!
  4 ngộ nhận về công việc kiểm thử phần mềm - Trở thành Tester hay Developer?

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

Làm thế nào để đảm bảo chất lượng của sản phẩm phần mềm?

Một câu hỏi thuộc dạng khó và rộng tuy nhiên để tóm gọn thì mình xin trả lời như sau. Để đảm bảo chất lượng của phần mềm theo mình có 2 yếu tố quan trọng: qui trình tốt và nhân lực tốt. Qui trình chỉ những bước, cách thức để làm ra một sản phẩm có chất lượng. Nhân lực chỉ yếu tố con người để thực hiện qui trình đó. Nhân lực bao gồm đội phát triển, đội kiểm thử, phân tích yêu cầu, quản lý dự án, quản lý qui trình, v.v. (tùy theo mô hình có thể sẽ có thêm hoặc bớt). Điều đó có nghĩa là tất cả những bộ phận liên quan trong dự án đều tham gia, đóng góp và chịu trách nhiệm về chất lượng của sản phẩm. Đội kiểm thử đóng vai trò quan trọng trong đảm bảo chất lượng sản phẩm nhưng không phải duy nhất.

Bạn sẽ làm gì nếu bạn không có đủ thời gian để kiểm thử? 

Ngày nay việc đội kiểm thử không có đủ thời gian để kiểm thử cũng không có gì là lạ. Không chỉ riêng đội kiểm thử mà cả đội phát triển, đội phân tích đều bị đặt dưới áp lực thời gian do áp lực cạnh tranh, chi phí. Dĩ nhiên khi chúng ta có ít thời gian hơn chúng ta sẽ phải kiểm thử ít hơn đều đó cũng đồng nghĩa rủi ro chất lượng sản phẩm sẽ bị ảnh hưởng lớn hơn. Để giảm thiểu rủi ro, chúng ta sẽ phải sắp xếp độ ưu tiên cho việc kiểm thử (Risk-based testing). Những trường hợp kiểm thử, thành phần nào quan trọng được kiểm thử trước, cái nào không quan trọng ít rủi ro có thể thực thi sau hoặc có thể cắt bỏ. Chúng ta cũng có thể tận dụng kiểm thử tự động để rút ngắn thời gian thực thi cũng như tăng độ bao phủ cho công việc kiểm thử.

Khi nào bạn nói dự án kiểm thử của bạn hoàn thành? Nêu tên các yếu tố. 

Các bạn có thể tìm hiểu thêm về Exit criteria. Tuy nhiên, theo quan điểm của mình thì việc kiểm thử không bao giờ có khái niệm xong (Các bạn có thể tìm đọc “You are not done yet” của Michael Hunter). Luôn có thứ để chúng ta kiểm thử và mình sẽ dừng việc kiểm thử khi dự án hết tiền hoặc sếp bảo dừng.

Làm thế nào để bạn biết rằng tất cả các kịch bản thử nghiệm được bao phủ (covered)?

Mình cũng không rõ kịch bản thử nghiệm trong ngữ cảnh câu hỏi là gì. Tuy nhiên theo mình hiểu câu hỏi đề cập đến độ bao phủ trong kiểm thử. Độ bao phủ đóng vai trò quan trọng trong kiểm thử đặc biệt là trong quản lý kiểm thử. Tuy nhiên khi nói đến độ bao phủ, chúng ta phải nói độ bao phủ đó được đo dựa trên đơn vị nào. Độ bao phủ của yêu cầu, độ bao phủ của chức năng, độ bao phủ của các loại kiểm thử, độ bao phủ của kỹ thuật kiểm thử, độ bao phủ của trình duyệt v.v. Chúng ta cũng nên lưu ý thông tin về độ bao phủ cũng rất dễ gây nhầm lẫn. Bạn có 100 yêu cầu và bạn đã kiểm thử được 90 yêu cầu vậy độ bao phủ là 90% đối với yêu cầu. Con số 90% nói lên điều gì về chất lượng công việc kiểm thử cũng như chất lượng sản phẩm. Chẳng nói lên điều gì cả. 90% đó sẽ có nghĩa hơn nếu được kết hợp với những thông tin khác như bao nhiêu yêu cầu quan trọng đã được bao phủ, bao nhiêu lỗi đã tìm được trong 90% đó.

Ý kiến của bạn về quan điểm “kiểm thử tự động nâng cao hiệu quả kiểm thử phần mềm”.

Theo quan điểm của mình thì kiểm thử tự động sẽ hỗ trợ trong việc tăng độ bao phủ, giảm thời gian thực thi cũng như giảm thiểu chi phí cho công việc kiểm thử….nếu làm đúng cách.

Bạn có nghĩ rằng kiểm thử tự động có thể thay thế kiểm thử thủ công?

Có và không. Kiểm thử tự động có thể thay thế kiểm thử thủ công ở những công việc mang tính lặp đi lặp lại hay không thể thực thi bằng kiểm thử thủ công. Tuy nhiên, kiểm thử tự động không thể thay thế kiểm thử thủ công chẳng hạn như việc tìm bug hay hỏi những câu hỏi hay.

Mô tả những vấn đề chung của kiểm thử tự động

Kiểm thử tự động mang lại nhiều giá trị cho công việc kiểm thử. Tuy nhiên, cũng như kiểm thử thủ công, kiểm thử tự động cũng có những vấn đề riêng của nó.

1)    Chi phí cao. Chi phí này bao gồm chi phí mua công cụ, chi phí đào tạo hoặc thuê kỹ sư triển khai, chi phí bảo trì.

2)    Kỹ thuật. Việc tương tác giữa công cụ kiểm thử và sản phẩm là một thách thức lớn đối với kiểm thử tự động do sự phát triển nhanh chóng của công nghệ nói chung và công nghệ phát triển phần mềm nói riêng.

3)    Đòi hỏi một nền tảng kiến thức nhất định về coding cũng như phát triển phần mềm. Thực chất, kiểm thử tự động cũng không khác việc phát triển phần mềm là mấy. Chúng tai phải viết thiết kế framework, viết code, thực thi, debug, sửa lỗi v.v. Nhiều công cụ ngày nay với những mô hình tiên tiến hỗ trợ kỹ sư kiểm thử có thể triển khai kiểm thử tự động mà không phải “động” đến code nhiều nhưng vẫn còn nhiều hạn chế.

Có lỗi nào có mức độ nghiêm trọng cao nhưng ưu tiên thấp không (và ngược lại, mức độ nghiêm trọng thấp nhưng độ ưu tiên lại cao)?

Câu trả lời là có. Mình có viết 1 bài về độ ưu tiên, độ nghiêm trọng. Các bạn có thể đọc thêm ở đây.

Đây chỉ là những câu trả lời tham khảo không phải là câu trả lời đúng nhất cũng không chắc đúng. Các bạn có thể chia sẻ câu trả lời của mình bằng cách comment bên dưới để cùng trao đổi.

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

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

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

Cách sử dụng lệnh Xcopy trong CMD (Command Prompt)

lệnh xcopy
Cách sử dụng lệnh Xcopy trong CMD (Command Prompt)

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

Nếu như bạn chưa biết thì Xcopy là một lệnh có trong CMD, nó được sử dụng để copy tệp hoặc thư mục trên hệ điều hành Windows. Sau này ở các phiên bản Windows mới hơn thì Xcopy được thay thế bằng Robocopy.

Tuy nhiên, lệnh Xcopy không bị xóa đi, tức là bạn vẫn có thể sử dụng được lệnh Xcopy quen thuộc này bởi độ tương thích cao của nó.

  Hướng dẫn sử dụng Xcode và Tạo project Xcode
  Tạo thư viện bằng Swift Package Manager trong Xcode

#1. Hướng dẫn cơ bản về xcopy trong CMD

Nếu chỉ copy [tệp] hoặc [thư mục] đơn thuần thì lệnh sẽ đơn giản như sau:

xcopy [Đường-dẫn-file-hoặc-folder-cần-copy] [Đường-dẫn -đến-vị-trí-cần-paste]

Ví dụ mình dùng lệnh xcopy để copy file ghost32.exe từ thư mục Setup ra Desktop thì dùng lệnh như sau:

xcopy D:\Setup\ghost32.exe C:\Users\Admin\Desktop

tim-hieu-ve-lenh-xcopy-trong-cmd (3)

Nếu kết qua là “1 (hoặc nhiều hơn) File(s) copied” thì bạn đã copy tệp hoặc thư mục thành công rùi nha.

//*đọc thêm*//

Vấn đề tiếp theo…………

Nếu bạn muốn ghi đè tệp hoặc thư mục (tức là khi bạn copy tên file hoặc tên thư mục giống nhau) thì sẽ xuất hiện bảng thông báo như sau:

tim-hieu-ve-lenh-xcopy-trong-cmd (1)

Có ba tùy chọn sau:

  • Yes (y): Chấp nhận ghi đè lên file cũ.
  • No (n): Hủy bỏ sao chép, không ghi đè lên file cũ.
  • All (a): Ghi đè lên tất cả các file bị trùng.

=> Bạn nhập các ký hiệu tương ứng => sau đó nhấn Enter để thực hiện lệnh.

Tiếp theo nữa…………

Bạn có thể copy [tệp] hoặc [thư mục] tới đường dẫn không tồn tại. Như vậy, xcopy sẽ tạo cho ta một thư mục hoặc tệp có tên giống như đường dẫn đích.

tim-hieu-ve-lenh-xcopy-trong-cmd (6)

Ví dụ như trong trường hợp này thì Newfolder3 là đường dẫn không tồn tại. Ta có thể thấy được xcopy hỏi rằng muốn tạo tệp hay thư mục không?

  • Nếu chọn thư mục [D], xcopy sẽ tạo ra thư mục với tên đúng với đường dẫn cuối (Newfolder3).
  • Còn nếu chọn tệp [F] thì xcopy sẽ copy tệp nguồn tới đường dẫn cuối tồn tại (Desktop), sau đó đổi tên giống với tên đường dẫn cuối (Newfolder3).

//*hết phần đọc thêm*//

#2. Những điều mà bạn cần lưu ý về lệnh xcopy trong CMD

  • Bạn có thể hủy bất kì lệnh xcopy nào bằng cách nhấn tổ hợp phím Ctrl + C.
  • Nếu bạn không có quyền để sao chép tệp thì sẽ xuất hiện thông báo lỗi Access Denied. Khi đó bạn cần mở CMD bằng quyền Admin để có thể copy tệp. Nếu vẫn không được, thêm tham số /r vào trong lệnh để sửa lỗi này.
  • Khi sao chép tên file phải có thêm phần mở rộng phía sau, nếu không sẽ không thể copy được. Ví dụ mình copy file ghost32.exe nhưng khi dùng lệnh mình chỉ viết là ghost32 thì sẽ bị lỗi và không thể copy được.

tim-hieu-ve-lenh-xcopy-trong-cmd (2)

  • Khi sử dụng xcopy, mặc định tất cả các thuộc tính của file mới được sao chép đều sẽ bị mất. Ví dụ File ghost32.exe của mình có thuộc tính chỉ đọc (Read-only), nhưng sau khi copy ở thư mục mới thì file này sẽ không có thuộc tính chỉ đọc.
  • Mỗi lần dùng xcopy thì chỉ có thể copy được một tệp hoặc thư mục cho mỗi một lệnh.

#3. Các lệnh nâng cao trong xcopy

Lưu ý: Tất cả các tham số như /v/c,… đều phải viết sau “Đường-dẫn-đến-vị-trí-cần-paste” nha.

Đầu tiên ta có thể lọc chỉ copy file hoặc folder có thuộc tính. Ta có thể sử dụng hai lệnh sau để thực hiện trong hai trường hợp như sau:

  • Khi muốn file hoặc folder đích không còn thuộc tính: xcopy /A
  • Khi muốn file hoặc folder đích giữ nguyên thuộc tính: xcopy /M

Tiếp theo, ta có lệnh để cập nhật tệp đã thay đổi bằng cách sử dụng lệnh sau:

xcopy /d:”tháng-ngày-năm hoặc ngày-tháng-năm”

Tác dụng của lệnh này là cho phép ta chỉ sao chép tệp nguồn khi tệp được chỉnh sửa lần cuối, sau ngày mà bạn đã nhập ở bên trên.

Ví dụ mình có file ghost32.exe ở thư mục Setup được chỉnh sửa lần cuối vào ngày 18/6/2021.

tim-hieu-ve-lenh-xcopy-trong-cmd (4)

Và file ghost32.exe ở thư mục Download được chỉnh sửa lần cuối vào ngày 27/6/2021

tim-hieu-ve-lenh-xcopy-trong-cmd (5)

Hiện tại mình muốn thay thế file được chỉnh sửa sau ngày 19/6/2021 thì mình sẽ sử dụng lệnh sau => và nhấn Enter:

xcopy C:\Users\Admin\Downloads\Programs\ghost32.exe D:\Setup\ghost32.exe /d:06-19-2021

tim-hieu-ve-lenh-xcopy-trong-cmd (7)

Tiếp theo ta bấm y để đồng ý ghi đè lên file cũ.

tim-hieu-ve-lenh-xcopy-trong-cmd (9)

Nếu ta chỉ viết /d mà không viết thêm thời gian thì xcopy sẽ chỉ sao chép tệp nếu tệp nguồn được chỉnh sửa lần cuối sau tệp đích.

Bạn có thể tham khảo thêm một vài tham số của xcopy sau đây:

1. xcopy /w: Xác nhận trước khi copy, bấm nút bất kì để bắt đầu copy.

tim-hieu-ve-lenh-xcopy-trong-cmd (10)

2. xcopy /p: Xác nhận trước khi copy, bấm y để đồng ý, n để hủy bỏ.tim-hieu-ve-lenh-xcopy-trong-cmd (11)

3. xcopy /c: Bỏ qua lỗi khi copy, mặc định file bị lỗi sẽ dừng tiến trình copy lại.

4. xcopy /v: Kiểm tra file nguồn và file đích sau khi copy để chắc chắn hai file giống hệt nhau, tránh bị lỗi file hỏng hoặc thiếu sau khi copy (Giống như kiểm tra MD5, SHA-1,…).

5. xcopy /q: Bỏ qua dòng lệnh thông báo đường dẫn nguồn của xcopy khi copy.

dòng lệnh thông báo đường dẫn nguồn
tim-hieu-ve-lenh-xcopy-trong-cmd (12)

6. xcopy /f: Thêm dòng lệnh thông báo đường dẫn đích của xcopy khi copy.tim-hieu-ve-lenh-xcopy-trong-cmd (13)

7. xcopy /l: Bỏ từ “copied” sau kết quả copy.

tim-hieu-ve-lenh-xcopy-trong-cmd (14)

Ngoài ra, bạn có thể thử qua các lệnh như sau:

  1. xcopy /g: Tạo tệp đích được giải mã nếu đích không hỗ trợ mã hóa.
  2. xcopy /u: Chỉ copy tệp nguồn nếu tệp đó đã có ở đích (Lệnh chỉ dùng để ghi đè).
  3. xcopy /i: Nếu tệp đích không tồn tại, tạo thư mục đích với tên của tệp đích và sao chép tệp nguồn vào thư mục đó. Mặc định khi tệp đích không tồn tại thì xcopy sẽ hỏi là tạo tệp nguồn là file hoặc folder.
  4. xcopy /s: Copy thêm các thư mục con trong folder, bỏ qua các thư mục trống. Mặc định xcopy chỉ copy file trong thư mục, bỏ qua các thư mục con trong đó.
  5. xcopy /e: Giống với /s nhưng sẽ copy thêm các thư mục con trống.
  6. xcopy /t: Chỉ sao chép các thư mục con trong folder, bỏ qua tất cả các file, kể cả file trong thư mục con.
  7. xcopy /k: Giữ nguyên thuộc tính Read-only của tệp đích.
  8. xcopy /r: Copy tệp có thuộc tính Read-only. Thường sẽ sử dụng để fix lỗi Access Denied.
  9. xcopy /h: Copy tệp có thuộc tính Hidden hoặc System. Mặc định xcopy sẽ bỏ qua các tệp có thuộc tính trên.
  10. xcopy /a: Giữ nguyên thuộc tính Read-only, Hidden hoặc System của tệp đích. Cần thêm tham số /h hoặc /r để có thể copy.
  11. xcopy /m: Xóa thuộc tính Read-only, Hidden hoặc System của tệp đích. Cần thêm tham số /h hoặc /r để có thể copy.
  12. xcopy /y: Bỏ qua hỏi ghi đè file. Trực tiếp ghi đè tệp khi dùng lệnh này.
  13. xcopy /z: Có thể tiếp tục copy tệp nếu bị mất kết nối đường dẫn nguồn hoặc đích.
  14. xcopy /j: Sao chép tệp không lưu vào bộ nhớ đệm. Nên dùng với file lớn. Chỉ có thể sử dụng từ Windows Server 2008 R2 về sau.

#4. Lời kết

Như vậy là mình đã hướng dẫn xong cho các bạn gần như là tất cả các lệnh xcopy trong CMD rồi nhé.

Hi vọng là bạn sẽ thích bài viết này, đừng quên ghé thăm Blog Chia Sẻ Kiến Thức mỗi ngày để học hỏi thêm nhiều kiến thức thú vị khác 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