Hướng dẫn Java Design Pattern – Object Pool

Lập Trình
Hướng dẫn Java Design Pattern – Object Pool
Bài viết được sự cho phép của tác giả Giang Phan Trong OOP, một class có thể có rất nhiều instance nhưng ngược lại Singleton là một dạng class mà chỉ hỗ trợ tối đa một instance duy nhất và một đối tượng khi đã được khởi tạo sẽ tồn tại suốt vòng đời chương trình. Trong một số trường hợp, chúng ta cần khởi tạo và sử dụng một tập hợp các đối tượng. Khi với số lượng lớn các đối tượng giống nhau, thì việc khởi tạo nhiều lần sẽ gây lãng phí không cần thiết. Chúng ta cũng có thể sử dụng Prototype Pattern để cãi thiện performance bằng cách cloning object. Tuy nhiên, không phải lúc nào object cũng có thể được clone đầy đủ. Trong những trường hợp như vậy, chúng ta có thể dùng Object pool pattern . Object Pool Pattern là gì? Object Pool Pattern là một trong những Creational pattern . Nó không nằm trong danh sách các Pattern được giới thiệu bởi GoF . Object Pool Pattern cung cấp một kỹ thuật để tái sử dụng objects thay vì khởi tạo không kiểm soát. Ý tưởng của Object Pooling là: chúng ta dùng Object Pool Pattern quản lý một tập hợp các objects mà sẽ được tái sử dụng trong chương trình. Khi client cần sử dụng object, thay vì tạo ra một đối tượng mới thì client chỉ cần đơn giản yêu cầu Object pool lấy một đối tượng đã có sẵn trong object pool. Sau khi object được sử dụng nó sẽ không hủy mà sẽ được trả về pool cho client khác sử dụng. Nếu tất cả các object trong pool được sử dụng thì client phải chờ cho tới khi object được trả về pool. Object pool...

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

Trong OOP, một class có thể có rất nhiều instance nhưng ngược lại Singleton là một dạng class mà chỉ hỗ trợ tối đa một instance duy nhất và một đối tượng khi đã được khởi tạo sẽ tồn tại suốt vòng đời chương trình. Trong một số trường hợp, chúng ta cần khởi tạo và sử dụng một tập hợp các đối tượng. Khi với số lượng lớn các đối tượng giống nhau, thì việc khởi tạo nhiều lần sẽ gây lãng phí không cần thiết. Chúng ta cũng có thể sử dụng Prototype Pattern để cãi thiện performance bằng cách cloning object. Tuy nhiên, không phải lúc nào object cũng có thể được clone đầy đủ. Trong những trường hợp như vậy, chúng ta có thể dùng Object pool pattern.

Object Pool Pattern là gì?

Object Pool Pattern là một trong những Creational pattern. Nó không nằm trong danh sách các Pattern được giới thiệu bởi GoF. Object Pool Pattern cung cấp một kỹ thuật để tái sử dụng objects thay vì khởi tạo không kiểm soát.

Ý tưởng của Object Pooling là: chúng ta dùng Object Pool Pattern quản lý một tập hợp các objects mà sẽ được tái sử dụng trong chương trình. Khi client cần sử dụng object, thay vì tạo ra một đối tượng mới thì client chỉ cần đơn giản yêu cầu Object pool lấy một đối tượng đã có sẵn trong object pool. Sau khi object được sử dụng nó sẽ không hủy mà sẽ được trả về pool cho client khác sử dụng. Nếu tất cả các object trong pool được sử dụng thì client phải chờ cho tới khi object được trả về pool.

Object pool thông thường hoạt động theo kiểu: tự tạo đối tượng mới nếu chưa có sẵn hoặc khởi tạo trước 1 object pool chứa một số đối tượng hạn chế trong đó.

Cài đặt Object Pool Pattern như thế nào?

Java Design Pattern – Object PoolJava Design Pattern – Object Pool

Cài đặt

Một Object Pool Pattern bao gồm các thành phần cơ bản sau:

  • Client : một class yêu cầu khởi tạo đối tượng PooledObject để sử dụng.
  • PooledObject : một class mà tốn nhiều thời gian và chi phí để khởi tạo. Một class cần giới hạn số lượng đối tượng được khởi tạo trong ứng dụng.
  • ObjectPool : đây là lớp quan trọng nhất trong Object Pool Pattern. Lớp này lưu giữ danh sách các PooledObject đã được khởi tạo, đang được sử dụng. Nó cung cấp các phương thức cho việc lấy đối tượng từ Pool và trả đối tượng sau khi sử dụng về Pool.

Tham khảo việc làm Fresher Java mới nhất trên Station D

Ví dụ Object Pool thông qua ứng dụng Taxi

Một hãng taxi A chỉ hữu hạn N chiếc taxi, hãng taxi chịu trách nhiệm quản lý trạng thái các xe (đang rảnh hay đang chở khách), phân phối các xe đang rảnh đi đón khách, chăm sóc, kéo dài thời gian chờ đợi của khách hàng cho trong trường hợp tất cả các xe đều đang bận (để chờ một trong số các xe đó rảnh thì điều đi đón khách luôn), hủy khi việc chờ đợi của khách hàng là quá lâu.

Ta mô phỏng và thiết kế thành các lớp sau:

  • Taxi: đại diện cho một chiếc taxi, là một class định nghĩa các thuộc tính và phương thức của một taxi.
  • TaxiPool: Đại diện cho công ty taxi, có:
    • Phương thức getTaxi() : để lấy về một thể hiện Taxi đang ở trạng thái rảnh, có thể throw ra một exception nếu chờ lâu mà không lấy được thể hiện.
    • Phương thức release() : để trả thể hiện Taxi về Pool sau khi đã phục vụ xong.
    • Thuộc tính available : lưu trữ danh sách Taxi rãnh, đang chờ phục vụ.
    • Thuộc tính inUse : lưu trữ danh sách Taxi đang bận phục vụ.
  • ClientThread: đại diện cho khách hàng sử dụng dịch vụ Taxi, mô phỏng việc gọi, chở và trả khách.

Java Design Pattern – Object PoolJava Design Pattern – Object Pool

Trong đoạn code bên dưới, tôi sẽ cài đặt mô phỏng với TaxiPool quản lý được 4 taxi, cùng lúc có 8 cuộc gọi của khách hàng đến công ty để gọi xe, thời gian mỗi taxi đến địa điểm chở khách là 200ms, mỗi taxi chở khách trong khoảng thời gian từ 1000ms đến 1500ms (ngẫu nhiên), mỗi khách hàng chịu chờ tối đa 1200ms trước khi hủy.

Taxi:

package com.gpcoder.patterns.creational.objecpool.taxi;

public class Taxi {

    private String name;

    public Taxi(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Taxi [name=" + name + "]";
    }
}

TaxiPool:

package com.gpcoder.patterns.creational.objecpool.taxi;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Lazy pool
 * 
 * @author gpcoder
 */
public class TaxiPool {

    private static final long EXPIRED_TIME_IN_MILISECOND = 1200; // 1.2s
    private static final int NUMBER_OF_TAXI = 4;

    private final List<Taxi> available = Collections.synchronizedList(new ArrayList<>());
    private final List<Taxi> inUse = Collections.synchronizedList(new ArrayList<>());

    private final AtomicInteger count = new AtomicInteger(0);
    private final AtomicBoolean waiting = new AtomicBoolean(false);

    public synchronized Taxi getTaxi() {
        if (!available.isEmpty()) {
            Taxi taxi = available.remove(0);
            inUse.add(taxi);
            return taxi;
        }
        if (count.get() == NUMBER_OF_TAXI) {
            this.waitingUntilTaxiAvailable();
            return this.getTaxi();
        }
        Taxi taxi = this.createTaxi();
        inUse.add(taxi);
        return taxi;
    }

    public synchronized void release(Taxi taxi) {
        inUse.remove(taxi);
        available.add(taxi);
        System.out.println(taxi.getName() + " is free");
    }

    private Taxi createTaxi() {
        waiting(200); // The time to create a taxi
        Taxi taxi = new Taxi("Taxi " + count.incrementAndGet());
        System.out.println(taxi.getName() + " is created");
        return taxi;
    }

    private void waitingUntilTaxiAvailable() {
        if (waiting.get()) {
            waiting.set(false);
            throw new TaxiNotFoundException("No taxi available");
        }
        waiting.set(true);
        waiting(EXPIRED_TIME_IN_MILISECOND);
    }

    private void waiting(long numberOfSecond) {
        try {
            TimeUnit.MILLISECONDS.sleep(numberOfSecond);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }
}

ClientThread:

package com.gpcoder.patterns.creational.objecpool.taxi;

import java.util.Random;
import java.util.concurrent.TimeUnit;

public class ClientThread implements Runnable {

    private TaxiPool taxiPool;

    public ClientThread(TaxiPool taxiPool) {
        this.taxiPool = taxiPool;
    }

    @Override
    public void run() {
        takeATaxi();
    }

    private void takeATaxi() {
        try {
            System.out.println("New client: " + Thread.currentThread().getName());
            Taxi taxi = taxiPool.getTaxi();

            TimeUnit.MILLISECONDS.sleep(randInt(1000, 1500)); 

            taxiPool.release(taxi);
            System.out.println("Served the client: " + Thread.currentThread().getName());
        } catch (InterruptedException | TaxiNotFoundException e) {
            System.out.println(">>>Rejected the client: " + Thread.currentThread().getName());
        }
    }

    public static int randInt(int min, int max) {
        return new Random().nextInt((max - min) + 1) + min;
    }
}

TaxiNotFoundException:

package com.gpcoder.patterns.creational.objecpool.taxi;

public class TaxiNotFoundException extends RuntimeException {

    private static final long serialVersionUID = -6670953536653728443L;

    public TaxiNotFoundException(String message) {
        System.out.println(message);
    }
}

TaxiApp:

package com.gpcoder.patterns.creational.objecpool.taxi;

public class TaxiApp {

    public static final int NUM_OF_CLIENT = 8;

    public static void main(String[] args) {
        TaxiPool taxiPool = new TaxiPool();
        for (int i = 1; i <= NUM_OF_CLIENT; i++) {
            Runnable client = new ClientThread(taxiPool);
            Thread thread = new Thread(client);
            thread.start();
        }
    }
}

Kết quả thực thi chương trình trên:

New client: Thread-0
New client: Thread-1
New client: Thread-2
New client: Thread-3
New client: Thread-4
New client: Thread-5
New client: Thread-6
New client: Thread-7
Taxi 1 is created
Taxi 2 is created
Taxi 3 is created
Taxi 4 is created
Taxi 1 is free
Served the client: Thread-1
Taxi 2 is free
Served the client: Thread-7
No taxi available
>>>Rejected the client: Thread-0
Taxi 3 is free
Served the client: Thread-6
Taxi 4 is free
Served the client: Thread-5
Taxi 2 is free
Served the client: Thread-4
Taxi 1 is free
Served the client: Thread-3
Taxi 3 is free
Served the client: Thread-2

Nhận xét:

  • Ưu điểm của việc cài đặt Pool là việc tận dụng được các tài nguyên đã được cấp phát. Với ví dụ về taxi ở trên với 4 taxi, trong nhiều trường hợp vẫn có thể đáp ứng được nhiều hơn 4 yêu cầu cùng một lúc. Nó làm tăng hiệu năng hệ thống ở điểm không cần phải khởi tạo quá nhiều thể hiện (trong nhiều trường hợp việc khởi tạo này mấy nhiều thời gian), tận dụng được các tài nguyên đã được khởi tạo (tiết kiệm bộ nhớ, không mất thời gian hủy đối tượng).
  • Việc cài đặt Pool có thể linh động hơn nữa bằng cách đặt ra 2 giá trị N và M. Trong đó: N là số lượng thể hiện tối thiểu (trong những lúc rảnh rỗi), M là số thể hiện tối đa (lúc cần huy động nhiều thể hiện nhất mà phần cứng đáp ứng được). Sau khi qua trạng thái cần nhiều thể hiện, Pool có thể giải phóng bớt một số thể hiện không cần thiết.

Xem tin tuyển dụng Java mới nhất trên Station D

Ví dụ Object Pool thông qua Connection Pooling

Khi làm việc với cơ sở dữ liệu hay cho những hệ thống tương đối lớn ở các công ty, thì vấn đề performance rất quan trọng. Nếu mỗi request đến chúng ta phải mở và đóng kết nối thủ công thì rất khó quản lý, điều quan trọng hơn nữa đó là cứ mỗi lần open và close connection mất khoảng từ 2-3s thì chắc chắn rằng hiệu năng hoạt động của ứng dụng web không tốt. Để giải quyết được vấn đề này, chúng ta sẽ dùng kỹ thuật connection pool để quản lý và chia sẻ số kết nối. Connection Pool cũng là một trong các ứng dụng của Object Pool Pattern.

Connection pooling là gì?

Connection pool (vùng kết nối) : là kỹ thuật cho phép tạo và duy trì 1 tập các kết nối dùng chung nhằm tăng hiệu suất cho các ứng dụng bằng cách sử dụng lại các kết nối khi có yêu cầu thay vì việc tạo kết nối mới.

Cách làm việc của Connection pooling?

Connection Pool Manager (CPM) là trình quản lý vùng kết nối, một khi ứng dụng được chạy thì Connection pool tạo ra một vùng kết nối, trong vùng kết nối đó có các kết nối do chúng ta tạo ra sẵn. Và như vậy, một khi có một request đến thì CPM kiểm tra xem có kết nối nào đang rỗi không? Nếu có nó sẽ dùng kết nối đó còn không thì nó sẽ đợi cho đến khi có kết nối nào đó rỗi hoặc kết nối khác bị timeout. Kết nối sau khi sử dụng sẽ không đóng lại ngay mà sẽ được trả về CPM để dùng lại khi được yêu cầu trong tương lai.

Ví dụ

Một connection pool có tối đa 10 connection trong pool. Bây giờ user kết nối tới database (DB), hệ thống sẽ kiểm tra trong connection pool có kết nối nào đang rảnh không?

  • Trường hợp chưa có kết nối nào trong connection pool hoặc tất cả các kết nối đều bận (đang được sử dụng bởi user khác) và số lượng connection trong connection < 10 thì sẽ tạo một connection mới tới DB để kết nối tới DB đồng thời kết nối đó sẽ được đưa vào connection pool.
  • Trường hợp tất cả các kết nối đang bận và số lượng connection trong connection pool = 10 thì người dùng phải đợi cho các user dùng xong để được dùng.

Sau khi một kết nối được tạo và sử dụng xong nó sẽ không đóng lại mà sẽ duy trì trong connection pool để dùng lại cho lần sau và chỉ thực sự bị đóng khi hết thời gian timeout (lâu quá không dùng đến nữa).

Chi tiết các bạn tham khảo thêm tại link sau: https://ejbvn.wordpress.com/category/week-2-entity-beans-and-message-driven-beans/day-09-using-jdbc-to-connect-to-a-database/

Source code về cách tạo Connection Pool các bạn tham khảo thêm tại đây: https://sourcemaking.com/design_patterns/object_pool/java

Ví dụ Object Pool thông qua Thread Pool

Thread Pool cũng là một trong các ứng dụng của Object Pool Pattern.

Tạo ra một Thread mới là một hoạt động tốn kém bởi vì nó đòi hỏi hệ điều hành cung cấp tài nguyên để có thể thực thi task (tác vụ). ThreadPool được dùng để giới hạn số lượng Thread được chạy bên trong ứng dụng của chúng ta trong cùng một thời điểm.

Thay vì tạo các luồng mới khi các task (nhiệm vụ) mới đến, một ThreadPool sẽ giữ một số luồng nhàn rỗi (no task) đã sẵn sàng để thực hiện tác vụ nếu cần. Sau khi một thread hoàn thành việc thực thi một tác vụ, nó sẽ không chết. Thay vào đó nó vẫn không hoạt động trong ThreadPool và chờ đợi được lựa chọn để thực hiện nhiệm vụ mới.

Chi tiết về Thread Pool các bạn có thể xem lại ở bài viết này: https://gpcoder.com/3548-huong-dan-tao-va-su-dung-threadpool-trong-java/

Một vài lưu ý khi triển khai Object Pool

Xác định số lượng tối đa các đối tượng được khởi tạo trong Pool?

Tùy vào ứng dụng, chúng ta cần xác định con số này sao cho hợp lý để đảm bảo không khởi tạo quá dư thừa đối tượng gây lãng phí tài nguyên, hay quá ít làm cho các ứng dụng client phải chờ lâu hay bị lỗi.

Thời gian timeout?

Để quản lý thời gian timeout bạn cần xác định:

  • Khi một đối tượng không được sử dụng trong một thời gian xác định có cần thiết hủy bỏ để giải phóng tài nguyên hay không? Chẳng hạn: nếu giới hạn số lượng tối thiểu là 4, số lượng tối đa là 100. Điều này có nghĩa là có ít nhất 4 đối tượng sẵn dùng trong Object Pool, tối đa là 100 đối tượng được tạo ra và được quản lý trong pool. Đối tượng không được sử dụng sau khoảng thời gian timeout, thì sẽ được hủy bỏ cho tới khi còn lại 4 đối tượng.
  • Khi một client giữ một object quá lâu mà không trả về object pool thì có cần thiết set timeout để trả về cho đối tượng khác sử dụng không? Chẳng hạn: một client1 cần sử dụng object trong khoảng thời gian 10 phút, một client2 cần sử dụng trong 20 giây. Khi client1 yêu cầu sử dụng trước, nếu không set timeout thì client2 phải chờ 10 phút mới được sử dụng trong 20 giây.
  • Khi một client chờ quá lâu thì sẽ xử lý như thế nào? Chờ đến khi có tài nguyên sử dụng hay sẽ throw ngoại lệ.

Làm gì khi Pool không chứa đối tượng nào?

Chúng ta có thể sử dụng một trong ba chiến lược để xử lý một yêu cầu từ client khi trong object pool không chứa đối tượng nào (rỗng):

  • Tạo mới: khởi tạo thêm một đối tượng mới và trả về cho client nếu nó chưa vượt quá số lượng đối tượng được phép khởi tạo.
  • Chờ: Trong một môi trường đa luồng, một object pool có thể block các yêu cầu từ client cho đến khi một luồng khác trả về một đối tượng có thể sử dụng vào object pool.
  • Trả lỗi: không cung cấp một đối tượng và ngay lập tức trả lại lỗi cho client. Hoặc chờ một khoảng thời gian (timeout) và trả lại lỗi cho client.

Đảm bảo trạng thái của object không bị thay đổi khi trả về Object Pool?

Khi triển khai mô hình Object pool, chúng ta phải cẩn thận để đảm bảo rằng trạng thái của các đối tượng quay trở lại object pool phải được đặt ở trạng thái hợp lý cho việc sử dụng tiếp theo của đối tượng. Nếu không kiểm soát được điều này, đối tượng sẽ thường ở trong một số trạng thái mà chương trình client không mong đợi và có thể làm cho chương trình client lỗi (failed), không nhất quán, rò rỉ thông tin.

Lợi ích của Object Pool Pattern là gì?

  • Tăng hiệu suất của ứng dụng.
  • Hiệu quả trong một vài tình huống mà tốc độ khởi tạo một object là cao.
  • Quản lý các kết nối và cung cấp một cách để tái sử dụng và chia sẻ chúng.
  • Có thể giới hạn số lượng tối đa các đối tượng có thể được tạo ra.

Sử dụng Object Pool Pattern khi nào?

Objects pool được sử dụng khi:

  • Khi cần tạo và hủy một số lượng lớn các đối tượng trong thời gian ngắn, liên tục.
  • Khi cần sử dụng các object tương tự thay vì khởi tạo một object mới không có kiểm soát.
  • Các đối tượng tốn nhiều chi phí để tạo ra.
  • Khi có một số client cần cùng một tài nguyên tại các thời điểm khác nhau.

Một vài thư viện sử dụng Object Pool trong Java:

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 Station D

Bài viết liên quan

Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Lĩnh vực EdTech (ứng dụng công nghệ vào các sản phẩm giáo dục) trên toàn cầu hiện nay đã tương đối phong phú với nhiều tên tuổi lớn phân phối đều trên các hạng mục như Broad Online Learning Platforms (nền tảng cung cấp khóa học online đại chúng – tiêu biểu như Coursera, Udemy, KhanAcademy,…) Learning Management Systems (hệ thống quản lý lớp học – tiêu biểu như Schoology, Edmodo, ClassDojo,…) Next-Gen Study Tools (công cụ hỗ trợ học tập – tiểu biểu như Kahoot!, Lumosity, Curriculet,…) Tech Learning (đào tạo công nghệ – tiêu biểu như Udacity, Codecademy, PluralSight,…), Enterprise Learning (đào tạo trong doanh nghiệp – tiêu biểu như Edcast, ExecOnline, Grovo,..),… Hiện nay thị trường EdTech tại Việt Nam đã đón nhận khoảng đầu tư khoảng 55 triệu đô cho lĩnh vực này nhiều đơn vị nước ngoài đang quan tâm mạnh đến thị trường này ngày càng nhiều hơn. Là một trong những xu hướng phát triển tốt, và có doanh nghiệp đã hoạt động khá lâu trong ngành nêu tại infographic như Topica, nhưng EdTech vẫn chỉ đang trong giai đoạn sơ khai tại Việt Nam. Tại Việt Nam, hệ sinh thái EdTech trong nước vẫn còn rất non trẻ và thiếu vắng nhiều tên tuổi trong các hạng mục như Enterprise Learning (mới chỉ có MANA), School Administration (hệ thống quản lý trường học) hay Search (tìm kiếm, so sánh trường và khóa học),… Với chỉ dưới 5% số dân công sở có sử dụng một trong các dịch vụ giáo dục online, EdTech cho thấy vẫn còn một thị trường rộng lớn đang chờ được khai phá. *** Vừa qua Station D đã công bố Báo cáo Vietnam IT Landscape 2019 đem đến cái nhìn toàn cảnh về các ứng dụng công...

By stationd
Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bài viết được sự cho phép của tác giả Chung Nguyễn Hôm nay, nhóm Laravel đã phát hành một phiên bản chính mới của “ laravel/installer ” bao gồm hỗ trợ khởi động nhanh các dự án Jetstream. Với phiên bản mới này khi bạn chạy laravel new project-name , bạn sẽ nhận được các tùy chọn Jetstream. Ví dụ: API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth Cách sử dụng Laravel với Socket.IO laravel new foo --jet --dev Sau đó, nó sẽ hỏi bạn thích stack Jetstream nào hơn: Which Jetstream stack do you prefer? [0] Livewire [1] inertia > livewire Will your application use teams? (yes/no) [no]: ... Nếu bạn đã cài bộ Laravel Installer, để nâng cấp lên phiên bản mới bạn chạy lệnh: composer global update Một số trường hợp cập nhật bị thất bại, bạn hãy thử, gỡ đi và cài đặt lại nha composer global remove laravel/installer composer global require laravel/installer Bài viết gốc được đăng tải tại chungnguyen.xyz Có thể bạn quan tâm: Cài đặt Laravel Làm thế nào để chạy Sql Server Installation Center sau khi đã cài đặt xong Sql Server? Quản lý các Laravel route gọn hơn và dễ dàng hơn Xem thêm Tuyển dụng lập trình Laravel hấp dẫn trên Station D

By stationd
Principle thiết kế của các sản phẩm nổi tiếng

Principle thiết kế của các sản phẩm nổi tiếng

Tác giả: Lưu Bình An Phù hợp cho các bạn thiết kế nào ko muốn làm code dạo, design dạo nữa, bạn muốn cái gì đó cao hơn ở tầng khái niệm Nếu lập trình chúng ta có các nguyên tắc chung khi viết code như KISS , DRY , thì trong thiết kế cũng có những nguyên tắc chính khi làm việc. Những nguyên tắc này sẽ là kim chỉ nam, nếu có tranh cãi giữa các member trong team, thì cứ đè nguyên tắc này ra mà giải quyết (nghe hơi có mùi cứng nhắc, mình thì thích tùy cơ ứng biến hơn) Tìm các vị trí tuyển dụng designer lương cao cho bạn Nguyên tắc thiết kế của GOV.UK Đây là danh sách của trang GOV.UK Bắt đầu với thứ user cần Làm ít hơn Thiết kế với dữ liệu Làm mọi thứ thật dễ dàng Lặp. Rồi lặp lại lần nữa Dành cho tất cả mọi người Hiểu ngữ cảnh hiện tại Làm dịch vụ digital, không phải làm website Nhất quán, nhưng không hòa tan (phải có chất riêng với thằng khác) Cởi mở, mọi thứ tốt hơn Bao trừu tượng luôn các bạn, trang Gov.uk này cũng có câu tổng quát rất hay Thiết kế tốt là thiết kế có thể sử dụng. Phục vụ cho nhiều đối tượng sử dụng, dễ đọc nhất nhất có thể. Nếu phải từ bỏ đẹp tinh tế – thì cứ bỏ luôn . Chúng ta tạo sản phẩm cho nhu cầu sử dụng, không phải cho người hâm mộ . Chúng ta thiết kế để cả nước sử dụng, không phải những người đã từng sử dụng web. Những người cần dịch vụ của chúng ta nhất là những người đang cảm thấy khó sử dụng dịch...

By stationd
Applicant Tracking System là gì? ATS hoạt động ra sao

Applicant Tracking System là gì? ATS hoạt động ra sao

Công nghệ phát triển hướng đến giải quyết và cải tiến cho mỗi quy trình, hoạt động của doanh nghiệp cũng như đời sống. Đối với lĩnh vực tuyển dụng, sự xuất hiện của phần mềm ATS (Applicant Tracking System) mang đến nhiều thay đổi đáng kể, cả đối với nhà tuyển dụng và ứng viên. Vậy phần mềm ATS là gì? Chúng được sử dụng ra sao? Những thắc mắc về phần mềm ATS trong tuyển dụng sẽ được Station D giải đáp tại bài viết dưới đây. Hệ thống sàng lọc ứng viên ATS (Applicant Tracking System) Applicant Tracking System là gì? Applicant Tracking System (ATS) hay còn gọi là Hệ thống quản lý hồ sơ ứng viên là phần mềm quản lý quy trình tuyển dụng từ đầu đến cuối một cách tự động hóa. ATS được thiết kế để giúp nhà tuyển dụng tiết kiệm thời gian và chi phí trong việc thu thập, sắp xếp và sàng lọc hồ sơ các ứng viên. Các tính năng nổi bật của Applicant Tracking System Các tính năng nổi bật của Applicant Tracking System Applicant Tracking System (ATS) là một công cụ quan trọng giúp các công ty quản lý quy trình tuyển dụng hiệu quả hơn. Cùng chúng tôi điểm qua các tính năng nổi bật của ATS: Sàng lọc và quản lý hồ sơ ứng viên Khả năng tìm kiếm và sàng lọc ứng viên là một trong các tính năng nổi bật nhất của ATS. Với việc sử dụng từ khóa và tiêu chí cụ thể, hệ thống có thể nhanh chóng tìm kiếm và sàng lọc các hồ sơ phù hợp, tự động loại bỏ những ứng viên không đạt yêu cầu. Điều này giúp nhà tuyển dụng tập trung vào những ứng viên...

By stationd
Hiểu về trình duyệt – How browsers work

Hiểu về trình duyệt – How browsers work

Bài viết được sự cho phép của vntesters.com Khi nhìn từ bên ngoài, trình duyệt web giống như một ứng dụng hiển thị những thông tin và tài nguyên từ server lên màn hình người sử dụng, nhưng để làm được công việc hiển thị đó đòi hỏi trình duyệt phải xử lý rất nhiều thông tin và nhiều tầng phía bên dưới. Việc chúng ta (Developers, Testers) tìm hiểu càng sâu tầng bên dưới để nắm được nguyên tắc hoạt động và xử lý của trình duyệt sẽ rất hữu ích trong công việc viết code, sử dụng các tài nguyên cũng như kiểm thử ứng dụng của mình. Cách để npm packages chạy trong browser Câu hỏi phỏng vấn mẹo về React: Component hay element được render trong browser? Khi hiểu được cách thức hoạt động của trình duyệt chúng ta có thể trả lời được rất nhiều câu hỏi như: Tại sao cùng một trang web lại hiển thị khác nhau trên hai trình duyệt? Tại sao chức năng này đang chạy tốt trên trình duyệt Firefox nhưng qua trình duyệt khác lại bị lỗi? Làm sao để trang web hiển thị nội dung nhanh và tối ưu hơn một chút?… Hy vọng sau bài này sẽ giúp các bạn có một cái nhìn rõ hơn cũng như giúp ích được trong công việc hiện tại. 1. Cấu trúc của một trình duyệt Trước tiên chúng ta đi qua cấu trúc, thành phần chung và cơ bản nhất của một trình duyệt web hiện đại, nó sẽ gồm các thành phần (tầng) như sau: Thành phần nằm phía trên là những thành phần gần với tương tác của người dùng, càng phía dưới thì càng sâu và nặng về xử lý dữ liệu hơn tương tác. Nhiệm...

By stationd
Tối ưu tỉ lệ chuyển đổi với Google Optimize và Google Analytics

Tối ưu tỉ lệ chuyển đổi với Google Optimize và Google Analytics

Tối ưu tỷ lệ chuyển đổi là một trong những yếu tố quan trọng mà một Growth Marketer không thể bỏ qua. Google Analytics là công cụ hữu hiệu và phổ biến nhất giúp chúng ta theo dõi, đo lường và tối ưu tỷ lệ chuyển đổi. Số liệu từ Google Analytics giúp chúng ta nhìn ra điểm cần thay đổi để tăng tỷ lệ chuyển đổi. Theo dõi chuyển đổi là quá trình thiết yếu nhưng cũng rất “khó nhằn”. Ngày nay, mọi người đang sử dụng điện thoại di động nhiều hơn và thường xuyên hơn khi mua hàng trực tuyến. Việc tối ưu hóa website phiên bản di động rất quan trọng. Traffic đến từ mobile khá lớn và làm ảnh hưởng nhiều tới tỷ lệ chuyển đổi. Để xem website của bạn có hoạt động tốt trên mobile hay không như thế nào? Làm gì khi tỷ lệ chuyển đổi giảm? Website phiên bản di động của bạn có nội dung hấp dẫn không? Không có những nút điều hướng hành động? Trang bị lỗi …, những điều này có thể ảnh hưởng tới tỉ lệ chuyển đổi Google Analytics, hiểu được điều này, bạn sẽ có cơ sở để khắc phục và hoàn thiện website của mình. Hãy cùng đến với chủ đề “DÙNG GOOGLE ANALYTICS TỐI ƯU TỈ LỆ CHUYỂN ĐỔI TRÊN MOBILE” với sự chia sẻ của diễn giả Nguyễn Minh Đức, CEO IM GROUP tại Vietnam Mobile Day 2018 nhé

By stationd