Home Blog Page 51

Database developer là gì? Kỹ năng cần có của Database Developers

Database developer là gì? Kỹ năng cần có của Database Developers

Anh em khi tìm hiểu Database Developer chắc chắn là có biết về database (hệ cơ sở dữ liệu). Nhìn sơ cái tên có thể đoán ra Database Developer là lập trình viên liên quan tới cơ sở dữ liệu. Nhưng có phải ông lập trình viên này ăn rồi ngồi viết query lấy data này, xoá dữ liệu kia?

Mà khác với anh em Frontend Developers hay Backend Developers. Suốt ngày ngồi lò mò với dữ liệu vậy có sinh ra nhàm chán quá mà trầm cảm không?

database-developer-la-gi
Ăn uống thoải mái xong bật Caplocks viết SQL thui hở chời?
Tất cả những câu hỏi, thắc mắc của anh em về Database Developer sẽ được làm rõ qua bài viết này. Ok, bắt đầu thôi nào!.

1. Database Developer cụ thể là làm gì?

Tất nhiên rồi, không có định nghĩa không hình dung được Database Developer là làm gì đâu?

“Database Developers commonly work to a process known as the Software Development Life Cycle (SDLC), which contains six stages: analysis, design, development and testing, implementation, documentation, and evaluation. They work in the IT department of tech–driven organisations in a broad range of industries.”

Database Developer thường làm việc cho một quy trình thường gọi là Quy trình phát triển phần mềm (SDLC), bao gồm sau quá trình chính là phân tích, thiết kế, phát triển và kiểm thử, hiện thực, tài liệu và đánh giá. Họ làm việc trong IT department của nhiều nghành công nghiệp. Họ cũng có thể làm việc tự do cho một loạt khách hàng khác nếu muốn.

À rồi, vậy Database developers vẫn tham gia vào quá trình phát triển phần mềm như những anh em khác trong đội Frontend, Backend hay Product Owner. Nhưng focus vào hệ cơ sở dữ liệu.

Không phải chỉ ăn rồi ngồi rõ query. Một số nhiệm vụ chính của DB Developer bao gồm:

  • Thiết kế hệ cơ sở dữ liệu (Designing database systems – cái này không dễ đâu nha).
  • Tạo và cập nhật tài liệu liên quan tới hệ cơ sở dữ liệu (Creating and updating database documentation).
  • Thu thập yêu cầu của dự án bằng cách liên hệ với các bên có liên quan (Gathering project requirements by liaising with stakeholders).

database-developer-la-gi

Anh em nhớ chỉ là một số nhiệm vụ chính thôi nha. Trong thực tế Database Developer có thể tham gia vào quá trình kiểm thử phần mềm. Bản thân có thể kết hợp mượt mà với QC (quality control) vì bản thân ông Database Developer hiểu rất rõ về dữ liệu hệ thống.

Ngoài ra phần tài liệu về hệ cơ sở dữ liệu cũng quan trọng không kém. Dùng loại nào, có function, có function hay store procedure nào không? Database trigger như nào?,… Tất cả đều được ghi vào tài liệu rõ ràng và cụ thể.

  Dùng Python viết hàm xử lý dữ liệu dưới tầng database cho PostgreSQL

  Quản lý realm database theo hướng micro-service trong iOS

2. Vai trò, vị trí của DB Developers

Rõ ràng là dữ liệu là thứ sống còn với bất cứ ứng dụng hay hệ thống nào. Dữ liệu là thứ quý giá, được bảo vệ kỹ càng. Mà đã là người làm việc với thứ quý giá thì auto trở nên quan trọng đúng không anh em?.

Là người trực tiếp làm việc với Database (hệ cơ sở dữ liệu), tham gia vào quá trình thiết kế hệ cơ sở dữu liệu. Database developers có vai trò vô cùng quan trọng trong dự án.

database-developer-la-gi

Thiết kế hệ cơ sở dữ liệu mà không đúng hoặc không adapt được với requirement thì xem như ứng dụng không thể hoàn thành.

Nếu thiết kế hệ cơ sở dữ liệu bị sai mà vẫn đem vào vận hành thì còn thảm hoạ hơn, khi dữ liệu đã là production mà nó còn sai thì anh em chỉ có đường ngồi nhìn.

Anh em Backend developer cần có data test hoặc có câu queries này chạy chậm, hay query chưa đúng business (lấy ra đúng thứ cần lấy) thì biết hỏi ai. Có Database developer thì còn nói gì nữa.

Rồi chị QC cần có dữ liệu để mock test nhưng mà nhìn vào danh sách một đống bảng biểu thư từ thì chị ấy tiền đình ra (do một phần ở nhà có con nhỏ, phóng đại lên tý cho điêu thôi). Mà tạo mock data thì nhờ ai. Lại nhờ Database developer chứ ai?

Một số ví dụ trên cho ta biết Database developer là một vị trí quan trọng trong quá trình phát triển phần mềm. Vậy giờ muốn trở thành Database developer thì cần có những kỹ năng nào?

Đây, có ngay đây!

Tham khảo Jobs Database Developer hấp dẫn trên TopDev

3. Các kỹ năng cần có của Database Developers

Tất nhiên là mỗi vị trí đều đòi hỏi những kỹ năng riêng. Database Developer cũng vậy. Đã liên quan tới hệ cơ sở dữ liệu thì sẽ yêu cầu những kỹ năng làm việc với DB.

Cụ thể liệt kê đưới đây:

  • Hiểu biết về SQL, T-SQL và PL/SQL, DB2 – Proficient knowledge of SQL, T-SQL and PL / SQL, DB2
  • Kinh nghiệm với Oracle database – Experience with Oracle databases
  • Hiểu biết về hệ cơ sở dữ liệu NoSQL – Knowledge of non-relational databases like NoSQL
  • Chuẩn bị data – Knowing how to prepare data
  • Ước lượng tiền – Ability to perform cost calculations
  • Integratioin hệ thống và kiểm thử chất lượng – system integration and quality testing
  • Hiểu biết về hệ điều hành như Windows hoặc Linux – Knowledge of operating systems like Windows and Linux
  • Hiểu biết về ngôn ngữ lập trình như C++ hay Java – Knowledge of programming languages ​​like C ++, Java, C#, etc.
  • Hiểu biết về HTML – Experience with page description languages ​​like HTML

database-developer-la-gi
Hiểu biết về nhiều loại hình cơ sở dữ liệu luôn là một điểm cộng. Mà hiểu là hiểu sâu nha

3.1 Nice to have – có thêm càng tốt

Ủa gì có code Java, C++ luôn hở? Tất nhiên rồi anh em ơi, vẫn cần có tư duy lập trình và tốt nhất là nên biết một ngôn ngữ lập trình nào đó. Kỹ sư hệ thống hay kiến trúc phần nhiều họ cũng từ developers đi lên. Nên cũng biết về code, như bài viết về Data Analyist cũng có phân tích với anh em về điểm này rồi.

database-developer-la-gi

Phía trên chỉ viết về Oracle với database. Nhưng anh em nếu có kinh nghiệm với các hệ cơ sở dữ liệu khác như Postgres, MySQL, MariaDB càng tốt.

Một số kỹ năng khác nếu có thì là điểm cộng lớn như:

  • Chuẩn bị dữ liệu test – Kiểu mock data phục vụ cho IT (Integrations test), RT (Regression test)
  • Migration data từ hệ cơ sở dữ liệu này qua hệ cơ sở dữ liệu khác (từ Oracle qua Postgres, …). Trước nhớ có đợt Oracle đắt qua các công ty thường chuyển qua hệ cơ sở dữ liệu Postgres.

4. Con đường cho Database Developers

Nói về hiểu biết thì mức độ hiểu biết về hệ cơ sở dữ liệu của Database developer nhất thiết phải sâu và rộng hơn so với Backend developer. Kinh nghiệm về thiết kế DB cũng phải dày dặn hơn. Những kinh nghiệm này có được do đã trải qua nhiều lần sai trước đó về mặt dữ liệu.

Về hướng đi thi Database develops có thể chuyển qua Data Analytics, Computer Science hoặc Solution Architect nếu muốn. Tất nhiên các hướng đi về Computer Science đòi hỏi nỗ lực lớn để học thêm (không những về kinh nghiệm làm việc mà còn các kiến thức khác về toán học).

database-developer-la-gi

Nếu lựa chọn theo hướng Solutions Architect thì cần kinh nghiệm code và hiểu biết rộng hơn về ngôn ngữ lập trình và hệ thống. SA đòi hỏi cái nhìn và góc nhìn bao quát rộng, không chỉ gói gọn ở hệ cơ sở dữ liệu.

5. Tham khảo

Cảm ơn anh em đã đón đọc – Thank you for your time – Happy coding!

Tác giả: Kiên Nguyễn

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

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

Top 10 câu hỏi phỏng vấn Java Developer thường gặp

Top 10 câu hỏi phỏng vấn Java Developer thường gặp

Trong top những ngôn ngữ lập trình phổ biến thì Java luôn luôn có một vị trí vững chắc; cũng vì thế mà nhu cầu tuyển dụng Java Developer luôn cao cho bất cứ lĩnh vực nào. Để chuẩn bị cho một buổi phỏng vấn vị trí lập trình viên Java, bài viết hôm nay mình cùng các bạn liệt kê ra top 10 câu hỏi phỏng vấn Java Developer thường gặp nhất cùng cách trả lời cụ thể nhé.

Câu 1: Bạn có thể nói gì về Java?

Java là một ngôn ngữ lập trình bậc cao, hướng đối tượng, dựa trên class (lớp); được phát triển bởi Sun Microsystems từ những năm 1995, hiện nay thuộc sở hữu của Oracle. Đặc điểm nổi bật nhất của Java là khả năng cho phép các nhà phát triển ứng dụng viết code một lần và có thể chạy ở mọi nơi. Để làm được điều này thì các ứng dụng Java sẽ được biên dịch thành bytecode, sau đó chạy trên nền máy ảo JVM đã được cài sẵn trên nền tảng hệ điều hành.

Cú pháp của Java tương tự như C và C++; phiên bản mới nhất hiện nay là Java 19 phát hành tháng 9/2022. Java được sử dụng trong đa dạng các lĩnh vực:

  • Desktop Application
  • Web Application
  • Enterprise Application (phổ biến như các nghiệp vụ ngân hàng)
  • Mobile Application
  • Hệ thống nhúng
  • Robotic, Smarthome
  • Game

  Top 10 câu hỏi phỏng vấn JavaScript cực chi tiết

  Top 7 câu hỏi phỏng vấn Backend Developer

Câu 2: Các tính năng nổi trội của Java

Những tính năng nổi trội của ngôn ngữ lập trình Java:

  • Hướng đối tượng: tất cả trong Java đều là Object nên có thể dễ dàng mở rộng
  • Nền tảng độc lập: Java biên dịch source code thành bytecode  chạy trên nền tảng máy ảo JVM và không phụ thuộc vào nền tảng hệ điều hành
  • Đa luồng: Java hỗ trợ đa luồng, tức là chương trình viết ra có thể thực hiện nhiều tác vụ cùng lúc
  • Dễ học, dễ hiểu: Java có cú pháp dựa trên C/C++, đồng thời loại bỏ các tính năng phức tạp và hiếm sử dụng; có tính năng tự động hủy cấp phát bộ nhớ,… giúp người học dễ đọc, dễ hiểu code.
  • Bảo mật cao: việc chạy bên trong một máy ảo JVM giúp các chương trình Java khó bị can thiệp tác động, ngoài ra Java có sẵn các lớp giúp chương trình của bạn bảo mật tốt hơn: Classloader, Bytecode Verifier, Security Manager
  • Tính phân tán: Java tạo điều kiện cho người dùng tạo những ứng dụng phân tán bằng RMI và EJB, nó giúp chúng ta có thể truy cập đến các tệp bằng cách gọi phương thức từ bất kỳ máy nào trên Internet

Tham khảo việc làm Java Fresher không yêu cầu kinh nghiệm!

Câu 3: Phân biệt JVM, JDK, JRE

JVM: Java Virtual Machine là máy ảo để thực thi các Java bytecode. Để chạy chương trình Java thì bắt buộc bạn phải cài đặt JVM trên máy của bạn (mỗi hệ điều hành sẽ có phiên bản khác nhau); sau đó source code Java được biên dịch thành bytecode và chuyển vào chạy trên nền JVM

JRE: Java Runtime Environment là môi trường thực thi Java, nó chính là trình triển khai JVM cùng với các plugins, thư viện cần thiết để thực thi chương trình

JDK: Java Development Kit là bộ công cụ phát triển ứng dụng Java. Nó chứa JRE, trình biên dịch bytecode cùng các công cụ hỗ trợ khác về debug, doc. Để lập trình Java chúng ta cần cài đặt JDK

Nói tóm lại:

JDK = JRE + Development Tool

JRE = JVM + Library Classes

Câu 4: Lập trình hướng đối tượng là gì?

Lập trình hướng đối tượng (OOP – Object Oriented Programming) là một phương pháp lập trình dựa trên khái niệm về lớp và đối tượng. Đối tượng ở đây là thể hiện của 1 lớp, bao gồm các thuộc tính và phương thức. OOP bao gồm 4 tính chất:

  • Tính đóng gói: che giấu thông tin quan trọng của 1 lớp
  • Tính đa hình: 1 hành động có thể thực hiện theo nhiều cách khác nhau
  • Tính trừu tượng: ẩn các triển khai chi tiết và chỉ hiển thị tính năng với người dùng
  • Tính kế thừa: khả năng tái sử dụng thuộc tính và phương thức của lớp

Java là một ngôn ngữ lập trình hướng đối tượng, mọi thứ trong Java đều là một đối tượng; vì thế trong hầu hết các bài giảng, khóa học về OOP thì luôn dùng Java làm ngôn ngữ thực hành.

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

Câu 5: Phạm vi truy cập trong Java gồm những gì?

Trong Java, có 4 từ khóa xác định phạm vi truy cập (access specifiers) gồm:

  • Public (công khai): cho phép truy cập vào bất kỳ lớp nào hoặc thông qua bất kỳ phương thức nào thông qua tên của chúng
  • Private (riêng tư): chỉ cho phép truy cập trong chính lớp mà chúng chỉ định.
  • Protected (bảo vệ): cho phép truy cập từ trong lớp, từ một lớp con hoặc từ lớp chung gói
  • Default (mặc định): phạm vi tiêu chuẩn, chỉ cho phep truy cập từ cùng một gói

Câu 6: Có những kiểu dữ liệu nào trong Java. Autoboxing và Unboxing là gì?

Trong Java có 8 kiểu dữ liệu cơ bản (Primitive Type):

  • byte
  • short
  • int
  • long
  • float
  • double
  • boolean
  • char

Trong Java, tất cả đều là Object; vì thế trong quá trình biên dịch, Java sẽ tự động chuyển đổi giữa kiểu dữ liệu cơ bản (Primitive Type) về đối tượng tương ứng với lớp (Wrapper class) của kiểu dữ liệu đó. Chẳng hạn int chuyển sang lớp Integer, kiểu double chuyển sang Double, … Quá trình này gọi là Autoboxing. Và ngược lại để chuyển từ Integer về int, gọi là Unboxing.

Câu 7: Thread trong Java là gì?

Trong Java, quá trình thực thi một chương trình gọi là Process; một Process có thể có nhiều thực thi đơn bên trong gọi là Thread (luồng). 

Một Thread có thể có những trạng thái sau:

  • New: khi tạo 1 lớp instance của lớp Thread và chưa gọi phương thức start
  • Runnable: trạng thái Thread sẵn sàng thực thi
  • Running: đang xử lý code trong Thread
  • Non-Runable (Blocked): trạng thái khi Thread vẫn còn tồn tại nhưng không thể chạy do không đủ điều kiện. Nó bao gồm việc bị blocked trên I/O và blocked trên Synchronization.
  • Terminated: Thread kết thúc

Câu 8: Deadlock là gì? Làm sao để tránh nó.

Deadlock là một trạng thái xảy ra khi có 2 process A và B cùng thực hiện, trong đó A cần chờ B thực hiện xong để chạy tiếp và đồng thời B cũng chờ A thực hiện xong mới có thể chạy tiếp. Kết quả là cả 2 process A và B đều không thể chạy được, chờ nhau vô thời hạn.

Để tránh deadlock, có 1 số cách xử lý như sau:

  • Tránh Nested Locks: không cấp khóa cho nhiều thread
  • Tránh cấp khóa không cần thiết
  • Sử dụng Thread.join set timeout cho Thread

Câu 9: Các interface cơ bản của Collections

Java Collections framework sử dụng để thao tác dữ liệu dạng tập hợp các objects. Có gồm các interface sau:

  • Collection: lớp cơ bản nhất chứa các phương thức làm việc với tập hợp objects như duyệt qua các phần tử
  • Set: mỗi phần tử trong tập hợp chỉ xuất hiện một lần duy nhất
  • List: danh sách tuyến tính sắp xếp theo một thứ tự nhất định
  • Queue: hàng đợi, kiểu dữ liệu FIFO (first-in first-out) vào trước ra trước
  • Map: đồ thị, ánh xạ lưu trữ dạng key-value

Lưu ý là Set, Lis, Queue đều kế thừa Collection; riêng Map thì là một interface độc lập với chỉ những phương thức riêng nó.

Câu 10: Garbage Collectors là gì?

Bộ thu gom rác Garbage Collectors là một quá trình thụ động thực thi nhiệm vụ quản lý bộ nhớ trong Java. Trong quá trình chạy chương trình Java, các đối tượng được tạo ra ở vùng nhớ heap (một phần bộ nhớ dành cho chương trình), sau đó nếu đối tượng không được sử dụng đến nữa thì garbage collectors sẽ truy tìm và xóa bỏ để thu hồi dung lượng bộ nhớ.

Nếu một object được set reference null thì đối tượng đó sẽ được đánh dấu là sẵn sàng cho viện thu gom rác trong chu kỳ hoạt động tiếp theo của Garbage Collectors. Để khởi động việc dọn rác, chúng ta có thể sử dụng các methods System.gc hoặc Runtime.gc

Kết bài

Trên đây là 10 câu hỏi thường gặp nhất trong một cuộc phỏng vấn vị trí Java Developer, hy vọng bài viết này mang lại cho bạn sự chuẩn bị tốt nhất, sẵn sàng đáp ứng yêu cầu của công ty tuyển dụng. Cảm ơn các bạn đã đọc bài, hẹn gặp lại trong các bài viết tiếp theo của mình.

Tác giả: Phạm Minh Khoa

Xem thêm:

Tìm việc làm IT lương cao, đãi ngộ hấp dẫn trên TopDev!

Phân biệt save, persist, update, merge, saveOrUpdate trong hibernate

Phân biệt save, persist, update, merge, saveOrUpdate trong hibernate

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

Ở bài này chúng ta sẽ thảo luận về sự khác nhau giữa vài method của Session interface: save, persist, update, merge, saveOrUpdate.

(Các framework ORM khác có thể không dùng interface session mà dùng interface entityManager nên sẽ có sự khác nhau giữa tên của các method)

1. Session là 1 cài đặt của Persitence Context

Session interface có một và method thực hiện lưu dữ liệu vào database như persist, save, update, merge, saveOrUpdate. Để hiểu sự khác nhau giữa những method này trước hết ta cần phải hiểu mục đích của Session interface và các trạng thái/quan hệ của 1 thể hiện entity với Session

Chúng ta cũng nên hiểu một chút về lịch sử phát triển của Hibernate, điều gì dẫn tới sự trùng lặp một số API method.

1.1. Quản lý các thể hiện entity

Ngoài mối quan hệ giữa các object, một vấn đề khác được Hibernate dự định giải quyết là vấn đề quản lý các entity trong thời gian chạy (runtime). Khái nhiệm “persistence context” là giải pháp của Hibernate cho vấn đề này. Persistence context có thể hiểu như là 1 container hoặc mức cache đầu tiên cho tất cả các object mà ta đã tải hoặc save vào database trong 1 session.

Session là 1 lý luận transaction, nó bao là ranh giới để định nghĩa logic nghiệp vụ của ứng dụng của bạn. Khi bạn làm việc với database thông qua một persistence context và tất cả các thể hiện entity đều được gán với context, bạn nên có 1 thể hiện phân biệt của entity cho mỗi bản ghi database mà bạn giao tiếp trong suốt suốt session.

Trong Hibernate, persistence context được thể hiện bới  org.hibernate.Session. Với JPA, nó là javax.persistence.EntityManager.

  Cài đặt và sử dụng Hibernate

  Các Annotation của Hibernate

1.2 Các trạng thái của 1 thể hiện Entity

Trong 1 Session persistence context, các entity có 4 trạng thái:

  • transient: đối tượng chưa bao giờ bị quản lí bởi session và nó không tương ứng với bản ghi nào trong database; thông thường đây là 1 đối tượng mới được tạo để save vào database
  • persistent: đối tượng bị quản lý bởi session và là unique (trong 1 session không thể tồn tại 2 object có cùng id), sau khi flush bởi session sẽ tồn tại 1 bản ghi tương ứng đối tượng này trong database.
  • detached: đối tượng này đã từng bị quản lý bởi session nhưng hiện tại thì không. (bị evict(), clear(), close())
  • removed:cũng giống như detached nhưng bản ghi tương ứng với đối tượng này trước đó đã bị xóa khỏi database. (bị remove())

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

Các trạng thái của 1 thể hiện Entity

1.3. Sự phù hợp với đặc tả của JPA

Hibernate là cài đặt ORM Java thành công nhất. Không ngạc nhiên khi mà các đặc tả cho Java persistence API (JPA) bị ảnh hưởng nhiều bởi Hibernate API. Cũng không ngạc nhiên khi Hibernate là ORM Framework phổ biến nhất.

Để thực hiện các cài đặt theo chuẩn của JPA, nhiều Hibernate API phải sửa lại. Một vài method được thêm vào Session interface để khớp với EntityManager interface. Những method này phục vụ các mục đích giống với method gốc.

2. Sự khác nhau giữa các hành động thực thi

Các method persist, save, update, merge, saveOrUpdate không lập tức đưa ra kết quả tương ứng SQL UPDATE hoặc INSERT. Thực tế thì việc cập nhật dữ liệu vào database xảy ra khi transaction được commit hoặc flushing session.

2.1. Persist

Method persist được dùng để thêm 1 thể hiện entity mới vào persistence context (ví dụ chuyển trạng thái của entity từ transient sang persistent

Chúng ta thường gọi method này khi chúng ta muốn thêm 1 bản ghi vào database:

Person person = new Person();
person.setName("John");
session.persist(person);

Điều gì xảy ra sau khi method persist được gọi? Đối tượng person bị đổi trạng thái từ transient sang persistent. Đối tượng vào trong persistence context nhưng vẫn chưa được lưu vào database. Thông thường lệnh INSERT sẽ chỉ xuất hiện khi commit transaction hoặc flushing/close session.

Lưu ý rằng persist method trả về kiểu void.

Ý nghĩa của method persist:

  • Thay đổi trạng thái 1 đối tượng từ transient sang persistent (và thực hiện cascades tới tất cả các relations của nó nếu cascade = PERSIST hoặc cascade = ALL)
  • Nếu đối tượng đã là persistent thì nó không làm gì cả (nhưng vẫn thực hiện cascades tới tất cả các relations của nó nếu cascade = PERSIST hoặc cascade = ALL)
  • Nếu đối tượng là detached nó sẽ xảy ra exception khi gọi method hoặc khi commit hoặc khi flushing session.
Person person = new Person();
person.setName("John");
session.persist(person);

session.evict(person);

session.persist(person); // PersistenceException!

2.2. Save

Method save là một method gốc trong đặc tả của JPA

Mục đích cơ bản của method save giống với persist, tuy nhiên nó có sự khác nhau trong cài đặt chi tiết. Tài liệu cho method này nhấn mạnh rằng nó persists 1 thể hiện (hiểu nôm na là nó sẽ tạo ra 1 định danh mới cho thể hiện)

Person person = new Person();
person.setName("John");
Long id = (Long) session.save(person);

Nó khác với method persist khi bạn cố gắng save 1 thể hiện detached:

Person person = new Person();
person.setName("John");
Long id1 = (Long) session.save(person);

session.evict(person);
Long id2 = (Long) session.save(person);

Giá trị của id2 sẽ khác với id1. Khi gọi method save 1 thể hiện detached nó sẽ tạo ra 1 thể hiện persistent và chỉ định cho một định danh/id mới. Kết quả là tạo ra 2 bản ghi vào database khi commit hoặc flushing.

2.3. Merge

Mục đích chính của method merge là update một thể hiện entity có trạng thái persistent vào 1 một thể hiện entity có trạng thái detached.

Trong ví dụ dưới đây, chúng ta eviect(detach) 1 entity đã saved, thay đổi name và merge.

Person person = new Person(); 
person.setName("John"); 
session.save(person);

session.evict(person);
person.setName("Mar

Person mergedPerson = (Person) session.merge(person);

Lưu ý rằng method merge trả về 1 đối tượng, đó là đối tượng đã được merge không phải đối tượng truyền vào.

2.4. Update

Cũng giống như method persist và save, method update là method gốc trong đặc tả JPA
Nó giống với method merge và đã có từ khá lâu trước khi method merge được thêm vào, 1 số ý nghĩa khác của method update là:
  • Trả về kiểu void, thay đổi trạng thái của object truyền vào từ detached sang persistent
Person person = new Person();
person.setName("John");
session.save(person);
session.evict(person);

person.setName("Mary");
session.update(person);

Xảy ra exception nếu bạn truyền vào 1 đối tượng transient.

Person person = new Person();
person.setName("John");
session.update(person); // PersistenceException!

 2.5. saveOrUpdate

Method saveOrUpdate chỉ xuất hiện trong Hibernate API và không có

Điểm khác chính của method saveOrUpdate là nó không xảy ra exception khi truyền vào 1 đối tượng transient. Thay vì đó, nó sẽ tạo ra 1 thể hiện persistent

Person person = new Person();
person.setName("John");
session.saveOrUpdate(person);

3. Kết luận

Chúng ta đã thảo luận mục đích của sự khác nhau trong các method của Hibernate Session. Các trạng thái của object trong persistence context, sự chuyển đổi giữa các trạng thái và tại sao lại có các method có chức năng giống nhau. Phân biệt save, persist, update, merge, saveOrUpdate trong hibernate.

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

Cách xây dựng ThreadLocal trong Java

Cách xây dựng ThreadLocal trong Java

Bài viết được sự cho phép của tác giả Trần Văn Dem

ThreadLocal là một công cụ rất mạnh mẽ của Java Concurrent. Nó cung cấp API để lưu data trên từng Thread, các Thread tự quản lý data của mình. Khi cần dùng thì không cần phải khởi tạo lại dữ liệu mà có thể lấy ra dùng trực tiếp mà không cần khởi tạo lại đối tượng từ đó giúp tiết kiệm thời gian.

Chúng ta thường hay sử dụng các loại API sau :

  • public T get() : dùng để lấy dữ liệu lưu trong Thread.
  • public void set(T value) : dùng để lưu dữ liệu vào Thread.

Tuy nhiên sau khi đọc code của Java tôi nhận thấy ThreadLocal không tối ưu cho 2 loại API này. Cụ thể tôi đã search trên mạng và thấy một bài khá hay về FastThreadLocal của netty.

  Tránh lỗi ConcurrentModificationException trong Java như thế nào?

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

Các bạn tham khảo tại link sau. Dưới đây tôi xin giải thích đơn giản như sau.

Đầu tiên hãy phân tích hàm set của Java.


        public void set(T value) {
                Thread t = Thread.currentThread();
                ThreadLocalMap map = getMap(t);
                if (map != null)
                    map.set(this, value);
                else
                    createMap(t, value);
        }

        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }

        /**
         * Set the value associated with key.
         *
         * @param key the thread local object
         * @param value the value to be set
         */
        private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
        /**
         * Increment i modulo len.
         */
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }

Như thường lệ thì Java sẽ sử dụng Array để lưu giá trị của một Map. Khác với HashMap sử dụng LinkedList hoặc BTree để lưu giá trị của Key khi bị trùng HashCode để đảm bảo được khi lấy dữ liệu ra sẽ được O(1). Tại ThreadLocal với implement bên trên ta thấy như sau:

  • Khi 2 key không trùng mã HashCode thì các key được lưu tại vị trí int i = key.threadLocalHashCode & (len-1); điều này đảm bảo được việc set,get đạt độ phức tạp O(1)
  • Khi 2 key trùng mã HashCode thì sẽ tìm vị trí liền kề tiếp theo trong table mà tại đó giá trị bằng null, sau đó gán value vào vị trí đó. Điều này dẫn đến khi ta dùng phương thức get,set không còn đạt được độ phức tạp O(1) nữa. Điều này sẽ dẫn đến key tiếp theo của bạn đã bị 1 key khác không trùng mã hashcode dữ vị trí đó.

Đừng bỏ lỡ việc làm Java hấp dẫn trên TopDev

Tiếp theo ta đến phương thức get của ThreadLocal.


    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
        /**
         * Get the entry associated with key.  This method
         * itself handles only the fast path: a direct hit of existing
         * key. It otherwise relays to getEntryAfterMiss.  This is
         * designed to maximize performance for direct hits, in part
         * by making this method readily inlinable.
         *
         * @param  key the thread local object
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }
            /**
             * Version of getEntry method for use when key is not found in
             * its direct hash slot.
             *
             * @param  key the thread local object
             * @param  i the table index for key's hash code
             * @param  e the entry at table[i]
             * @return the entry associated with key, or null if no such
             */
            private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
                Entry[] tab = table;
                int len = tab.length;

                while (e != null) {
                    ThreadLocal<?> k = e.get();
                    if (k == key)
                        return e;
                    if (k == null)
                        expungeStaleEntry(i);
                    else
                        i = nextIndex(i, len);
                    e = tab[i];
                }
                return null;
            }

ThreadLocal sẽ tìm rất nhanh nếu không bị trùng HashCode nhưng vấn đề sẽ tăng lên khi chúng ta bị trùng mã HashCode, khi đó ThreadLocal sẽ phải duyệt qua 1 lượt các phần tử lưu trong table để tìm ra key,value chính xác điều này sẽ mất rất nhiều thời gian. Vì vấn đề này netty đã xây dựng 1 class FastThreadLocal riêng nhằm tối ưu phương pháp get,set bạn có thể tìm tại blog.

Để dùng FastThreadLocal của netty ta phải import thư viện netty vào project điều đó có thể gây lãng phí vì vậy tại đây tôi sẽ dựa trên ý tưởng của netty xây dụng ra một FastThreadLocal hy vọng sẽ giúp ích cho project của các bạn.

Đê xây một FastThreadLocal chúng ta cần phải xây dụng 2 thứ sau :

  • DThread một Thread kế thừa Thread của Java nhưng sẽ chứa thêm DThreadLocalMap để lưu giá trị của Thread thay vì ThreadLocal.ThreadLocalMap của Java
  • FastThreadLocal<T> để quản lý API get,set.

public class FastThreadLocal<T> {
    private static final AtomicInteger MARK = new AtomicInteger(0);

    private final int index = MARK.getAndIncrement();

    private ThreadLocal<T> local;
    private Supplier<T> supplier;

    public FastThreadLocal() {
    }

    public T get(){
        Thread t = Thread.currentThread();
        if (t instanceof DThread){
            DThread.DThreadLocalMap map =((DThread)t).getdThreadLocalMap();
            T value = (T) map.getData(this.index);
            if (value == null && supplier !=null){
                value = supplier.get();
            }
            return value;
        }else {
            if (local == null) local = new ThreadLocal<>();
            return local.get();
        }
    }

    public void set(T value){
        Thread t = Thread.currentThread();
        if (t instanceof DThread){
            DThread.DThreadLocalMap map =((DThread)t).getdThreadLocalMap();
            map.setData(this.index , value);
        }else {
            if (local == null) local = new ThreadLocal<>();
            local.set(value);
        }
    }

    public static <T> FastThreadLocal<T> withInit(Supplier<T> supplier){
        FastThreadLocal<T> instance = new FastThreadLocal<>();
        instance.local = ThreadLocal.withInitial(supplier);
        instance.supplier = supplier;
        return instance;
    }
}

public class DThread extends Thread {

    private final DThreadLocalMap dThreadLocalMap;

    public DThread(Runnable runnable, String s) {
        super(runnable, s);
        this.dThreadLocalMap = new DThreadLocalMap();
    }

    public DThread(Runnable runnable) {
        super(runnable);
        this.dThreadLocalMap = new DThreadLocalMap();
    }

    public DThread() {
        this.dThreadLocalMap = new DThreadLocalMap();
    }



    public DThreadLocalMap getdThreadLocalMap() {
        return dThreadLocalMap;
    }

    public static class DThreadLocalMap {
        private static final int INIT_SIZE = 8;
        private Object[] data;

        public DThreadLocalMap() {
            this.data = new Object[INIT_SIZE];
        }

        public Object getData(int index) {
            if (index > data.length) return null;
            return data[index];
        }

        private void expand(){
            Object[] oldArray = data;

            // copy fom netty
            int newCapacity = oldArray.length;
            newCapacity |= newCapacity >>>  1;
            newCapacity |= newCapacity >>>  2;
            newCapacity |= newCapacity >>>  4;
            newCapacity |= newCapacity >>>  8;
            newCapacity |= newCapacity >>> 16;
            newCapacity ++;

            data = Arrays.copyOf(oldArray, newCapacity);
        }

        public void setData(int index, Object value) {
            if (index > data.length){
                expand();
            }

            Object[] temp = data;
            temp[index] = value;

        }
    }
}

Các bạn có thể tham khảo cách code này hoặc cải tiến lên để phù hợp với bài toán của mình. Chắc chắn cách implement này sẽ có độ phức tạp O(1).

Bài viết gốc được đăng tải tại demtv.hashnode.dev

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

Đừng bỏ lỡ việc làm IT mọi cấp độ tại TopDev

Câu lệnh điều kiện trong Java

Câu lệnh điều kiện trong Java

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

Câu lệnh điều kiện là một phần kiến thức của câu lệnh điều khiển luồng (control flow). Cũng bởi vì kiến thức về câu lệnh điều khiển luồng này hơi nhiều và quan trọng, nên mình tách chúng ra làm hai nhóm. Nhóm thứ nhất bao gồm các câu lệnh điều kiện (hay còn gọi là các câu lệnh rẽ nhánh) mà bạn sẽ làm quen hôm nay. Nhóm còn lại là câu lệnh lặp bạn sẽ được làm quen ở bài sau.

Đầu tiên chúng ta nói về khái niệm chung của hai nhóm, khái niệm câu lệnh điều khiển luồng là gì nhé.

Khái Niệm Câu Lệnh Điều Khiển Luồng

Để dễ hiểu khái niệm này nhất, thì bạn hãy nhớ lại việc code của mình ở các bài học trước xem nào (mặc dù chúng ta chưa code nhiều lắm). Các bạn có thể thấy khi bạn code, và các dòng code đó được IDE thực thi, chúng sẽ được trình biên dịch này đọc và thực hiện một cách tuyến tính từ trên xuống đúng không nào, từ dòng số 1 đến dòng cuối cùng.

Nhưng thực tế không phải lúc nào chúng ta cũng xây dựng một ứng dụng với logic đơn giản như vậy. Các project thực tế đều cần các giải thuật phức tạp hơn, chẳng hạn như cần truy xuất vào cơ sở dữ liệu và in ra console từng thông tin của sinh viên. Thì khi đó việc thực hiện tuyến tính từng dòng code sẽ vô cùng phức tạp, bạn phải viết hàng ngàn dòng code cho việc đọc tuần tự hàng ngàn sinh viên trong cơ sở dữ liệu. Chưa hết nếu với mỗi sinh viên được đọc lên có một số điều kiện nào đó, như chỉ in ra số sinh viên có giới tính nữ, thì việc code và thực thi tuyến tính thật sự là một cơn ác mộng.

Chính vì vậy mà các câu lệnh điều khiển luồng được các ngôn ngữ cho ra đời, nhằm tạo ra một luồng thực thi mới, đó có thể là một luồng lặp, hay luồng rẽ nhánh, sao cho chúng có thể hướng trình biên dịch thực thi một đoạn code nào đó nhiều lần, hoặc bỏ qua không thực thi đoạn code nào đó,… Như đã nói thì bài hôm nay bạn làm quen với nhóm đầu tiên trong câu lệnh điều khiển luồng, đó là nhóm các câu lệnh điều kiện giúp rẽ nhánh luồng.

Trước khi vào làm quen đến các câu lệnh, mình xin bắt đầu nói rõ về hai ký hiệu “thần thánh” mà từ bài đầu tiên bạn đã gặp, hai ký hiệu này giúp ích rất nhiều cho bài học hôm nay và cả việc code của các bạn sau này, đó là ký hiệu { và }. Cặp ngoặc nhọn này giúp tạo thành một khối lệnh (hay còn gọi là block).

  4 tips học Java cơ bản nhanh nhất dành cho Beginner Developer

  Ép Kiểu & Comment Source Code trong Java

Khái Niệm Khối Lệnh (Block)

Như bạn vừa biết thì khối lệnh trong Java được biểu thị bằng cặp dấu ngoặc nhọn ({ và }).

Ngược lại quá khứ quay về các bài trước, bạn sẽ thấy cặp ngoặc này đã xuất hiện trong khai báo class (bạn sẽ học đến class ở các bài viết về OOP sau). Trong trường hợp này cặp ngoặc đã tạo ra một khối lệnh đóng vai trò bao lấy code và cho biết tất cả các code bên trong đó đều là các code của class. Khi đó, chúng (các code trong cặp ngoặc đó) phải tuân theo các nguyên tắc của class (bạn sẽ biết các nguyên tắc này sau). Mọi dòng code nằm ngoài cặp ngoặc nhọn này sẽ không thuộc quyền quản lý của class đó. Cặp ngoặc nhọn mà mình nói đến xuất hiện như hình sau.

Khối Lệnh (Block)
Minh họa cặp ngoặc nhọn bao lấy code của class

Hay cặp ngoặc nhọn xuất hiện ở khai báo phương thức (bạn cũng sẽ học đến phương thức ở bài sau), giúp tạo ra một khối lệnh đóng vai trò bao lấy code cho biết tất cả các code bên trong đó đều là code của phương thức đó. Cũng như trên, mọi dòng code nằm ngoài cặp ngoặc nhọn của phương thức này sẽ nằm ngoài xử lý logic của phương thức đó. Cặp ngoặc nhọn phương thức xuất hiện như sau.

Khối Lệnh (Block)
Minh họa cặp ngoặc nhọn bao lấy code của phương thức

Ngoài các cặp ngoặc nhọn của class và của phương thức ra thì bạn cũng có thể tạo bất cứ khối lệnh nào trong các dòng code của bạn, chỉ cần bao các câu lệnh đó vào một cặp ngoặc nhọn. Việc tạo ra các khối lệnh như thế này có thể giúp cho các dòng code được tổ chức rõ ràng hơn.

Khối Lệnh (Block)
Minh họa cặp ngoặc nhọn bao lấy code của một khối lệnh

Và hiển nhiên khối lệnh còn được áp dụng cho các câu lệnh điều kiện mà chúng ta sẽ làm quen dưới đây nữa. Chính vì vậy mà chúng ta cần làm quen với khối lệnh trước khi đi vào bài học chính thức là vậy.

Nhưng dù cho có sử dụng khối lệnh với mục đích nào đi nữa, thì bạn cũng phải nhớ một điều, là nếu có khai báo dấu { để bắt đầu một khối lệnh, thì phải có dấu } ở đâu đó để đóng khối lệnh lại. Nếu một chương trình mà có tổng số lượng dấu { không bằng với tổng số lượng dấu } sẽ có lỗi xảy ra đấy nhé.

Xem thêm việc làm Tuyển dụng Java hấp dẫn tại TopDev

Phạm Vi Của Biến (Scope)

Chúng ta làm quen với một kiến thức nữa. Vì khi các bạn đã quen với khối lệnh, thì bạn cũng nên biết phạm vi của biến. Vì phạm vi của biến sẽ bị ảnh hưởng rất lớn dựa trên các khối lệnh này.

Chúng ta xác định phạm vi của biến như thế nào? Thực ra mình cũng có đọc nhiều tài liệu về vấn đề này, có nhiều cách để xác định phạm vi, nhưng cách xác định trực quan nhất có lẽ là phân biệt phạm vi của biến dựa trên ảnh hưởng local hay global của nó.

  • Phạm vi local, là phạm vi mà biến đó chỉ ảnh hưởng cục bộ trong một khối lệnh, không thể dùng đến biến đó ở bên ngoài khối lệnh.
  • Phạm vi global, là phạm vi mà biến đó được khai báo ở khối lệnh bên ngoài, khi đó nó có ảnh hưởng đến các khối lệnh bên trong, tức các khối lệnh bên trong có thể dùng được biến global này.

Trong ví dụ dưới đây, bạn có thể thấy là biến name được mình khai báo trong một khối lệnh, nên nó là biến local của khối lệnh đó, bạn không thể dùng lại biến này ở khối lệnh khác (bạn có thể thấy hệ thống báo lỗi như hình dưới). Bạn chỉ có thể dùng được biến tên name này nếu khai báo lại biến ở khối lệnh khác, nhưng lưu ý khi đó hai biến name ở hai khối lệnh khác nhau sẽ chẳng liên quan gì với nhau cả.

Phạm Vi Của Biến (Scope)
Ví dụ biến name là biến local bên trong một khối lệnh

Cũng ví dụ này nhưng mình khai báo biến name ở bên ngoài khối lệnh, khi đó biến name này được xem như biến global của hai khối lệnh con, và vì vậy nó được gọi đến thoải mái mà không bị lỗi.

Phạm Vi Của Biến (Scope)
Ví dụ biến name là biến global của 2 khối lệnh con

Được nước lấn tới, mình tiếp tục ví dụ với biến name được để bên ngoài phương thức main() luôn, khi này nó sẽ được xem là biến global của tất cả các phương thức có trong class này (không riêng gì phương thức main() đâu nhé, và bạn cũng đừng để ý đến khai báo static của biến, khai báo dạng này sẽ được nói đến ở bài này khi bạn học sang OOP).

Phạm Vi Của Biến (Scope)
Ví dụ biến name là biến global các phương thức bên trong class

Hai ví dụ sau cùng trên đây đều cho ra console cùng một kết quả. Bạn cứ code và thực thi thử chương trình để kiểm chứng nhé.

Câu Lệnh if

Đến đây thì chúng ta đã xong kiến thức râu ria rồi, giờ hãy bắt đầu đi vào câu lệnh điều kiện đầu tiên, câu lệnh if. Chỉ với cái tên if thôi nhưng thực chất có tới bốn biến thể của câu lệnh dạng này mà bạn phải nắm, đó là: ifif elseif else if, và ?:. Chúng ta bắt đầu làm quen với từng loại như sau.

if

Cú pháp cho câu lệnh if như sau.

if (biểu_thức_điều_kiện) {
     các_câu_lệnh;
}

Trong đó:

  • biểu_thức_điều_kiện là một biểu thức mà sẽ trả về kết quả là một giá trị boolean.
  • các_câu_lệnh sẽ được thực thi chỉ khi mà biểu_thức_điều_kiện trả về giá trị true mà thôi. Bạn thấy rằng khối lệnh đã được áp dụng để bao lấy các_câu_lệnh.

Ví dụ cho câu lệnh if.

Scanner scanner = new Scanner(System.in);
System.out.println("Please enter your age: ");
int age = scanner.nextInt();

if (age < 18) {
    System.out.printf("You can not access");
}

Mình giải thích một chút ví dụ trên, các bạn thấy biểu_thức_điều_kiện lúc này là age < 18. Nghĩa là nếu biến age mà user nhập từ bàn phím nhỏ hơn 18, thì biểu thức này sẽ trả về true, khi đó trong khối lệnh của câu lệnh if này (dòng in ra console câu thông báo chưa đủ tuổi) sẽ được thực thi. Còn nếu user nhập vào một age lớn hơn 18, sẽ không có chuyện gì xảy ra, ứng dụng kết thúc. Ví dụ này đã bắt đầu dùng đến kiến thức về nhập/xuất trên console rồi đấy nhé.

Một lưu ý nhỏ thôi, là với trường hợp trong khối lệnh của if nếu chỉ có một dòng code như ví dụ trên, nhiều khi người ta bỏ luôn cả dấu { và }, khi đó câu lệnh if trên sẽ như sau.

if (age < 18)
    System.out.printf("You can not access");

Hay thậm chí viết như sau.

if (age < 18) System.out.printf("You can not access");

if else

Cú pháp cho câu lệnh if else như sau.

if (biểu_thức_điều_kiện) {
     các_câu_lệnh_1;
} else {
     các_câu_lệnh_2;
}

Trong đó:

  • biểu_thức_điều_kiện cũng sẽ trả về kết quả là một giá trị boolean.
  • các_câu_lệnh_1 được thực thi trong trường hợp biểu_thức_điều_kiện là true.
  • các_câu_lệnh_2 sẽ được thực thi trong trường hợp biểu_thức_điều_kiện là false.

Ví dụ cho câu lệnh if else.

if (age < 18) {
    System.out.printf("You can not access");
} else {
    System.out.printf("Welcome to our system!");
}

Bạn thấy ví dụ này làm rõ hơn trường hợp user nhập một age lớn hơn 18, khi đó biểu_thức_điều_kiện sẽ trả về kết quả false, và vì vậy các_câu_lệnh_2 sẽ được thực thi, trong ví dụ này là dòng in ra console “Welcome to our system!”.

Cũng bởi khối lệnh của if và else chỉ có một dòng nên bạn có quyền viết thế này.

if (age < 18)
  System.out.printf("You can not access");
else
  System.out.printf("Welcome to our system!");

Hay thế này, nhưng lưu ý code dài quá sẽ khó đọc lắm đấy, mình không khuyến khích viết như vậy.

if (age < 18) System.out.printf("You can not access"); else System.out.printf("Welcome to our system!");

if else if

Cú pháp cho câu lệnh if else if như sau.

if (biểu_thức_điều_kiện_1) {
     các_câu_lệnh_1;
} else if (biểu_thức_điều_kiện_2) {
     các_câu_lệnh_2;
} else if (...) {
     ...
} else if (biểu_thức_điều_kiện_n) {
     các_câu_lệnh_n;
} else {
     các_câu_lệnh_n+1;
}

Đây là dạng mở rộng hơn của câu lệnh if else. Khi đó:

  • các_câu_lệnh_1 được thực thi trong trường hợp biểu_thức_điều_kiện_1 trả về true.
  • các_câu_lệnh_2 được thực thi trong trường hợp biểu_thức_điều_kiện_1 trả về false và biểu_thức_điều_kiện_2 trả về true.
  • các_câu_lệnh_n được thực thi trong trường hợp các biểu_thức_điều_kiện trước nó đều trả về false và biểu_thức_điều_kiện_n trả về true.
  • Nếu không có bất kỳ biểu_thức_điều_kiện nào trả về true cả thì các_câu_lệnh_n+1 sẽ được thực thi.

Ví dụ cho câu lệnh if else if.

Scanner scanner = new Scanner(System.in);
System.out.println("Please enter a number of week (1 is Monday): ");
int day = scanner.nextInt();

if (day == 1) {
    System.out.printf("Monday");
} else if (day == 2) {
    System.out.printf("Tuesday");
} else if (day == 3) {
    System.out.printf("Wednesday");
} else if (day == 4) {
    System.out.printf("Thursday");
} else if (day == 5) {
    System.out.printf("Friday");
} else if (day == 6) {
    System.out.printf("Saturday");
} else if (day == 7) {
    System.out.printf("Sunday");
} else {
    System.out.printf("Invalid number!");
}

?:

Câu lệnh này thực chất không mới, nó như là câu lệnh if else nhưng được biểu diễn ngắn gọn hơn.

Mình thấy nhiều tài liệu gom kiến thức về việc sử dụng ?: này vào bài viết về các Toán tử. Khi đó nó được gọi là toán tử tam nguyên (ternary operator). Vì công dụng của nó được dùng cho mục đích tính toán nhanh giá trị hơn là một câu lệnh giúp điều khiển luồng. Nhưng với mình nó không khác gì if else cả, mình xem nó là một cách viết ngắn gọn hơn của if else nên gộp chung vào mục này. Còn sở dĩ gọi là toán tử tam nguyên là bởi hai ký tự mà bạn nhìn thấy (? và :) giúp tách các thành phần của câu lệnh ra làm ba phần (hay ba toán hạng), các bạn xem cú pháp của nó như sau.

[kết_quả =] biểu_thức_điều_kiện ? câu_lệnh_nếu_true : câu_lệnh_nếu_false;

Trong đó:

  • kết_quả có thể có hoặc không, biến kết_quả này sẽ lưu lại giá trị là kết quả của câu lệnh, nó phải là kiểu dữ liệu của câu_lệnh_nếu_true và câu_lệnh_nếu_false, lý do tại sao thì mời bạn đọc tiếp đoạn sau.
  • biểu_thức_điều_kiện tương tự như ở các câu lệnh if phía trên.
  • câu_lệnh_nếu_true sẽ thực thi khi biểu_thức_điều_kiện trả về true, vế này sẽ trả về một kết quả về cho kết_quả, có thể là kiểu String, hoặc boolean, hoặc int,…
  • Ngược lại câu_lệnh_nếu_false sẽ thực thi khi biểu_thức_điều_kiện trả về false, và vế này cũng sẽ trả kết quả về cho kết_quả.

Ví dụ cho câu lệnh ?: (ví dụ này được viết lại từ ví dụ if else ở trên).

Scanner scanner = new Scanner(System.in);
System.out.println("Please enter your age: ");
int age = scanner.nextInt();

String access = (age < 18) ? "You can not access" : "Welcome to our system!";
System.out.printf(access);

Bạn cũng thấy rằng câu lệnh này chỉ thích hợp thay thế cho if else mà thôi, và thực sự nó giúp chúng ta rút ngắn số dòng code lại, nhưng lại làm cho thuật toán khó đọc hơn đúng không nào. Tùy bạn cân nhắc sử dụng if else hay ?: nhé.

Một chút lưu ý là với code trên, bạn không cần dùng biến kết_quả access mà in trực tiếp ra console từ câu lệnh này luôn cũng được, mình điều chỉnh một tí như sau.

Scanner scanner = new Scanner(System.in);
System.out.println("Please enter your age: ");
int age = scanner.nextInt();

System.out.printf((age < 18) ? "You can not access" : "Welcome to our system!");

Câu Lệnh switch case

Câu lệnh này có thể dùng để thay thế if else if nói trên nếu như các biểu_thức_điều_kiện đều dùng một đối tượng giống nhau để so sánh (ví dụ ở if else if trên đây chúng ta dùng biến day để so sánh đi so sánh lại với các giá trị khác nhau). Khi này bạn nên dùng switch case để giúp cho if else if trông tường minh hơn.

Cú pháp cho câu lệnh switch case như sau:

switch (đối_tượng_so_sánh) {
     case giá_trị_1:
          các_câu_lệnh_1;
          break;
     case giá_trị_2:
          các_câu_lệnh_2;
          break;
     case ...:
          ...;
          break;
     case giá_trị_n:
          các_câu_lệnh_n;
          break;
     default:
          các_câu_lệnh_n+1;
          break;
}

Thay vì so sánh đối tượng ở từng biểu_thức_điều_kiện như ở if else if, bạn chỉ cần truyền nó vào đối_tượng_so_sánh, rồi chỉ định từng giá_trị_x của nó để thực thi kết quả của nó ở các_câu_lệnh_x tương ứng.

Bạn nhớ ở mỗi case đều có kết thúc là câu lệnh đặc biệt break (câu lệnh break này sẽ được nói ở bài sau). Hiện tại, bạn chỉ nên biết là câu lệnh break này giúp bạn dừng việc thực thi ở một khối lệnh của các_câu_lệnh_x nào đó, nếu không có break, hệ thống sẽ đi tiếp qua case tiếp theo để xử lý và như vậy sẽ cho kết quả sai.

Thành phần cuối cùng trong câu lệnh này là từ khóa default, thành phần này giống như else cuối cùng của một if else if, nó biểu thị rằng nếu như các so sánh case không thỏa các giá_trị của đối_tượng_so_sánh, thì các_câu_lệnh_n+1 trong default sẽ được gọi.

Ví dụ cho câu lệnh switch case (ví dụ này được viết lại từ ví dụ if else if ở trên).

Scanner scanner = new Scanner(System.in);
System.out.println("Please enter a number of week (1 is Monday): ");
int day = scanner.nextInt();
  
switch (day) {
case 1:
    System.out.printf("Monday");
    break;
case 2:
    System.out.printf("Tuesday");
    break;
case 3:
    System.out.printf("Wednesday");
    break;
case 4:
    System.out.printf("Thursday");
    break;
case 5:
    System.out.printf("Friday");
    break;
case 6:
    System.out.printf("Saturday");
    break;
case 7:
    System.out.printf("Sunday");
    break;
default:
    System.out.printf("Invalid number!");
    break;
}

Bạn có thấy giống if else if không nào.

Kết Luận

Chúng ta vừa đi qua các câu lệnh điều kiện – Một phần trong câu lệnh điều khiển luồng. Qua đó bạn cũng đã hiểu khối lệnh và phạm vi của biến trong chương trình Java rồi, bạn hãy theo dõi các bài học kế tiếp để nắm rõ hơn ngôn ngữ Java này nhé.

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

Xem thêm:

Tìm việc làm IT mọi cấp độ tại TopDev

Resume là gì? Résume khác CV như thế nào?

CV và Resume: Điểm khác biệt quan trọng khi xin việc

CV và Resume là những “tấm vé thông hành” giúp bạn có được công việc mơ ước. Tuy nhiên, nhiều người không biết Resume là gì và vẫn lầm tưởng CV và Resume là một, nhưng thật ra chúng hoàn toàn khác nhau đấy. Vậy bạn nên lựa chọn CV hay Resume để nộp cho nhà tuyển dụng, cái nào sẽ phù hợp với bạn và thu hút nhà tuyển dụng nhất? Cùng TopDev theo dõi bài viết dưới đây để tìm ra câu trả lời nhé!

Resume là gì?

Resume là gì?
Resume là gì?

Resume là một bản tài liệu tóm tắt về kinh nghiệm làm việc, kỹ năng và thành tựu của ứng viên. Resume thường ngắn hơn, thường chỉ có 1-2 trang và tập trung vào các thông tin quan trọng nhất về kinh nghiệm làm việc, kỹ năng và thành tựu của ứng viên liên quan đến vị trí ứng tuyển. Resume thường được sử dụng trong các ngành nghề liên quan đến kinh doanh, quản lý, tiếp thị và truyền thông.

Resume có nguồn gốc từ tiếng Pháp và được viết chính xác là Résumé có nghĩa trong tiếng Anh là “summary”.

Vậy còn CV?

CV (Curriculum Vitae) thường là một bản tài liệu chi tiết và toàn diện về trình độ học vấn, kinh nghiệm làm việc và kỹ năng của ứng viên. CV thường có độ dài từ 2-3 trang và chứa đầy đủ thông tin về quá trình học tập, kinh nghiệm làm việc, thành tựu, kỹ năng và nghiên cứu khoa học của ứng viên. CV thường được sử dụng trong các ngành nghề yêu cầu nhiều kinh nghiệm và trình độ học vấn cao.

  CV IT Developer là gì? Viết CV IT Developer như thế nào là chuẩn?

Resume và CV khác nhau như thế nào?

Sau khi hiểu khái niệm CV và Resume là gì, ta thấy rằng cả CV và Resume đều là các hồ sơ đăng ký ứng tuyển cho công việc, nhưng chúng có một số điểm khác biệt về nội dung và mục đích sử dụng

Nội dung

CV thường là một bản tài liệu chi tiết và toàn diện hơn về trình độ học vấn, kinh nghiệm làm việc và kỹ năng của ứng viên. Trong khi đó, Resume tập trung vào các thông tin quan trọng nhất về kinh nghiệm làm việc, kỹ năng và thành tựu của ứng viên liên quan đến vị trí ứng tuyển.

Chiều dài

CV là một tài liệu chi tiết tổng hợp mọi sự kiện quan trọng xảy ra trong cuộc đời của mỗi người. Do đó, độ dài của CV không xác định. Nếu bạn học lên càng cao, trải qua nhiều công việc và có nhiều thành tựu thì CV của bạn sẽ càng dài. CV của một sinh viên mới tốt nghiệp thông thường có thể dài từ 2 đến 3 trang, trong khi đó CV của một nhà nghiên cứu lâu năm có thể dài lên đến 10 trang hoặc hơn.

CV (Curriculum Vitae) và Resume

Trái ngược với CV, Resume là một bản tóm tắt ngắn gọn học vấn và kỹ năng của bạn. Vì vậy, độ dài của nó càng ngắn càng tốt, lý tưởng là từ 1 đến 2 trang là đủ. Trong Resume, bạn không nên liệt kê tất cả những gì đã trải qua mà chỉ nên lọc ra những thành tích hoặc thành tựu có liên quan và nổi bật nhất của mình.

Mục đích sử dụng

CV thường được sử dụng trong các ngành nghề yêu cầu nhiều kinh nghiệm và trình độ học vấn cao, như giáo dục, nghiên cứu và y tế, hoặc dùng để nộp hồ sơ cho các học bổng du học.

Trong khi đó, Resume thường được dùng để xin việc, sử dụng trong các ngành nghề liên quan đến kinh doanh, quản lý, tiếp thị và truyền thông. Vì vậy, bạn nên điều chỉnh Resume, chỉ cho các kỹ năng liên quan đến vị trí ứng tuyển vào Resume để làm bật lên bạn là người phù hợp với vị trí này.

Bố cục

CV thường có bố cục đơn giản và rõ ràng, tập trung vào việc trình bày các thông tin liên quan đến kinh nghiệm làm việc và kỹ năng của ứng viên. Mỗi mục trong CV được sắp xếp theo thứ tự thời gian ngược dần, từ kinh nghiệm mới nhất đến cũ hơn. Trong khi đó, Resume thường có bố cục theo độc đáo hơn, sắp xếp tùy ý dựa vào mục đích và yêu cầu của thông tin tuyển dụng được đưa ra.

Độ phổ biến

Mặc dù CV và Resume có nhiều điểm khác biệt và mục đích sử dụng không giống nhau nhưng nhiều nơi trên thế giới vẫn xảy ra nhầm lẫn. Hiện nay, nhiều khu vực ở châu Á, châu Âu, châu Phi và Trung Đông thường lựa chọn CV trong quá trình tuyển dụng, trong khi ở Mỹ và Canada lại được ưa chuộng Resume hơn.

Bên cạnh đó, một số quốc gia như Vương Quốc Anh, New Zealand và Ireland chấp nhận cả Resume và CV khi nộp đơn xin việc. Còn ở Việt Nam, nhà tuyển dụng và ứng viên không quá rạch ròi trong việc phân biệt CV hay Resume, nên thường bạn sẽ rất ít bị bắt lỗi vấn đề này.

  Mẫu CV IT tiếng Anh hấp dẫn nhà tuyển dụng

Bạn nên lựa chọn CV hay Resume để phỏng vấn việc làm?

Sự khác biệt giữa CV và resume mở ra nhiều lựa chọn cho bạn trong quá trình tìm việc. Nếu bạn là ứng viên mới ra trường hoặc chưa có nhiều kinh nghiệm, resume có thể là lựa chọn tốt để bắt đầu sự nghiệp. Đơn giản vì nó ngắn gọn và yêu cầu bạn tập trung vào những thông tin cần thiết nhất, tránh lan man tới những chi tiết không liên quan mà nhà tuyển dụng không cần biết.

  Cách viết CV xin việc IT "bao đậu" dành cho người chưa có kinh nghiệm

Tuy nhiên, khi bạn tích lũy được nhiều kinh nghiệm làm việc và đạt được nhiều thành tựu, cập nhật resume thành một bản CV chi tiết và chuyên nghiệp sẽ là một điều rất hữu ích. Điều này đặc biệt quan trọng khi bạn muốn ứng tuyển cho các vị trí cấp cao, nơi nhà tuyển dụng cần những kỹ năng chuyên môn cao và kinh nghiệm xử lý công việc phức tạp.

Tóm lại, việc lựa chọn giữa Resume và CV phụ thuộc vào nhiều yếu tố, nhưng hiểu rõ sự khác biệt giữa chúng sẽ giúp bạn tạo ra bản hồ sơ phù hợp với mục tiêu tìm việc của mình. Truy cập ngay TopDev để tìm việc làm lương cao và tạo ngay cho mình một CV hấp dẫn, thu hút nhà tuyển dụng bạn nhé!

Tạo CV online chuẩn tại TopDev

Xem thêm Tìm việc làm IT hàng đầu tại TopDev

Cách Thiết Lập Máy Ảo, Máy Thật & Khởi Chạy Ứng Dụng Trong Android

Cách Thiết Lập Máy Ảo Máy Thật & Khởi Chạy Ứng Dụng Trong Android

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

Chà chà… Mình biết khi các bạn đọc đến bài học này, chắc hẳn các bạn đều rất muốn được nhìn thấy diện mạo của ứng dụng khi thực thi (khởi chạy trên thiết bị) sẽ trông như thế nào đúng không.

Chưa cần biết nhiều về kiến thức Android, tại đây, khi đã đọc qua và thực hiện các thao tác cài đặt theo các bài học trước, hôm nay bạn đã có thể chạy ứng dụng được rồi, thậm chí bạn có thể mang ứng dụng này để cài đặt lên các thiết bị khác để lòe bạn bè nữa đấy. Vậy làm thế nào? Trước hết chúng ta điểm qua các cách thiết lập máy ảo và máy thật ở các bước sau. Như vậy cho dù bạn đã có hay chưa có trong tay một thiết bị Android (điện thoại hoặc máy tính bảng đều được), thì với bài học này, bạn đã có thể tự tạo ra cho mình một môi trường để chạy thử ứng dụng của mình được rồi đó.

Máy Ảo

Máy ảo (Emulator) là một phần mềm giả lập, nó được tạo ra với cấu hình và hoạt động giống như máy thật nhất có thể. Câu hỏi là nếu bạn đã có trong tay một máy thật Android lúc này rồi thì sao? Câu trả lời là: không gì tốt bằng. Nhưng không phải vì vậy mà bạn lại không tạo cho riêng mình một máy ảo.

Vì sao? Có hai lý do chính. Lý do thứ nhất, là không phải lúc nào bạn cũng dùng máy thật để chạy đi chạy lại ứng dụng mà bạn đang làm dở dang chưa ổn định, điều này có thể làm hư cái máy thật của bạn. Lý do thứ hai, là số lượng máy thật của bạn sẽ chỉ có một hoặc rất ít, thì việc bạn có thêm một hay nhiều máy ảo giả lập các cấu hình phần cứng khác mà các máy thật của bạn chưa có, giúp bạn kiểm tra kỹ hơn sự tương thích của ứng dụng trên nhiều phần cứng và màn hình khác nhau trước khi “xuất xưởng”.

Bạn có thể sử dụng một trong hai loại máy ảo sau (hoặc sử dụng cả hai đều được), mỗi loại sẽ có ưu điểm và khuyết điểm riêng mà chúng ta sẽ nói rõ theo từng phần bên dưới. Lưu ý là chúng ta còn nhiều tùy chọn máy ảo khác chứ không riêng hai loại này, nhưng các máy ảo được giới thiệu với các bạn sau đây đang là hai máy ảo hot nhất đối với dân lập trình Android ở thời điểm hiện tại.

  Tạo Splash Screen cho Android như thế nào là "chuẩn" nhất?

Máy Ảo Android – Android Virtual Device (AVD)

AVD là một máy ảo Android được hỗ trợ chính thức từ Google. Vì là bản “chính chủ” nên máy ảo này sẽ có tính ổn định cao.

Chẳng hạn như nó sẽ tiêu tốn bộ nhớ của máy tính ít hơn các máy ảo khác, nó còn hỗ trợ giả lập tất cả các loại thiết bị, từ điện thoại, máy tính bảng, thiết bị đeo được, và kể cả Android TV nữa đấy. Nhược điểm của máy ảo này là khá ít, khi mà mới đây mình đã thấy AVD có hỗ trợ ứng dụng Google Play, giúp bạn có thể install các ứng dụng có trên store về để mà vọc thoải mái.

  Tổng Hợp Các Tip Khi Sử Dụng Android Studio

Cài đặt AVD

Đầu tiên, đảm bảo bạn đã mở Android Studio lên rồi. Từ màn hình chính của Android Studio, có hai cách để khởi động AVD, bạn có thể đi từ menu Tools > Android > AVD Manager, hoặc tìm kiếm icon  trên thanh công cụ (toolbar).

Cửa sổ Quản Lý AVD – Android Virtual Device Manager sẽ xuất hiện như sau.

Cài đặt AVD

Với cửa sổ như trên đây, hoặc bạn đang mở một cửa sổ trông khác chút, thì bạn cứ tìm kiếm nút Create Virtual Device…. Nhấn vào nút này sẽ mở ra một cửa sổ cho bạn chọn các thiết bị giả lập.

Tham khảo việc làm Android hấp dẫn trên TopDev

Cài đặt AVD

Mình sẽ điểm sơ qua các thành phần của cử sổ này, để giúp bạn có một chọn lựa máy ảo hợp lý (nếu bạn lỡ tạo lầm một máy ảo không ưng ý cũng không sao, bạn cứ tạo và chạy lên thử, nếu không thích hoàn toàn có thể gỡ bỏ và tạo lại máy ảo khác một cách nhanh chóng).

– Khung bên trái (Category): khung này cho phép bạn chọn loại máy ảo như điện thoại (Phone), máy tính bảng (Tablet), thiết bị đeo được (Wear OS), hay là  TV. Với ứng dụng TourNote, chúng ta sẽ trải nghiệm ứng dụng trên điện thoại trước, do đó bạn hãy chọn Phone như hình trên.

– Khung lớn ở giữa: chính là các thiết bị giả lập tương ứng với từng loại thiết bị bên trái, có vài thiết bị được tạo ra dựa vào thiết bị thật đang được kinh doanh phổ biến trên thị trường, như các dòng Pixel, Nexus hay Galaxy (hiển thị ở cột Name). Cột Play Store cho biết máy ảo này có hỗ trợ ứng dụng Google Play hay không, nếu có, một icon Máy ảo máy thật - Icon Google Play sẽ xuất hiện, mình khuyến khích các bạn nên chọn các loại máy ảo có xuất hiện icon này. Cột Size cho biết kích cỡ màn hình mà máy ảo giả lập, kích cỡ này tính theo đơn vị inch như ngoài thực tế. Cột Resolution là độ phân giải của màn hình, độ phân giải này được tính theo đơn vị pixel, chính là điểm ảnh theo các chiều ngang & dọc. Density cho biết mật độ điểm ảnh của màn hình, căn cứ vào kích cỡ màn hình (size) và độ phân giải (resolution) mà ta có tỷ lệ (resolution) tương ứng như mdpihdpixhdpixxhdpi, 420dpi…, thông số này bạn sẽ được làm quen ở các bài học sau, chẳng hạn như bài học về dimen này.

– Khung bên phải: như một tóm tắt trực quan cho chọn lựa của bạn ở các khung khác.

Như hình trên, chúng ta sẽ chọn con máy ảo là điện thoại Nexus 5X, có sẵn Google Play, màn hình 5.2″, độ phân giải 1080×1920, có density là 420dpi. Sau khi bạn đã chọn máy ảo, bạn hãy nhấn Next và xem màn hình kế tiếp.

Cài đặt AVD

Đến bước như hình trên đây chính là bước mà bạn sẽ cài hệ điều hành Android vào cho con Nexus 5X ảo mà bạn đã chọn. Lưu ý là bạn phải đảm bảo tab Recommended đang được chọn, đây chính là tab mà hệ thống sẽ gợi ý gói hệ điều hành Android tốt nhất cho bạn. Có khá nhiều loại hệ điều hành, nhưng để dễ dàng kiểm thử xem ứng dụng của bạn trông như thế nào trên các giao diện hệ điều hành mới thì bạn nên chọn loại mới nhất, cho đến thời điểm hiện tại, hệ điều đáng để chạy chính là Pie (API Level 28).

À nếu bạn chưa cài đặt gói máy ảo nào, thì nó sẽ xuất hiện nút download bên cạnh tên hệ điều hành như hình trên, và nút Next bị mờ đi, khi đó phải nhấn download để down gói máy ảo mà bạn cần về trước. Sau khi nhấn download thì cửa sổ download và install sẽ xuất hiện như hình sau.

Cài đặt AVD

Sau khi download xong, bạn sẽ thấy chọn lựa của chúng ta không còn nút download kế bên nữa, và chúng ta hoàn toàn có thể nhấn nút Next để qua bước cuối cùng.

Bước tiếp theo như hình dưới, sẽ là bước cho bạn vài tùy chỉnh cuối cùng trước khi hoàn thành. Bạn có thể đổi tên máy ảo (ở mục AVD Name), tỷ lệ scale, hiển thị màn hình theo chế độ mặc định là đứng/ngang, dung lượng Ram và bộ nhớ dành cho máy ảo này, camera cho máy ảo,… như hình dưới đây. Nhưng tốt nhất bạn nên để mặc định và nhấn Finish.

Cài đặt AVD

Sau khi kết thúc quá trình cài đặt bạn sẽ nhìn thấy cửa sổ như hình dưới. Máy ảo mà bạn vừa tạo sẽ hiển thị trong danh sách máy ảo của cửa sổ này, bạn có thể tạo thêm nhiều máy ảo khác, hay nhấn chuột phải vào bất kỳ máy nào và chọn xóa nó đi, hoặc click đúp vào để khởi chạy máy ảo lên.

Cài đặt AVD

Trường hợp nhấn đúp vào một máy ảo. Máy ảo sẽ khởi động như thế này.

khởi động máy ảo AVD

Sau khi khởi động xong màn hình máy ảo sẽ trông như hình dưới đây. Bạn nên mở ứng dụng Google Play (Play Store) có sẵn trong máy ảo lên và đăng nhập vào tài khoản Gmail của bạn.

Lưu ý là trong suốt quá trình mở máy ảo để kiểm thử, bạn đừng nên tắt máy đi nhé, tưởng tượng như đây là máy thật và không ai cứ tắt mở nguồn liên tục cả, bạn chỉ việc chạy và chạy và chạy ứng dụng lên máy đã mở sẵn mà thôi.

khởi động máy ảo AVD

Thực Thi Ứng Dụng Lên AVD

Đảm bảo Android Studio đang mở. Đảm bảo máy ảo AVD vẫn đang mở. Nếu bạn đang ở màn hình Welcome của Android Studio như hình dưới thì chọn vào project TourNote ở danh sách bên trái để vào màn hình chính của Android Studio. Nếu không thấy danh sách ứng dụng nào bên trái thì bạn có thể chọn Open an existing Android Studio project và tìm đến đường dẫn chứa project TourNote mà bạn đã tạo ở bài trước.

Thực Thi Ứng Dụng Lên AVD

Khi màn hình chính của Android Studio được mở, bạn nhấn vào nút Run  Máy ảo máy thật - Icon run trên thanh công cụ (toolbar).

Một cửa sổ xuất hiện với tên máy ảo mà bạn đang chạy như hình dưới đây.

Thực Thi Ứng Dụng Lên AVD

Giờ thì nhấn OK và đợi một phút. Xin chúc mừng, bạn đã thành công với việc khởi chạy ứng dụng đầu tiên của mình lên thiết bị (ảo)!!!

Thực Thi Ứng Dụng Lên AVD

Máy Ảo Genymotion

Genymotion là một máy ảo đa năng, trước đây mình rất thích dùng Genymotion, nhưng giờ đây máy ảo AVD đã giúp mình “thỏa mãn” hơn rồi. Tuy nhiên nếu bạn muốn thử nghiệm một ứng dụng từ một nhà cung cấp khác không phải Google, thì hãy vào trang chủ của Genymotion https://www.genymotion.com/ để đăng ký thành viên và down file cài đặt về nhé.

Một vài điểm cộng cho Genymotion, đó là máy ảo này chạy khá ổn định, nó có thể giúp giả lập được cả việc chụp hình với camera trước/sau, giả lập hiệu quả định vị GPS (AVD cũng có nhưng khó sử dụng hơn). Genymotion cũng cho bạn cài Google Play. Nói chung, Genymotion so với AVD thì như là “kẻ tám lạng người nửa cân” vậy.

Khuyết điểm của Genymotion cũng không nhiều, có thể kể đến như là, do đây là bên cung cấp dịch vụ thứ ba (third party), nên nó không hoàn toàn miễn phí, bạn chỉ được phép sử dụng miễn phí khi mà bạn chỉ muốn học chơi, nhưng nếu bạn đang làm việc cho công ty hay tổ chức nhỏ nào đó, thì bạn nên dùng bản có phí. Ngoài ra vì cũng vì là bên dịch vụ thứ ba, nên bạn phải tốn thời gian download và cài đặt ban đầu hơn là với AVD.

Có một điều với mục này là, mình chỉ nói đến đây cho máy ảo Genymotion thôi. Trước đây mình viết rất nhiều ở mục này, nhưng giờ mình xóa đi hết rồi. Thứ nhất, mình cũng muốn khuyến khích các bạn dùng AVD nhiều hơn, vì đây là công cụ “chính chủ” và hoàn toàn miễn phí từ Google. Thứ hai, do áp lực phải ra nhiều bài viết mới trên blog của mình sao cho hợp thời với các kỹ thuật lập trình mới, nên mình sẽ không có đủ thời gian để điều chỉnh bài viết theo sát sự thay đổi của Genymotion. Các bạn có thể tự tìm hiểu thêm trên mạng để sử dụng tốt Genymotion nhé.

Máy Thật

Với máy thật thì dễ dàng hơn nhiều, bạn sẽ không tốn công chọn lựa và cài đặt, việc duy nhất lúc này là bạn cần mở chế độ Developer options mà thôi.

Mặc định nếu thiết bị của bạn đang có hệ điều hành Android 4.2 trở lên, thì khi vào Settings của máy, bạn sẽ không thấy Developer options ở đâu. Đơn giản vì hệ thống đã giấu tùy chọn này, chỉ những nhà phát triển (developer) mới biết cách cho nó hiện ra. Để hiện ta tùy chọn này bạn làm như sau, mở ứng dụng Settings, tìm đến mục About phone, một số máy bạn phải vào tiếp mục Software info, bạn sẽ thấy mục Build number. Xem hình sau.

máy thật

Lúc này bạn hãy nhấn nhanh nhiều lần lên Build number, cho đến khi bạn thấy thông báo dạng toast (một thông báo nhỏ ở phía dưới màn hình) với nội dung Developer mode has been turned on thì đã thành công, khi này quay lại màn hình Settings bạn đã thấy mục Developer options như hình dưới đây.

máy thật

Sau đó bạn hãy vào Developer options, và check chọn USB debugging như hình này.

máy thật

Từ giờ trở đi khi bạn cắm thiết bị thật Android vào máy tính thông qua dây cáp và nhấn nút Run Máy ảo máy thật - Icon run trên thanh công cụ (giống như ở các bước khởi chạy với máy ảo ở trên) thì khi đó cửa sổ xuất hiện tiếp theo sẽ có tên thiết bị của bạn trong đó, như hình sau.

máy thật

Đến đây bạn hoàn toàn có thể nhấn OK để xem kết quả trên máy thật.

Tuy nhiên nếu bạn gặp trục trặc như hai tình huống dưới đây thì bạn phải làm tiếp vài bước nhỏ nữa, còn các bạn nào đã chạy ứng dụng được lên máy thật rồi thì không cần đọc hai ý dưới này nhé.

1. Tôi không thấy tên thiết bị xuất hiện ở cửa sổ như hìnhtrên. Có thể bạn đang xài Windows và máy bạn không có sẵn driver cho thiết bị rồi, bạn đọc bài này để install driver nhé https://developer.android.com/studio/run/oem-usb.html.

2. Tên thiết bị của tôi có xuất hiện ở cửa sổ như hình trên, nhưng nút OK bị mờ không nhấn được. Điều này xảy ra với thiết bị Android lần đầu tiên kết nối với máy tính của bạn, bạn hãy nhìn lại màn hình thiết bị Android xem nếu có xuất hiện hộp thoại sau thì hãy check chọn vào Always allow from this computer rồi nhấn OK như hình dưới nhé, khi đó cửa sổ trên máy tính sẽ trông giống như trên thôi.

máy thật

Bạn vừa trải qua một bài học dài về cách thiết lập máy ảo và khởi chạy ứng dụng trên máy ảo và máy thật. Từ giờ bạn đã có thể thoải mái chạy thử ứng dụng để xem kết quả như thế nào rồi nhé. Các bạn có thể chọn cho mình một máy ảo hoặc máy thật để kiểm thử, nhưng các bài học từ đây về sau mình sẽ dùng AVD để chạy ứng dụng và dùng để chụp màn hình ứng dụng cho các bạn cùng xem.

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

Xem thêm:

Tìm việc làm IT mọi cấp độ tại TopDev

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

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

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 đó.

  Hướng dẫn Java Design Pattern – Proxy

  Bridge Pattern trong Java – Code ví dụ Composite Pattern

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

Java 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 TopDev

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 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 TopDev

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 TopDev

Hướng dẫn sử dụng thư viện Jackson

Hướng dẫn sử dụng thư viện Jackson

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

Trong các bài trước, chúng ta đã tìm hiệu về thư viện Gson để chuyển đổi từ đối tượng Java sang JSON và từ JSON sang đối tượng Java. Trong bài này, tôi sẽ hướng dẫn bạn sử dụng thư viện Jackson, một thư viện mã nguồn mở miễn phí rất mạnh mẽ được sử dụng trong nhiều ứng dụng Java.

Giới thiệu

Jackson là một thư viện Java chứa rất nhiều chức năng để đọc và xây dựng JSON. Nó có khả năng ràng buộc dữ liệu rất mạnh mẽ và cung cấp một framework để tùy chỉnh quá trình chuyển đối tượng Java sang chuỗi JSON và chuỗi JSON sang đối tượng Java.

Tạo JSON từ đối Java

Có 3 cách để tạo JSON từ Java:

  • Từ một đối tượng Java
  • Từ cây JsonNode
  • Từ Json Stream

Phân tích chuỗi JSON

Có 3 cách thường dùng để phân tích chuỗi JSON sang Java:

  • Streaming : sử dụng JsonParser để phân tích cú pháp json. Nó cung cấp các phần tử json như là các token. Sử dụng JsonGenerator để tạo ra json từ chuỗi, số nguyên, boolean, …
  • Tree Traversing : json có thể được đọc thành một JsonNode. Node sau đó có thể đi qua để có được thuộc tính cần thiết. Một cây cũng có thể được tạo ra và sau đó được viết như chuỗi json.
  • Data Binding (liên kết dữ liệu) : sử dụng Annotation để đánh dấu các thuộc tính trên đối tượng (POJO) liên kết với các phần tử của chuỗi JSON.

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

Download thư viện Jackson

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.3</version>
</dependency>

Các ví dụ

Chuyển Java Object sang JSON

Student.java

package com.gpcoder.jackson.object;

import java.util.List;

public class Student {
    private String name;
    private int age;
    private List<Subject> subjects;

    public Student() {
        super();
    }

    public Student(String name, int age, List<Subject> subjects) {
        super();
        this.name = name;
        this.age = age;
        this.subjects = subjects;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Subject> getSubjects() {
        return subjects;
    }

    public void setSubjects(List<Subject> subjects) {
        this.subjects = subjects;
    }

    @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", subjects=" + subjects + "]";
    }
}

Subject.java

package com.gpcoder.jackson.object;

public class Subject {
    public Subject() {
        super();
    }

    private String name;
    private float point;

    public Subject(String name, float point) {
        super();
        this.name = name;
        this.point = point;
    }

    public String getName() {
        return name;
    }

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

    public float getPoint() {
        return point;
    }

    public void setPoint(float point) {
        this.point = point;
           }

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

}

Chương trình chuyển đối tượng Java sang JSON

package com.gpcoder.jackson;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gpcoder.jackson.object.Student;
import com.gpcoder.jackson.object.Subject;

public class Object2JsonExample {
    public static void main(String[] args) throws Exception {
        Student student = getStudent();

        ObjectMapper mapper = new ObjectMapper();

        // Convert object to JSON string and save into a file directly
        mapper.writeValue(new File("data/result.json"), student); // Plain JSON

        // Convert object to JSON string
        String jsonInString = mapper.writeValueAsString(student);
        System.out.println("JSON: " + jsonInString);

        // Convert object to JSON string and pretty print
        jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
        System.out.println("JSON pretty print: " + jsonInString);
    }

    private static Student getStudent() {
        Subject math = new Subject("Math", 10.0f);
        Subject physical = new Subject("Physical", 8.5f);
        List<Subject> subjects = new ArrayList<>();
        subjects.add(math);
        subjects.add(physical);

        return new Student("GP Coder", 28, subjects);
    }
}

Thực thi chương trình trên, một file result.json được tạo ra trong thư mục data của project, console của ide hiển thị kết quả như sau:

JSON: {"name":"GP Coder","age":28,"subjects":[{"name":"Math","point":10.0},{"name":"Physical","point":8.5}]}

JSON pretty print: {
  "name" : "GP Coder",
  "age" : 28,
  "subjects" : [ {
    "name" : "Math",
    "point" : 10.0
  }, {
    "name" : "Physical",
    "point" : 8.5
  } ]
}

Phân tích JSON sang Java Object

package com.gpcoder.jackson;

import java.io.File;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gpcoder.jackson.object.Student;

public class Json2ObjectExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        // Convert JSON string from file to Object
        Student student = mapper.readValue(new File("data/result.json"), Student.class);
        System.out.println(student);

        // Convert JSON string to Object
        String jsonInString = "{\"name\":\"GP Coder\",\"age\":28,\"subjects\":[{\"name\":\"Math\",\"point\":10.0},{\"name\":\"Physical\",\"point\":8.0}]}";
        student = mapper.readValue(jsonInString, Student.class);
        System.out.println(student);

        // Pretty print
        jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
        System.out.println(jsonInString);
    }
}

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

Student [name=GP Coder, age=28, subjects=[Subject [name=Math, point=10.0], Subject [name=Physical, point=8.5]]]

Student [name=GP Coder, age=28, subjects=[Subject [name=Math, point=10.0], Subject [name=Physical, point=8.0]]]

{
  "name" : "GP Coder",
  "age" : 28,
  "subjects" : [ {
    "name" : "Math",
    "point" : 10.0
  }, {
    "name" : "Physical",
    "point" : 8.0
  } ]
}

Chuyển Json Array sang Java List

package com.gpcoder.jackson;

import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gpcoder.jackson.object.Student;
import com.gpcoder.jackson.object.Subject;

public class ArrayExample {
    public static void main(String[] args) throws Exception {

        ObjectMapper mapper = new ObjectMapper();

        Student student1 = getStudent(1);
        Student student2 = getStudent(2);

        Student[] students = { student1, student2 };

        // Convert array object to JSON string
        String jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(students);
        System.out.println("JSON: " + jsonInString);

        // Convert a JSON Array format to a Java List object
        List<Student> list = mapper.readValue(jsonInString, new TypeReference<List<Student>>() {
        });
        for (Student student : list) {
            System.out.println(student);
        }
    }

    private static Student getStudent(int id) {
        Subject math = new Subject("Math", 10.0f);
        Subject physical = new Subject("Physical", 8.5f);
        List<Subject> subjects = new ArrayList<>();
        subjects.add(math);
        subjects.add(physical);

        return new Student("GP Coder " + id, 28, subjects);
    }
}

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

JSON: [ {
  "name" : "GP Coder 1",
  "age" : 28,
  "subjects" : [ {
    "name" : "Math",
    "point" : 10.0
  }, {
   "name" : "Physical",
    "point" : 8.5
  } ]
}, {
    "name" : "GP Coder 2",
    "age" : 28,
    "subjects" : [ {
      "name" : "Math",
      "point" : 10.0
    }, {
      "name" : "Physical",
      "point" : 8.5
    } ]
} ]
Student [name=GP Coder 1, age=28, subjects=[Subject [name=Math, point=10.0], Subject [name=Physical, point=8.5]]]
Student [name=GP Coder 2, age=28, subjects=[Subject [name=Math, point=10.0], Subject [name=Physical, point=8.5]]]

Chuyển Json Object sang Java Map

package com.gpcoder.jackson;

import java.util.Map;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gpcoder.jackson.object.Subject;

public class MapExample {
    public static void main(String[] args) throws Exception {

        ObjectMapper mapper = new ObjectMapper();

        Subject math = new Subject("Math", 10.0f);

        // Convert array object to JSON string
        String jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(math);
        System.out.println("JSON: " + jsonInString);

        // Convert a JSON to a Map
        Map<String, Object> map = mapper.readValue(jsonInString, new TypeReference<Map<String, Object>>() {
        });
        System.out.println("Map: " + map);
    }
}

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

JSON: {
  "name" : "Math",
  "point" : 10.0
}
Map: {name=Math, point=10.0}

Web Developer là gì? Lộ trình để trở thành Web Developer

Web Developer là gì? Lộ trình để trở thành Web Developer

Web Developer là những lập trình viên tạo ra các ứng dụng Web có thể chạy được trên các trình duyệt website. Để xây dựng được một ứng dụng Web thì cần có nhiều phần khác nhau, đòi hỏi sự tham gia của nhiều lập trình viên với các kỹ năng khác nhau, cũng vì thế mà khái niệm Web Developer khá là rộng và dùng cho nhiều ngôn ngữ lập trình khác nhau. Bài viết hôm nay mình sẽ cùng các bạn tìm hiểu về ngành này cũng như lộ trình học để trở thành một Web Developer nhé.

Web Developer là gì?

Lập trình viên Web là những người sử dụng ngôn ngữ lập trình để xây dựng, phát triển, vận hành và bảo trì các website, ứng dụng trên nền tảng web và chạy với các trình duyệt web. Có nhiều ngôn ngữ cùng thư viện đa dạng mà các Web Developer có thể sử dụng: từ Java, JavaScript đến C, Python, Ruby, …

Một website cơ bản thông thường được chia thành 2 phần chính bao gồm phần hiển thị với khách hàng (gọi là clientside) và phần xử lý dữ liệu, tiếp nhận yêu cầu trả về kết quả (gọi là server side). Cũng vì thế mà khi nhắc đến Web Developer thì thường sẽ chia ra làm 3 công việc chính, bao gồm:

  • Frontend Developer: thiết kế, xây dựng giao diện người dùng ở phía client
  • Backend Developer: xây dựng ứng dụng chạy trên server tiếp nhận xử lý yêu cầu gửi đến từ client, thực hiện đọc ghi dữ liệu cập nhật vào cơ sở dữ liệu (database) và trả về kết quả
  • Full Stack Developer: đây là những lập trình viên có thể làm được cả 2 công việc Frontend và Backend trong cùng 1 dự án phát triển Web. Có thể sử dụng một vài ngôn ngữ lập trình cùng lúc để viết code xuyên suốt cả 2 bên trong dự án.

  5 lỗi sai các Web Developers newbie thường mắc phải và cách khắc phục

Web Developer là gì?

Những kỹ năng cần có của một Web Developer

Như đã nói ở trên, Web Developer được chia thành nhiều vị trí khác nhau trong một dự án phát triển, vì thế với mỗi vai trò sẽ cần những kỹ năng cụ thể khác nhau. Tất nhiên cũng có những kỹ năng mà bất cứ lập trình viên Web nào cũng nên được trang bị, cụ thể:

  • Kiến thức cơ bản về web: những khái niệm liên quan đến Internet về hosting, domain, dns, http, … hay cách trình duyệt (browsers) hoạt động là những kiến thức cơ bản nhất của hệ thống Web mà bất cứ lập trình viên làm Web nào cũng cần nắm vững. Chúng ta cũng hiểu rõ phương thức giao tiếp giữa client và server trong hệ thống sẽ làm, thông thường là thông qua cách gọi API, gửi request và nhận response cùng với các phương thức giao tiếp hỗ trợ.
  • Ngôn ngữ lập trình, quản lý source code: Lập trình viên thì đương nhiên là sẽ viết code, tùy vào phần dự án bạn tham gia mà sẽ cần trang bị kiến thức lập trình tương ứng. HTML, CSS, JS với Frontend, Java, C#, Ruby, PHP … với Backend. Cùng với đó, kỹ năng quản lý source code bằng các tool như Git, SVN là điều bắt buộc để có thể tham gia vào bất cứ dự án nào.
  • Sử dụng các tool làm việc với API và Database: dữ liệu trong ứng dụng Web sẽ được lưu vào cơ sở dữ liệu, vì thế bạn cần biết cách thao tác với Database thông qua các câu query SQL hoặc với các hệ thống noSQL. Cùng với đó là để kiểm tra cách giao tiếp giữa Frontend và Backend thì bạn cần biết cách sử dụng tool như Postman để có thể gọi thử API.
  • Kiến thức về nghiệp vụ: mỗi ứng dụng web được tạo ra đều có mục đích sử dụng hay giải quyết một vấn đề cụ thể cho khách hàng. Chẳng hạn một bệnh viện cần tạo ra hệ thống đặt khám cho người bệnh, một cửa hàng cần website bán đồ trực tuyến, … Để lập trình bạn cần hiểu về nghiệp vụ, về business logic của hệ thống, từ đó mới viết ra được những dòng code phù hợp, tạo ra được hệ thống hữu ích.
  • Kỹ năng làm việc nhóm: đây là điều rất quan trọng với mọi lập trình viên, càng quan trọng hơn khi gần như Web Developer sẽ làm việc nhóm trong một dự án. Việc giao tiếp, đọc hiểu, cùng giải quyết vấn đề để đảm bảo lợi ích của dự án là điều quan trọng và cũng không hề dễ dàng để học.

Tham khảo việc làm Web Developer hấp dẫn trên TopDev!

Những kỹ năng cần có của một Web Developer

Lộ trình trở thành Web Developer

Dựa trên những kỹ năng cần có của một Web Developer, để trở thành lập trình viên Web, bạn hãy trang bị các kiến thức cơ bản chung về ngành ở bước đầu tiên bao gồm kiến thức về ngành, về Internet, về lập trình, quản lý code hay sử dụng các tool làm việc như Postman, DevTool trên Chrome, IDE Visual Studio Code, MySQL tools, …

Bước tiếp theo, hãy chọn cho mình một trong 2 hướng để bắt đầu, làm Frontend hoặc Backend. Kể cả với những bạn có mong muốn trở thành một Fullstack Developer thì việc chọn 1 hướng trước tiên cũng là điều quan trọng. Khi xác định được hướng đi, bạn sẽ học những ngôn ngữ lập trình, thư viện hay framework tương ứng. Ví dụ Frontend chúng ta bắt buộc phải biết HTML, CSS, JS ở mức thành thạo; sau đó có thể tìm hiểu chuyên sâu hơn về một trong các thư viện như React, Angular, VueJS, … để có thể làm việc. Ngược lại Backend thì sẽ bắt buộc phải nắm được về ngôn ngữ lập trình như Java, PHP, Ruby, JavaScript, … cùng với hiểu biết về database, các hệ quản trị cơ sở dữ liệu như MySQL, Oracle, MongoDB,…

Có một ngôn ngữ giúp chúng ta sớm trở thành Fullstack Developer hơn chính là JavaScript (JS), nó có thể làm được cả Frontend và Backend (sử dụng NodeJS); vì thế bạn có thể cân nhắc hướng đi này. Mặc dù vậy mình vẫn có lời khuyên là hay chuyên vào một mảng trước khi có mong muốn làm tốt cả hai thứ và trở thành một Fullstack Web Developer.

  Linux - Setup môi trường cho Web Developer

Một vài gạch đầu dòng những kỹ năng, kiến thức cần học thêm cho từng hướng mà bạn có thể tham khảo nhé:

Với Frontend:

  • Framework: React, Angular, Vue.js, Svelte
  • Package Manager: npm, yarn, pnpm
  • Formatters: ESLint, Prettier
  • Module Bundlers: Webpack, Vite
  • CSS framework: Material, Tailwind
  • Mobile, Desktop application
  • GraphQL
  • SSR, SSG

Với Backend:

  • Relational Databases: PostgreSQL, MySQL, Oracle
  • NoSQL Databases: MongoDB, Firebase
  • Kiến thức chuyên sâu về databases: Transactions, Normalization, ACID
  • Kiến thức về OS (hệ điều hành): quản lý memory, input/output
  • APIs: REST, JSON APIs, SOAP, GraphQL
  • Security: MD5, bcrypt, scrypt

Sau những kiến thức chuyên sâu hơn về cả Frontend và Backend thì bạn có thể trở thành Fullstack Web Developer; lúc đấy công việc của chúng ta sẽ bao gồm việc thiết kế và xây dựng lên những kiến trúc hệ thống Web đáp ứng nhu cầu của khách hàng.

Kết bài

Với tốc độ phát triển của Internet, nhu cầu số hóa hiện nay thì gần như tất cả các thông tin đều được đưa lên Internet và thông qua các ứng dụng website để tương tác với người dùng. Vì vậy Web Developer đang là một ngành nghề rất hot trong thời gian vừa qua cũng như thời gian sắp tới. Nếu có dự định trở thành lập trình viên Web, hãy bắt đầu ngay từ những kiến thức mình đã đưa ra trong bài nhé. Cảm ơn các bạn đã đọc bài, hẹn gặp lại trong những bài viết tiếp theo của mình

Tác giả: Phạm Minh Khoa

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

Xem thêm tuyển dụng it hấp dẫn trên TopDev

Software Developer – Cơ hội nghề nghiệp và mức lương hấp dẫn

Software Developer - Cơ hội nghề nghiệp và mức lương hấp dẫn

Trong thời đại công nghệ “bùng nổ” như hiện nay, ngành công nghiệp phần mềm đang trở thành một trong những ngành có tốc độ phát triển nhanh nhất. Trong lĩnh vực này, Software Developer đóng vai trò rất quan trọng trong việc tạo ra các sản phẩm phần mềm với những chức năng mới phục vụ nhu cầu người dùng. Vậy Software Developer là gì? Những cơ hội và thách thức của công việc này như thế nào? Hãy cùng TopDev đi tìm câu trả lời dưới bài viết này nhé!

Software Developer là gì? (Kỹ sư phần mềm)

Software Developer là gì?

Software Developer là hay còn gọi là kỹ sư phần mềm, họ là những người chịu trách nhiệm thiết kế, xây dựng và duy trì các ứng dụng phần mềm. Những ứng dụng họ tạo ra có thể là ứng dụng di động, phần mềm máy tính, hoặc bất kỳ sản phẩm phần mềm nào khác để giải quyết một vấn đề nào đó của người dùng.

  Những mẹo hay ho cho các Software Developers

Công việc của một Software Developer là gì?

Một Software Developer không chỉ đơn thuần là viết code để xây dựng phần mềm mà còn nhiều công việc liên quan khác. Cụ thể:

  • Phân tích yêu cầu khách hàng: Software Developer sẽ gặp gỡ khách hàng hoặc các bên liên quan để trao đổi, phân tích nhu cầu của họ. Từ đó hình dung được phần mềm cần tạo ra sẽ như thế nào, cần những tính năng gì để đáp ứng đúng những gì khách hàng muốn.
  • Thiết kế phần mềm: Sau khi đã thu thập đủ thông tin, các Software Developer sẽ tổng hợp lại và đưa ra ý tưởng thiết kế phần mềm, đảm bảo nó đáp ứng các yêu cầu và chức năng cần thiết.
  • Viết code: Sử dụng các ngôn ngữ lập trình như Java, C++, Python, hoặc các ngôn ngữ khác để viết mã phần mềm.
  • Giải quyết vấn đề: Phát hiện và giải quyết các vấn đề trong quá trình phát triển phần mềm.
  • Triển khai và duy trì: Software Developer sẽ hỗ trợ khách hàng trong việc chạy phần mềm, tiếp nhận các yêu cầu chỉnh sửa để cải tiến phần mềm. Họ cũng sẽ theo dõi và cập nhật phần mềm thường xuyên để đảm bảo mang lại trải nghiệm tốt nhất cho người dùng.

Tùy vào loại công ty, các yêu cầu công việc của một Software Developer có thể khác nhau, nhưng đa phần đều liên quan đến việc phát triển, xây dựng và bảo trì phần mềm.

Tham khảo việc làm Software Developer hấp dẫn trên TopDev!

Công việc của một Software Developer

Software Developer cần những kỹ năng gì?

Hiện nay, nhu cầu nhân lực trong lĩnh vực Software Developer tại Việt Nam đang ở mức cao. Tuy nhiên, số lượng ứng viên đáp ứng được nhu cầu của doanh nghiệp lại quá ít. Vậy để trở thành một ứng viên mà các doanh nghiệp đang tìm kiếm bạn cần có những kỹ năng gì?

  • Kiến thức chuyên môn: Cần phải hiểu sâu về các ngôn ngữ lập trình như Java, C++, Python, Ruby,… kiến trúc phần mềm, quy trình phát triển phần mềm, các công nghệ phần mềm và những chuẩn mực của ngành. 
  • Kiến thức về các framework: Hiểu biết về các framework phổ biến như AngularJS, ReactJS, NodeJS, Spring.
  • Tư duy logic và sáng tạo: Có khả năng giải quyết các vấn đề phức tạp bằng cách tư duy và sáng tạo để tạo ra các sản phẩm phần mềm chất lượng.
  • Kỹ năng lập trình: Có khả năng viết mã lệnh, hiểu và sử dụng các thư viện, framework và các công cụ phát triển phần mềm.
  • Kỹ năng phân tích: Có khả năng phân tích yêu cầu của khách hàng và thiết kế kiến trúc phần mềm phù hợp.
  • Kỹ năng làm việc nhóm: Có khả năng tương tác và làm việc hiệu quả với các thành viên trong team.
  • Kỹ năng tự học: Có khả năng nghiên cứu và học hỏi các công nghệ mới để cập nhật kiến thức và kỹ năng phát triển phần mềm.

  Những tựa sách nổi tiếng dành cho Software Developer - Phần 1

Cơ hội nghề nghiệp Software Developer

Cơ hội nghề nghiệp Software Developer

Với sự phát triển mạnh mẽ của công nghệ thông tin, các doanh nghiệp đang ngày càng tìm kiếm những nhân tài có khả năng phát triển và thiết kế các sản phẩm phần mềm chất lượng cao. Điều này giúp Software Developer trở thành một ngành rất tiềm năng.

Theo các thống kê, nhu cầu tuyển dụng Software Developer tại Việt Nam đang tăng trưởng mạnh mẽ và dự kiến sẽ tiếp tục gia tăng trong tương lai. Nhiều doanh nghiệp công nghệ lớn như FPT, Tiki, VNG, VCCorp,… luôn có nhu cầu tuyển dụng lập trình viên để phát triển sản phẩm và mở rộng quy mô kinh doanh.

Bên cạnh đó, Software Developer cũng có cơ hội làm việc tại các công ty phần mềm, doanh nghiệp khởi nghiệp (startup) hoặc làm việc tự do với các dự án phát triển phần mềm riêng. Ngoài ra, Software Developer cũng có thể trở thành giảng viên, nhà nghiên cứu hoặc chuyên gia tư vấn về phát triển phần mềm.

Với sự phát triển của công nghệ thông tin, cơ hội nghề nghiệp cho Software Developer sẽ còn ngày một mở rộng, đặc biệt là với những người có khả năng thích nghi nhanh với các công nghệ mới và có khả năng giải quyết các vấn đề phức tạp.

Mức lương “đáng ngưỡng mộ” của Software Developer

Mức lương của Software Developer thường khá cao, điều này phần lớn là do tính chất công việc của Software Developer đòi hỏi kiến thức chuyên môn cao và kỹ năng đặc thù trong lĩnh vực lập trình.

Theo thống kê của các trang tuyển dụng hay các báo cáo về mức lương của ngành công nghệ thông tin tại Việt Nam, mức lương trung bình của Software Developer dao động từ 15 triệu đến 25 triệu đồng mỗi tháng. Tuy nhiên, mức lương cụ thể sẽ phụ thuộc vào nhiều yếu tố như kinh nghiệm làm việc, trình độ chuyên môn, kỹ năng và năng lực của từng cá nhân.

  Bí quyết deal lương giúp bạn “lật bài ngửa” với nhà tuyển dụng

Bên cạnh đó, những người có kỹ năng và năng lực tốt hơn còn có thể nhận được mức lương cao hơn, thậm chí là mức lương gấp đôi hoặc gấp ba so với mức lương trung bình. Ngoài ra, cơ hội thăng tiến và phát triển sự nghiệp của Software Developer cũng rất cao, giúp họ có thể tăng thu nhập và đạt được thành công trong lĩnh vực công nghệ thông tin.

Tính lương chuẩn với công cụ tính lương gross – net từ TopDev

Nghề Software Developer đang trở thành một trong những lĩnh vực hot nhất hiện nay. Nếu bạn muốn trở thành một Software Developer giỏi, hãy bắt tay vào học tập và rèn luyện các kỹ năng cần thiết. Để có thêm thông tin về cơ hội nghề nghiệp của một Software Developer, bạn có thể truy cập TopDev để tìm kiếm các công việc phù hợp với năng lực và kinh nghiệm của mình. Chúc bạn tìm được công việc ưng ý!

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

Tìm việc làm IT mọi cấp độ tại TopDev

Ép Kiểu & Comment Source Code trong Java

Ép Kiểu & Comment Source Code trong Java

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

Bài hôm nay chúng ta sẽ nói về 2 vấn đề “nhỏ”, đó là ép kiểu và comment source code. Bạn cũng nên biết nhỏ ở đây là nhỏ về tổng số chữ viết, chứ thực ra hai vấn đề hôm nay đều rất quan trọng cho các bài học kế tiếp đấy nhé. Với kiến thức về ép kiểu, chúng là kiến thức nền để bạn hiểu rõ cách sử dụng các kiểu dữ liệu khác nhau trong các ứng dụng của bạn. Còn comment source code sẽ trở thành phong cách viết code sao cho có đầy đủ chú thích dễ hiểu cho chính bạn và những người khác đọc source code của bạn sau này.

Nào để hiểu nó là gì, mời bạn đến với bài học.

Khái Niệm Ép Kiểu

Trước khi đi sâu vào tìm hiểu về ép kiểu, mình cũng xin nhắc lại một chút, là chúng ta đã từng làm quen với việc khai báo một biến (hoặc hằng), khi đó bạn cần chỉ định một kiểu dữ liệu cho biến hoặc hằng đó trước khi sử dụng. Việc khai báo một kiểu dữ liệu ban đầu như vậy mang tính tĩnh. Có nghĩa là nếu bạn định nghĩa biến đó là kiểu int, nó sẽ mãi là kiểu int, nếu bạn định nghĩa nó là kiểu float, nó sẽ mãi là kiểu float. Có bao giờ bạn thắc mắc nếu đem hai biến có kiểu dữ liệu khác nhau này vào tính toán với nhau, liệu nó sẽ tạo ra một biến kiểu gì? Và liệu chúng ta có thể thay đổi kiểu dữ liệu của một biến, hay một giá trị đã được khai báo hay không?

Câu hỏi trên cũng chính là nội dung của bài ép kiểu hôm nay. Cụ thể có thể mô tả ép kiểu như sau, ép kiểu là hình thức chuyển đổi kiểu dữ liệu của một biến sang một biến mới có kiểu dữ liệu khác. Vậy việc ép kiểu này không làm thay đổi kiểu dữ liệu của biến cũ, nó chỉ giúp bạn tạo ra một biến mới với kiểu dữ liệu mới, và mang dữ liệu từ biến cũ sang biến mới này. Khái niệm là vậy, còn mục đích là gì các bạn hãy đọc tiếp bài học hôm nay nhé.

Nên nhớ là vì các bạn chỉ mới làm quen với kiểu dữ liệu nguyên thủy, nên ép kiểu hôm nay cũng chỉ nói đến ép kiểu dữ liệu nguyên thủy mà thôi.

  Khai báo hàm khởi tạo trong Java – Constructor Declarations

  Ngôn ngữ Java: Không bao giờ là quá trễ để học thêm về nó

Phân Loại Ép Kiểu

Nếu phân loại ép kiểu dựa vào khả năng lưu trữ của biến, thì chúng ta có hai loại ép kiểu sau.

  • Nới rộng (widening) khả năng lưu trữ. Việc ép kiểu này sẽ làm chuyển đổi dữ liệu từ kiểu dữ liệu có kích thước nhỏ hơn sang kiểu dữ liệu có kích thước lớn hơn. Điều này không làm mất đi giá trị của dữ liệu sau khi thực hiện việc ép kiểu. Ví dụ ban đầu bạn có một biến kiểu int, có giá trị là 6, bạn ép dữ liệu từ kiểu int sang float, rồi gán vào biến mới float, thì biến mới float sẽ mang giá trị 6.0f. Việc ép kiểu theo dạng này thông thường người ta cứ để cho hệ thống thực hiện một cách ngầm định.
  • Thu hẹp (narrowing) khả năng lưu trữ. Việc ép kiểu này sẽ làm chuyển đổi dữ liệu từ kiểu dữ liệu có kích thước lớn hơn sang kiểu dữ liệu có kích thước nhỏ hơn. Điều này có thể làm mất đi giá trị của dữ liệu. Ví dụ bạn ban đầu bạn có một biến kiểu float, có giá trị là 6.5, bạn ép dữ liệu từ kiểu float sang int, rồi gán vào biến mới int, thì biến mới int sẽ mang giá trị 6. Việc ép kiểu này không thể để cho hệ thống thực hiện một cách ngầm định được, lúc này hệ thống sẽ báo lỗi, bạn phải thực hiện ép kiểu tường minh cho nó.

Tham khảo việc làm Java hấp dẫn trên TopDev

Kiểu phân loại thứ hai được chia làm hai dạng, đó là ngầm định và tường minh như mình có nhắc đến trên đây. Việc chia thành hai dạng này mang tính đặt tên để gọi đến, với lại để cho bạn nắm được cách gọi phòng khi bạn đọc tài liệu đâu đó có dùng đến các từ này, bản chất của nó vẫn tương ứng với phân biệt theo khả năng lưu trữ trên kia.

  • Ép kiểu ngầm định. Việc ép kiểu này có thể diễn ra một cách tự động bởi hệ thống, khi hệ thống phát hiện thấy cần phải thực hiện việc ép kiểu, nó sẽ tự thực hiện. Như mình có nhắc đến ở ngay trên đây, ép kiểu ngầm định chính là nới rộng khả năng lưu trữ, kiểu nới rộng này sẽ không làm mất đi giá trị của dữ liệu. Khi bắt đầu thực hiện ép kiểu, hệ thống sẽ kiểm tra các nguyên tắc sau, nếu thỏa sẽ ép.
    • byte có thể ép kiểu sang shortintlongfloatdouble.
    • short có thể ép kiểu sang intlongfloatdouble.
    • int có thể ép kiểu sang longfloatdouble.
    • long có thể ép kiểu sang floatdouble.
    • float có thể ép kiểu sang double.
  • Ép kiểu tường minh. Khi không thỏa điều kiện để có thể tự động ép kiểu, thì hệ thống sẽ báo lỗi. Việc còn lại là bạn phải chỉ định ép kiểu một cách tường minh. Vì cách ép kiểu này có thể làm mất đi giá trị của dữ liệu, cho nên rất cần bạn đưa ra quyết định, chứ hệ thống không dám tự quyết. Bạn sẽ chỉ định như sau khi muốn thực hiện việc ép kiểu tường minh này.
(kiểu_dữ_liệu_cần_ép) tên_biến;

Bài Thực Hành Số 1

Bài thực hành này sẽ giúp bạn làm quen với dạng ép kiểu ngầm định. Với cách ép kiểu này bạn chú ý là chúng ta không cần làm gì cả, cứ code đi rồi hệ thống sẽ tự thực hiện việc ép kiểu thôi. Bạn hãy nhìn code sau.

public class MyFirstClass {
    public static void main(String[] args) {
        byte b = 50;
        short s = b;
        int i = s;
        long l = i;
        float f = l;
        double d = f;

        System.out.println("This is a byte: " + b);
        System.out.println("This is a short: " + s);
        System.out.println("This is a int: " + i);
        System.out.println("This is a long: " + l);
        System.out.println("This is a float: " + f);
        System.out.println("This is a double: " + d);
        System.out.println("What type is it? " + (i + f));
    }
}

Bạn thấy với b ban đầu được khai báo là kiểu byte với giá trị 50. Sau phép gán cho biến s (giá trị là short) thì giá trị 50 trong biểu thức này được chuyển tự động thành kiểu giữ liệu short cao hơn và gán vào biến s. Tương tự cho các phép gán vào ilfd.

Dòng cuối cùng in ra “What type is it?” cho thấy một dạng ép kiểu ngầm định khác của hệ thống. Khi này bạn không khái báo trước một kiểu dữ liệu nào cả mà dùng hai biến có các kiểu int và float vào biểu thức. Bạn thấy hệ thống sẽ tự ép kiểu dữ liệu nhỏ hơn về kiểu lớn hơn, cụ thể lúc này là ép int về float và thực hiện phép cộng với hai số float. Kết quả chúng ta có một kiểu float in ra màn hình.

Bạn hãy so sánh kết quả in ra như hình sau.

Kết quả sau khi ép kiểu ngầm định
Kết quả sau khi ép kiểu ngầm định

Nhưng nếu bạn thử trắc nghiệm bằng cách kêu hệ thống ép một kiểu dữ liệu lớn hơn về kiểu nhỏ hơn xem. Hệ thống sẽ báo lỗi ngay. Và vì vậy bạn cần phải can thiệp mục kế tiếp dưới đây.

int i = 50;
short s = i;

Bài Thực Hành Số 2

Quay lại ví dụ báo lỗi trên đây, hệ thống đã từ chối tự động ép kiểu ngầm định, vậy nếu vẫn có nhu cầu muốn ép kiểu thì bạn hãy ép kiểu tường minh cho nó, lúc này bạn cần dùng đến cấu trúc ép kiểu tường minh mà mình có đưa ra ở trên kia, như vầy.

public class MyFirstClass {
    public static void main(String[] args) {
        int i = 50;
        short s = (short) i;

        System.out.println("This is a short: " + s);
    }
}

Bạn hãy nhìn vào dòng

short s = (short) i;

, dòng này sẽ ép kiểu giá trị của i về short và gán cho biến s. Việc bạn chỉ định ép kiểu với (short) nhìn vào là biết ý đồ ngay, vì vậy mới có cái tên là tường minh.

Bạn hãy xem một ví dụ nữa thực tế hơn, có một số trường hợp bạn muốn bỏ dấu thập phân của một kiểu số thực, cách nhanh nhất để làm điều này là ép kiểu số thực này về một kiểu số nguyên. Cách ép kiểu này thực chất là làm mất giá trị của biến một cách… cố tình.

public class MyFirstClass {
    public static void main(String[] args) {
        double d = 7.5;
        int i = (int) d;

        System.out.println("This is a int: " + i);
        System.out.println("This is a double: " + d);
    }
}

Kết quả của việc ép kiểu này được in ra như sau, bạn chú ý dòng in ra kiểu int nhé, mất tiêu phần thập phân rồi.

Kết quả sau khi ép kiểu tường minh
Kết quả sau khi ép kiểu tường minh

Comment Source Code

Vì kiến thức về ép kiểu ngắn quá, nên mình nói luôn về comment source code ở bài này. Hai kiến thức này không ăn nhập gì với nhau hết, nhưng nó sẽ giúp bổ trợ tốt cho bạn trong quá trình code đấy.

Sở dĩ mình dùng từ comment chứ không dịch sang tiếng Việt là vì để tránh hiểu lầm thôi, vì đa số các bạn đều biết comment nghĩa là “bình luận”, nhưng thực ra mục đích của comment trong việc code lại chính là “ghi chú” hay “chú thích”. Nó giúp bạn giải nghĩa cho một số dòng code, bạn có thể comment thoải mái ở bất kỳ đâu trong source code, trình biên dịch sẽ bỏ qua các comment này khi build, do đó sẽ không có lỗi xảy ra với chúng.

Cách Thức Comment

Bạn có 3 cách comment như sau.

  • // text

    . Khi trình biên dịch gặp ký hiệu //, nó sẽ bỏ qua tất cả các ký tự từ // đến ký tự cuối cùng của dòng đó. Như vậy với mỗi // sẽ giúp bạn comment được 1 dòng.

  • /* text */

    . Khi trình biên dịch gặp ký hiệu /*, nó sẽ bỏ qua tất cả các ký tự từ /* đến hết */. Cách comment này có thể giúp bạn comment được nhiều dòng cùng lúc.

  • /** document */

    . Tương tự như trên nhưng bạn chú ý có hai dấu * khi bắt đầu. Cách comment này giúp trích xuất ra các tài liệu hướng dẫn. Người ta gọi là document. Cách comment này mình đã nói rõ hơn ở bài viết này.

Bài Thực Hành Số 3

Với bài thực hành này bạn hãy tiến hành gõ comment tổng hợp “3 trong 1” sau đây, mình đã gộp cả ba cách comment được nói ở trên vào một chương trình. Thực ra thì bạn không cần phải comment quá nhiều như ví dụ, bạn nên comment khi cần thiết phải giải nghĩa cho một dòng code lạ nào đó, hoặc ghi chú tác giả dòng code đó là bạn, hoặc ngày sửa chữa dòng code này,…

public class MyFirstClass {

    /**
     * Kiểu comment cho document, sẽ được nói đến sau
     *
     * @param args
     */
    public static void main(String[] args) {

        // Comment một dòng
        // Muốn dòng thứ 2 thì như thế này
        double d = 7.5;
        int i = (int) d; // Cast the double into int

        /*
         * Các câu lệnh bên dưới sẽ in ra console,
         * và có thể comment nhiều dòng như sau
         * một dòng nữa, chỉ cần enter mà thôi
         */
        System.out.println("This is a int: " + i);
        System.out.println("This is a double: " + d);
    }
}

Kết Luận

Bạn vừa xem qua các cách thức ép kiểu trong Java, và các cách thức comment source code. Bài học này tuy nhẹ nhưng rất quan trọng nhé, bạn sẽ sử dụng việc ép kiểu và thực hiện việc comment thường xuyên trong các project của mình.

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

Xem thêm:

Tìm việc làm IT mọi cấp độ tại TopDev

Khám phá môi trường làm việc đa văn hoá tại Katalon – start-up Việt ghi danh trên bản đồ công nghệ thế giới

Khám phá môi trường làm việc đa văn hoá tại Katalon - start-up Việt ghi danh trên bản đồ công nghệ thế giới

Được thành lập vào năm 2016, Katalon là một công ty sản phẩm toàn cầu cung cấp nền tảng quản lý chất lượng toàn diện (Quality Management Platform), phục vụ hơn 30,000 đội ngũ phát triển phần mềm ở hơn 175 quốc gia và được Gartner Peer Insights trao giải Best Test Automation (Công cụ kiểm thử tự động tốt nhất) năm 2022. Với 2 trụ sở chính đặt tại Mỹ và Việt Nam, Katalon đang từng bước mở rộng nguồn nhân lực ra quy mô toàn cầu, đáp ứng nhu cầu ngày một tăng của thị trường. 

Thành công đến từ đội ngũ nhân lực tài năng và đa văn hoá 

Katalon được vận hành bởi đội ngũ lãnh đạo, kỹ sư, chuyên viên kinh doanh và marketing làm việc chính tại văn phòng Việt Nam, Mỹ và một số quốc gia khác như Ấn Độ, Pháp, Canada, Australia, Myanmar. Khởi nguồn từ vườn ươm công nghệ với 6 thành viên, công ty đã phát triển “thần tốc”, xây dựng đội ngũ nhân sự hơn 300 người và tiếp tục lên kế hoạch tuyển dụng thêm nguồn nhân lực tài năng trên toàn cầu.

Với phương châm con người là cốt lõi của thành công, Katalon hướng tới xây dựng đội ngũ tinh nhuệ, có kiến thức chuyên sâu để phát triển sản phẩm tạo được uy tín trên thế giới, đồng thời thích ứng với những yêu cầu cao từ khách hàng doanh nghiệp quốc tế. 

Văn hoá doanh nghiệp hướng tới sự gắn kết 

Vào năm 2022, sau vòng khảo sát minh bạch với sự giám sát tiêu chuẩn quốc tế được thực hiện bởi tổ chức Great Place To Work (GPTW), Katalon chính thức được công nhận là “Nơi làm việc tuyệt vời” ở cả hai văn phòng Việt Nam và Mỹ. Đây là danh hiệu uy tín dành cho những công ty chú trọng văn hóa doanh nghiệp và độ tin cậy của nhân viên. 

Tại Katalon, ngoài giờ làm việc, những hoạt động gắn kết nội bộ như câu lạc bộ thể thao, giải trí, các chương trình đào tạo và phát triển bản thân… thường xuyên được đẩy mạnh nhằm tạo điều kiện cho mọi nhân viên tận hưởng và phát huy tối đa khả năng trong một môi trường lành mạnh, năng động và cởi mở. 

Môi trường hiện đại thúc đẩy mô hình làm việc linh hoạt 

Văn phòng Katalon lấy cảm hứng chủ đạo từ yếu tố công nghệ, mang đến phong cách hiện đại và ứng dụng không gian mở để tăng cường kết nối, hợp tác giữa các nhân viên. Các không gian làm việc, phòng họp và sinh hoạt chung cũng được chú trọng để làm nổi bật sự hiện đại, minh bạch và linh hoạt, đáp ứng được nhu cầu tăng trưởng nhân sự, mở rộng kinh doanh trong thời gian sắp tới. ​​

Từ nền tảng con người vững chắc, Katalon và hành trình ươm mầm tài năng trí tuệ Việt sẽ tiếp tục là điểm sáng trên bản đồ công nghệ thế giới. Công ty sẽ tiếp tục tổ chức nhiều chương trình, hoạt động tuyển dụng nhằm thu hút nguồn nhân lực chất lượng cao. Katalon luôn sẵn sàng đón chào các thành viên mới để cùng phát triển và vươn xa đến những mục tiêu xa hơn trong tương lai. Tìm hiểu về những vị trí Katalon đang tuyển dụng ngay tại: katalon.com/careers. 

Xem thêm:

Tìm việc làm IT lương cao, đãi ngộ hấp dẫn trên TopDev!

Shopify Developer là gì? Học gì để làm Shopify

Shopify Developer là gì? Học gì để làm Shopify

Thương mại điện tử (e-commerce) là sự mua bán sản phẩm hay dịch vụ trên các hệ thống điện tử thông qua Internet; sự phát triển rất nhanh của nó cũng giúp anh em lập trình chúng ta có thêm nhiều công việc liên quan đến xây dựng những website bán hàng online. Cùng với đó, có nhiều nền tảng có sẵn giúp chúng ta có thể nhanh chóng tạo ra website thương mại điện tử, nổi bật là Shopify. Bài viết hôm nay mình cùng các bạn tìm hiểu về công việc của một Shopify Developer là gì? và cần học những gì để đáp ứng được nhu cầu của ngành này nhé.

Shopify là gì?

Shopify là một nền tảng thương mại điện tử, nơi mà người dùng có thể tạo cửa hàng online tích hợp việc đăng dịch vụ, sản phẩm, xử lý đơn hàng, tính năng giỏ hàng, thanh toán hay liên kết mạng xã hội. 

Shopify là gì?

Shopify cung cấp nền tảng dưới dạng SaaS (Software as a Service), tức là hệ thống core và nền tảng đều được host trên hệ thống của riêng Shopify; bạn không cần phải download source code về, chỉnh sửa và deploy lên hosting riêng của mình mà hoàn toàn làm trực tiếp trên hệ thống có sẵn mà Shopify cung cấp.

Shopify ra đời từ năm 2006, theo số liệu thống kê, đến năm 2021, có đến 1.58 triệu websites chạy trên nền tảng Shoptify. Với ưu điểm về mặt thiết kế chuyên nghiệp, giao diện đẹp mắt và thân thiện với người dùng, Shopify đã thu hút được nhiều doanh nghiệp lớn nhỏ trên toàn thế giới sử dụng.

  Android Developer là gì? Tất tần tật những điều cần biết

Shopify Developer là gì?

Shopify Developer là thuật ngữ để chỉ những lập trình viên làm việc trên nền tảng Shopify, không chỉ là lập trình mà còn là những công việc hỗ trợ khách hàng khác nhằm tối ưu hóa khả năng kinh doanh thương mại điện tử trên nền tảng này.

Tương tự như các nền tảng SaaS khác, cũng có những vị trí công việc dành cho Shopify Developer như sau:

Shopify Developer là gì?

Trong đó:

  • Custom Plugins: chỉnh sửa, tạo ra các plugins tùy biến chạy trên nền Shopify để thực hiện các tác vụ nhất định. Shopify cho phép publish các plugins để các bạn bán, kinh doanh chúng. Những người dùng Shopify khác sẽ trả tiền cho bạn nếu plugins của bạn hữu ích và phù hợp cho mục đích sử dụng của họ. 
  • Theme design: tương tự như plugins, lập trình viên cũng có thể tạo ra các theme chạy trên nền tảng Shopify và kinh doanh chúng.
  • Store Development: công việc xây dựng và phát triển cửa hàng (store) trên nền tảng Shopify
  • Shop customization: tùy biến gian hàng của bạn với các theme hay plugin cần thiết

Tham khảo việc làm Shopify hấp dẫn trên TopDev

Phát triển giao diện

Phát triển giao diện

Shopify phát triển ngôn ngữ riêng dành cho việc lập trình giao diện của nó, được đặt tên là Liquid. Liquid là một mã nguồn mở dựa trên nền tảng ngôn ngữ lập trình Ruby, sử dụng sự kết hợp các tag, object và filter để tải những nội dung động. Các tag trong Liquid cũng tương tự các tag trong HTML, ngay cả cách đặt tên file HTML và CSS thì Liquid cũng chỉ thêm đuôi .liquid đằng sau và vẫn giữ nguyên định dạng file css hay js, chẳng hạn: main.css.liquid hay scripts.js.liquid.

Để lập trình giao diện với Shoptify, chúng ta cần học về Liquid; nếu đã có kiến thức về HTML, CSS hay JS thì việc này cũng không mất quá nhiều thời gian. Để tạo ra 1 giao diện Shopify mới, thông thường bạn sẽ bắt đầu bằng cách sử dụng 1 Starter Theme (một dạng code mẫu mà Shopify cung cấp dành riêng cho lập trình viên), trong đó đã bao gồm tool hỗ trợ compile code và sync (đồng bộ) với live theme 1 cách dễ dàng.

Sau khi hoàn thành một Theme của Shopify, bạn có thể publish (phát hành) nó trên Theme store của Shopify ở địa chỉ https://themes.shopify.com/ , hoặc trên các website, chợ giao diện như ThemeForest, CreativeMarket, … Lưu ý là bạn cần tuân thủ các quy định chặt chẽ của Shopify để có thể phát hành trên Theme Store bao gồm việc cung cấp cả mockup và bản mô tả các đặc tính nổi bật của giao diện.

  Unity Developer là gì? Cần học gì để trở thành Unity Developer

Phát triển ứng dụng trên nền tảng Shopify

Thực tế ở vị trí là lập trình viên Shopify (Shopify Developer) thì việc xây dựng, phát triển store trên nền tảng Shopify sẽ yêu cầu cả việc chỉnh sửa, tùy biến giao diện Shopify theme. Công việc mà 1 Shopify Developer đảm nhận bao gồm:

  • Tham gia phân tích, thiết kế website trên platform Shopify
  • Hỗ trợ kỹ thuật, cấu hình, cài đặt cho khách hàng
  • Chỉnh sửa, tùy biến giao diện website theo yêu cầu
  • Xây dựng các plugins cần thiết trên website Shopify
  • Hỗ trợ kết nối, lấy dữ liệu giữa nền tảng Shopify và các nền tảng khác

Như vậy chúng ta có thể thấy lập trình Shopify không phân chia rõ rệt Frontend hay Backend như lập trình Web thông thường; trong quá trình làm việc với nền tảng thương mại điện tử này, bạn cần biết cả về Frontend để chỉnh sửa giao diện, cũng cần biết về Backend trong việc xử lý dữ liệu hay kết nối các nền tảng khác; và cũng cần có kiến thức về hệ thống khi setup, cấu hình website. Các kỹ năng cần học để đáp ứng yêu cầu trở thành một Shopify Developer như sau:

  • Có hiểu biết về mảng thương mại điện tử (e-commerce), lĩnh vực mà chúng ta sẽ tham gia lập trình
  • Kiến thức về HTML, CSS, JS: đây là điều cơ bản mà lập trình viên làm Web đều cần nắm được
  • Kiến thức về lập trình sử dụng ngôn ngữ Liquid: ngôn ngữ sẽ được sử dụng trong lập trình Shopify
  • Có kiến thức về một hoặc một vài framework JS khác: sẽ giúp bạn tự tin khi viết các ứng dụng kết nối đến Shopify
  • Tìm hiểu về Shopify, tài liệu hỗ trợ dành cho lập trình viên được mô tả đầy đủ trong document của Shopfy, vì thế bạn cần đọc và nắm được chúng
  • Kiến thức về hệ thống: domain, hosting và cũng nên tìm hiểu về Docker Server
  • Kiến thức về xử lý dữ liệu, về SEO, …
  • Nếu muốn trở thành nhà phát hành các themes, plugins cho nền tảng Shopify thì bạn cũng cần trang bị thêm kiến thức liên quan đến các market, store phát hành như Theme store hay ThemeForest, …

Kết bài

Hiện nay các công ty làm về thương mại điện tử có nhu cầu tuyển dụng lập trình viên Shopify là rất lớn, các bạn có thể dạo qua các trang tuyển dụng để thấy được mức độ phổ biến của nó. Để trở thành Shopify Developer không quá khó với các bạn đã có kiến thức cơ bản về lập trình Web, vì vậy đây cũng là một lựa chọn tiềm năng nếu bạn muốn đi sâu vào một mảng hiểu biết nhất định, cụ thể là thương mại điện tử. Hy vọng bài viết này đã đem lại cho các bạn một chút kiến thức hữu ích về ngành nghề này. Cảm ơn các bạn đã đọc và theo dõi, hẹn gặp lại trong các bài viết tiếp theo của mình.

Tác giả: Phạm Minh Khoa

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

Xem thêm các việc làm lĩnh vực IT hấp dẫn trên TopDev

Hướng dẫn viết code PHP chuẩn – PSR tiêu chuẩn khi lập trình PHP

Hướng dẫn viết code PHP chuẩn – PSR tiêu chuẩn khi lập trình PHP

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

Lý do bạn nên viết code theo tiêu chuẩn PSR:

  1. PSR là tiêu chuẩn code được áp dụng vào các dự án lớn hoặc framework PHP (Cakephp, Composer, Phalcon, Magento,…).
  2. Viết code chuẩn giúp bạn và đồng đội dễ dàng hiểu code của nhau.
  3. Thống nhất chung về cách thức viết code, tổ chức các class,…
  4. Dễ dàng đọc, hiểu, trình bày khỏi mất công bản thân “tự chế” kiểu code không giống ai.

PSR là gì?

PSR có nghĩa là PHP Standards Recommendations, nó là tiêu chuẩn được khuyến nghị áp dụng khi lập trình PHP và được các lập trình viên, tổ chức chấp nhận sử dụng.

PSR được soạn thảo, đánh giá và khuyến khích sử dụng bởi một nhóm chuyên gia PHP những người phát triển cho các Framework và hệ thống PHP phổ biến (thành viên PSR).

PSR bao gồm 7 phần (http://www.php-fig.org/psr/) từ PSR-1, PSR-2, PSR-3, PSR-4, PSR-6, PSR-7. Các tiêu chuẩn thành phần hoàn chỉnh của PSR đó gồm:

  • Basic Coding Standard: Tiêu chuẩn cơ bản khi viết code PHP
  • Coding Style Guide: Tiêu chuẩn trình bày code
  • Logger Interface: Giao diện logger
  • Autoloading Standard: Tiêu chuẩn về tự động nạp
  • Caching Interface: Giao diện về Caching
  • HTTP Message Interface: Tiêu chuẩn Giao diện thông điệp HTTP

  PHP Autoloading là gì? PSR-4 autoloading với Composer

  Code PHP chuẩn convention với PHP CodeSniffer


1. PSR-1 Basic Coding Standard (Tiêu chuẩn cơ bản khi viết code PHP)

PRS-1 là các nguyên tắc mỗi lập trình viên PHP nên theo để đảm bảo code dễ đọc, bảo trì, và dễ sử dụng lại cũng như chia sẻ cho đồng đội.

1. Nguyên tắc chung nhất khi code PHP

  • Các file code PHẢI sử dụng thẻ <?php hoặc <?
  • File code PHP sử dụng encode: UTF-8 without BOOM
  • Các Files NÊN hoặc dùng để khai báo các thành phần PHP (các lớp, hàm, hằng …) hoặc dùng với mục đích làm hiệu ứng phụ (như include, thiết lập ini cho PHP …), nhưng KHÔNG NÊN dùng cả 2 cùng lúc trong 1 file (Xem ví dụ này ở  Ví dụ 1)
  • Các Namespace và classes PHẢI theo chuẩn “autoloading” PSR: [PSR-4]
  • Tên lớp PHẢI có dạng NameClass (chữ không nameclass, Nameclass, namClass …)
  • Hằng số trong class tất cả PHẢI viết HOA và chia ra bởi dấu _ (ví dụ ahdsoft_member).
  • Tên phương thức của lớp PHẢI ở dạng camelCase (từ đầu viết thường, ví dụ: helloWorld).

Ví dụ 1)

File PHP viết không theo chuẩn, trộn lẫn lung tung hiệu ứng phụ và khai báo các đối tượng ngôn ngữ PHP.

<?php
// hiệu ứng phụ: đổi thiết lập ini
ini_set('error_reporting', E_ALL);

// hiệu ứng phụ: nạp file vào
include "file.php";

// hiệu ứng phụ: xuất dữ liệu
echo "<html>\n";

// khai báo hàm
function foo()
{
    // function body
}

Đoạn mã PHP sau đúng chuẩn, đã khai báo thì không gồm hiệu ứng phụ

<?php
// declaration
function foo()
{
    // function body
}

if (! function_exists('bar')) {
     //Khai báo hàm
    function bar()
    {
        // function body
    }
}

Xem ngay tin tuyển dụng PHP lương cao trên TopDev

2. Các Namespace và tên Class

Namespace và Lớp PHẢI theo chuẩn “autoloading” PSR: [PSR-4]

Có nghĩa là mỗi lớp được khai báo trên mỗi file PHP riêng và namespace tối thiểu có một cấp, cấp đầu là tên vendor.

Tên lớp lại PHẢI đúng dạng NameClass.

Ví dụ đúng chuẩn:

<?php
namespace Vendor\Model;

class Foo
{
}

3. Hằng, Thuộc tính và Phương thức của lớp

Hằng theo chuẩn ở trên, tất cả PHẢI viết hoa, phân cách từ bởi _

Ví dụ hằng đúng chuẩn:

<?php
namespace Vendor\Model;

class Foo
{
    const VERSION = '1.0';
    const DATE_APPROVED = '2012-06-01';
}

2. PSR-2 Coding Style Guide (Tiêu chuẩn trình bày code)

PSR-2 sẽ tạo cho bạn thói quen viết code đúng chuẩn, dễ đọc, đẹp.

Tổng quan về trình bày code PHP

  • Code PHẢI tuân thủ PSR-1
  • Code PHẢI sử dụng 4 ký tự space để lùi khối (không dùng tab)
  • Mỗi dòng code PHẢI dưới 120 ký tự, NÊN dưới 80 ký tự.
  • PHẢI có 1 dòng trắng sau namespace, và PHẢI có một dòng trắng sau mỗi khối code.
  • Ký tự mở lớp { PHẢI ở dòng tiếp theo, và đóng lớp } PHẢI ở dòng tiếp theo của thân class.
  • Ký tự { cho hàm PHẢI ở dòng tiếp theo, và ký tự } kết thúc hàm PHẢI ở dòng tiếp theo của thân hàm.
  • Các visibility (public, private, protected)  PHẢI được khai báo cho tất cả các hàm và các thuộc tính của lớp;
  • Các từ khóa điều khiển khối(if, elseif, else) PHẢI có một khoảng trống sau chúng; hàm và lớp thì KHÔNG ĐƯỢC làm như vậy.
  • Mở khối { cho cấu trúc điều khiển PHẢI trên cùng một dòng; và đóng khối này } với ở dòng tiếp theo của thân khối.
  • Hằng số truefalsenull PHẢI viết với chữ thường.
  • Từ khóa extends và implements phải cùng dòng với class.
  • implements nhiều lớp, thì mỗi lớp trên một dòng
  • keyword var KHÔNG ĐƯỢC dùng sử dụng khai báo property.
  • Tên property KHÔNG NÊN có tiền tố _ nhằm thể hiện thuộc protect hay private.
  • Tham số cho hàm, phương thức: KHÔNG được thêm space vào trước dấu , và PHẢI có một space sau ,. Các tham số CÓ THỂ trên nhiều dòng, nếu làm như vậy thì PHẢI mỗi dòng 1 tham số.
  • abstractfinal PHẢI đứng trước visibility, còn static phải đi sau.

Ví dụ:

<?php
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleFunction($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // method body
    }
}
<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

// ... additional PHP code ...
<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // constants, properties, methods
}

Gọi phương thức và hàm

Khi gọi một hàm hay phương thức của lớp, KHÔNG ĐƯỢC có khoảng trắng giữa phương thức, hàm và toán tử và dấu ( đồng thời không được có khoảng trắng sau (. không có khoảng trắng trước ), như phần trên không được có khoảng trắng trước , nhưng PHẢI có khoảng trắng sau ,.

<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);
<?php
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

IF, ELSE, SWITCH, CASE

<?php
if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}
<?php
switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

WHILE

<?php
while ($expr) {
    // structure body
}

FOR

<?php
for ($i = 0; $i < 10; $i++) {
    // for body
}
<?php
foreach ($iterable as $key => $value) {
    // foreach body
}

TRY,CATCH

<?php
try {
    // try body
} catch (FirstExceptionType $e) {
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

Trình bày Closure

<?php
$closureWithArgs = function ($arg1, $arg2) {
    // body
};

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};

3. PSR-3 Logger Interface (Giao diện logger)

PSR-3 Logger Interface: trình bày về các thành phần cần phải có của một Logger (ghi lại dấu vết của ứng dụng).

1. Các đặc điểm kỹ thuật

  • LoggerInterface với 8 phương thức ghi log theo chuẩn RFC 5424 thương sẽ được chia thành key log: debug, info, notice, warning, error, critical, alert, emergency.
  • Mọi method chỉ chấp nhận một string tin nhắn, hoặc object dùng method a__toString() để chuyển tất cả sang tring.
  • Message phải chứa placeholders với implementors phải replace giá trị từ array.
  • Tên placeholders phải phù hợp với key log.
  • Tên placeholders phải được phân cách bằng dấu ngoặc nhọn { và dấu ngoặc nhọn }.
  • KHÔNG được chứa bất kỳ khoảng trắng giữa các ký tự tên placeholders.
  • chỉ NÊN gồm các ký tự A-Z, a-z, 0-9, dấu gạch dưới _, và thời gian,.. Việc sử dụng các ký tự khác thì để xem trong tương lai có được áp dụng không.Implementors CÓ THỂ sử dụng giữ chỗ để thực hiện các chiến lược thoát khác nhau và dịch các bản ghi để hiển thị. Người dùng KHÔNG NÊN pre-escape giá trị giữ chỗ vì họ không thể biết trong đó bối cảnh các dữ liệu sẽ được hiển thị.

Ví dụ:

/**
   * Interpolates context values into the message placeholders.
   */
  function interpolate($message, array $context = array())
  {
      // build a replacement array with braces around the context keys
      $replace = array();
      foreach ($context as $key => $val) {
          // check that the value can be casted to string
          if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
              $replace['{' . $key . '}'] = $val;
          }
      }

      // interpolate replacement values into the message and return
      return strtr($message, $replace);
  }

  // a message with brace-delimited placeholder names
  $message = "User {username} created";

  // a context array of placeholder names => replacement values
  $context = array('username' => 'bolivar');

  // echoes "User bolivar created"
  echo interpolate($message, $context);

2. Package

Các Interface và Class được mô tả chi tiết trong gói psr/log.

3. Psr\Log\LoggerInterface

<?php

namespace Psr\Log;

/**
 * Describes a logger instance
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data, the only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function emergency($message, array $context = array());

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function alert($message, array $context = array());

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function critical($message, array $context = array());

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function error($message, array $context = array());

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function warning($message, array $context = array());

    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function notice($message, array $context = array());

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function info($message, array $context = array());

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function debug($message, array $context = array());

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param string $message
     * @param array $context
     * @return null
     */
    public function log($level, $message, array $context = array());
} 

4. Psr\Log\LoggerAwareInterface

<?php

namespace Psr\Log;

/**
 * Describes a logger-aware instance
 */
interface LoggerAwareInterface
{
    /**
     * Sets a logger instance on the object
     *
     * @param LoggerInterface $logger
     * @return null
     */
    public function setLogger(LoggerInterface $logger);
} 

5. Psr\Log\LogLevel

<?php

namespace Psr\Log;

/**
 * Describes log levels
 */
class LogLevel
{
    const EMERGENCY = 'emergency';
    const ALERT     = 'alert';
    const CRITICAL  = 'critical';
    const ERROR     = 'error';
    const WARNING   = 'warning';
    const NOTICE    = 'notice';
    const INFO      = 'info';
    const DEBUG     = 'debug';
}

4. PSR-4 Autoloading Standard (Tiêu chuẩn về tự động nạp)

PSR-4 Autoloading Standard: trình bày về cách chỉ định ứng dụng tự động nạp (giống include, require) các file php, lớp, hàm khi nó cần dùng đến.

Các lớp có thể được load tự động khi dùng đến bằng cách sử dụng cơ chế autoload của PHP (http://php.net/autoload).

Để thống nhất và sử dụng dễ dàng, phù hợp với nhiều mã Autoload khác nên viết các lớp theo quy tắc sau:

* “lớp” ở đây ám chỉ cho:  class, interface,traits

* Tên xác định đầy đủ của một lớp có dạng:

\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
  • Tên xác định đầy đủ PHẢI có một namespace gốc (hiểu là tên vendor)
  • Tên xác định đầy đủ có thể có một hoặc nhiều namespace con.
  • Tên đầy đủ nó phải có một tên lớp kết thúc (ClassName)

* Khi một nạp một file thì nó phải tương ứng với một tên xác định đầy đủ của lớp.

  • Mỗi tên xác định đầy đủ phải tương ứng với một cấu trúc thư mục
  • Tên lớp kết thúc tương ứng với tên file:
<ClassName>.php

Khi viết các lớp, theo quy tắc đó thì dễ dàng phát triển một bộ tự động nạp. Autoloader để khởi tạo ứng dụng.

Tham khảo mẫu Autoloader tự động đăng ký các lớp tự động tải vào khi dùng đến, với điều kiện các lớp viết theo PSR-4.

https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md

Các Framework PHP phổ biến hầu hết theo chuẩn PSR-4, nên chúng đều có bộ Autoloader tương tự.


5. PSR-6 Caching Interface (Giao diện về Caching)

PSR-6 Caching Interface là tiêu chuẩn cần có của một bộ ứng dụng caching (lưu tạm dữ liệu và database, đĩa, RAM …)

Tham khảo thông tin tại đây


6. PSR-7 HTTP Message Interface (Tiêu chuẩn Giao diện thông điệp HTTP)

PSR-7 HTTP Message Interface là tiêu chuẩn về giao diện (thành phần cần có) của một ứng dụng sử dụng thông điệp HTTP (HTTP Message – request và respone), nó căn cứ vào các tiêu chuẩn RFC 7230RFC 7231RFC 3986.

Thông điệp HTTP là nền tảng của ứng dụng web. Các Web Browser và các trình khách HTTP như cURL tạo ra một thông điệp HTTP (HTTP request message), rồi gửi nó đến web server, server nhận được thông điệp (có thể hiểu là yêu cầu) đó, nó sẽ gửi về một thông điệp HTTP (HTTP Response message).

Cấu tạo các HTTP MESSAGE

Các HTTP message thường thì không được nhìn thấy, không cần phải hiểu bởi người dùng, nhưng với người phát triển web thì rất nên hiểu về cấu trúc để sử dụng chúng thi hành các tác vụ theo yêu cầu.

Mọi HTTP Request Message đều có dạng:

POST /path HTTP/1.1
Host: example.com

foo=bar&baz=bat

Dòng đầu tiên yêu cầu, theo thứ tự chứa thông tin: phương thức yêu cầu (POST,GET …), đích yêu cầu (thường là URI hoặc đường dẫn trên web), và phiên bản của giao thức HTTP. Theo sau là các dòng HTTP header nếu nó, một dòng trống, cuối cùng là nội dung message.

Mọi HTTP Response Message đều có dạng:

HTTP/1.1 200 OK
Content-Type: text/plain

This is the response body

Dòng đầu là dòng trạng thái, theo thứ tự chứa phiên bản giao thức HTTP, mã trả về, và dòng mô tả mã. Tiếp theo là các dòng header nếu có, tiếp theo một dòng trống và cuối cùng là nội dung của HTTP Response Message.

Thuật ngữ gợi ý của PSR bạn lưu ý đó là: PHẢI, KHÔNG PHẢI, KHUYẾN NGHỊ … đó là các từ để căn cứ để bạn quyết định áp dụng phần nào của kỹ thuật vào ứng dụng.

Tiếp theo là các mô tả và namespace, interface class, các phương thức nên theo.

Các đặc điểm kỹ thuật về HTTP MESSAGE

1) Thông điệp (Message)

Một thông điệp HTTP có thể là yêu cầu gửi đi từ client hoặc thông điệp đáp trả từ server cho client. Như vậy cần phải có các lớp định nghĩa giao diện cho các thông điệp yêu cầu (request) Psr\Http\Message\RequestInterface và giao diện thông điệp đáp trả (response) Psr\Http\Message\ResponseInterface. Cả hai loại thông điệp này đều kế thừa từ một giao diện chung có Psr\Http\Message\MessageInterface.

Psr\Http\Message\MessageInterface CÓ THỂ được viết trực tiếp, nhưng bạn NÊN có kế từ cho Psr\Http\Message\RequestInterface và Psr\Http\Message\ResponseInterface.

2) Về các HTTP Header

Không phân biệt chữ hoa – thường

Các header được truy cập bởi tên của header đó trong bởi phương thức (withHeader) trong MessageInterface và phương thức này không phân biệt chữ hoa và chữ thường.

Ví dụ:

$message = $message->withHeader('foo', 'bar');

echo $message->getHeaderLine('foo');
// Outputs: bar

echo $message->getHeaderLine('FOO');
// Outputs: bar

$message = $message->withHeader('fOO', 'baz');
echo $message->getHeaderLine('foo');
// Outputs: baz

Bởi vì tên của header khi các server trả về có chữ hoa, chữ thường nên bạn PHẢI xử lý việc này trong hàm getHeaders().

Header nhiều giá trị

Thông lệ thì các header với nhiều giá trị vẫn được dùng, header có thể nhận được từ MessageInterface như là một mảng hoặc chuỗi. Sử dụng phương thức getHeaderLine() để nhận chuỗi có chứa giá trị phân cách bởi dấu ,. Sử dụng getHeader để nhận mảng tất cả giá trị header.

Ví dụ:

$message = $message
    ->withHeader('foo', 'bar')
    ->withAddedHeader('foo', 'baz');

$header = $message->getHeaderLine('foo');
// $header chứa: 'bar, baz'

$header = $message->getHeader('foo');
// ['bar', 'baz']

Host trong Header

Khi khởi tạo thông điệp Request PHẢI thiết lập Host header từ một URI nếu Host chưa được thiết lập. Hàm RequestInterface::withUri() làm điều này.

3) Streams – Các luồng

HTTP message chứa dòng bắt đầu, các header và body(nội dung). Phần body của thông điệp có thể rất nhở hoặc rất lớn. Nếu cố tình nhét tất cả dữ liệu vào body với kiểu chuỗi thì có vẻ dễ nhưng nhiều trường hợp ảnh hưởng nghiêm trọng đến bộ nhớ lưu giữ body.  Khi dữ liệu lớn bạn sẽ sử dụng StreamInterface để diễn tả dữ liệu được đọc/ghi của body. Nhưng trường hợp này chuỗi dữ liệu body của thông điệp được sử dụng từ php://memory hoặc php://temp. (php://memory và php://temp là luồng chuẩn PHP xem tại php://)

Các Stream có thể dùng ba phương thức: isReadable(), isWritable(), isSeekable() để kiểm tra giới hạn của Stream (đọc, ghi, tìm).

Cuối cùng StreamInterface định nghĩa phương thức __toString() để nhận hoặc chuyển dữ liệu.

4) Request Targets và URIs

Request target(mục tiêu – đích của HTTP mgs) có thể ở dạng sau:

  • origin-form, chứa đường dẫn URL
  • absolute-form, chứa scheme và người gửi authority (“[user-info@]host[:port]”)
  • authority-form, chỉ chứa authority
  • asterisk-form, kiểm tra khả năng.

URL được định nghĩa bởi UriInterface, nó cung cấp __toString() để lấy URI. Nhận request target bằng phương thức getRequestTarget().

Ví dụ:

$request = $request
    ->withMethod('OPTIONS')
    ->withRequestTarget('*')
    ->withUri(new Uri('https://example.org/'));
5) Server-side Request  – các request tại server

PHP cung cấp các biến toàn cục:

  • $_COOKIE, truy cập các cookie HTTP
  • $_GET, truy cập các tham số của chuỗi query (query trong url)
  • $_POST, truy cập các tham số urlencoded được chuyển đến bởi HTTP POST
  • $_FILES, chứa thông tin mô tả về các file được upload
  • $_SERVER, truy cập các biến môi trường CGI/SAPI, chứa nhiều thứ gồm request method, scheme, URI, header.

ServerRequestInterface mở rộng từ  RequestInterface cung cấp lớp trừu tượng bao học hết các biến toàn cục trên, nó thêm một property là “attributes” dùng truy cập các thông tin.

6 Uploaded files – các file upload

ServerRequestInterface có phương thức getUploadedFiles() để nhận một cây mô tả file upload, mà mỗi lá của cây là một UploadedFileInterface. Có các phương thưc để làm việc với file, moveTo($targetPath) , _uploaded_file()

Chuẩn giao diện thông điệp HTTP bắt đầu được cung cấp bởi hầu hết các Framework PHP phổ biến. Trong tiêu chuẩn này gợi ý xây dựng các Interface, Method, Atribute để trừu tượng hóa HTTP Message.

Gợi ý này được đóng gói và được nhiều Framework làm theo, bạn lấy Package này tại https://github.com/php-fig/http-message

Các Framework xây dựng sẵn cho bạn theo PSR-7

Symfony : http://symfony.com/blog/psr-7-support-in-symfony-is-here

Zend Framework : https://zendframework.github.io/zend-expressive/

Laravel :  https://laravel.com/docs/5.1/requests


7. Các tiêu chuẩn khác

PHPDoc Standard (PSR-5), Huggable Interface(PSR-8), Security Disclosure(PSR-9), Security Advisories(PSR-10),Container Interface(PSR-11),Extended Coding Style Guide(PSR-12),Hypermedia Links(PSR-13). Bạn có thể tham khảo tại http://www.php-fig.org/psr/

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

Ngôn ngữ lập trình bậc thấp là gì?

Ngôn ngữ lập trình bậc thấp là gì?

Bài viết được sự cho phép của BBT Tạp chí lập trình

Ngôn ngữ lập trình bậc thấp, thường được gọi là ngôn ngữ mẹ đẻ của máy tính, là một loại ngôn ngữ lập trình. Nó rất gần với việc viết các hướng dẫn máy thực tế và nó liên quan đến các thành phần và ràng buộc phần cứng của máy tính.

Nó hoạt động để kiểm soát ngữ nghĩa hoạt động của máy tính và cung cấp rất ít hoặc không cung cấp các ý tưởng lập trình trừu tượng. Trái ngược với ngôn ngữ lập trình bậc cao được sử dụng để lập trình phần mềm, code bậc thấp không thể đọc được bằng con người và nó thường khó hiểu. Hợp ngữ và ngôn ngữ máy là hai ví dụ về ngôn ngữ lập trình bậc thấp.

Ngôn ngữ lập trình bậc thấp

Mục tiêu chính của ngôn ngữ lập trình bậc thấp là sử dụng các ngôn ngữ lập trình bậc cao như PHP , C# và Swift để xây dựng các chương trình phần mềm và tập lệnh vận hành, quản lý và sửa đổi kiến ​​trúc tập lệnh và phần cứng của máy tính.

Mã nguồn có thể được tạo và chỉnh sửa bởi lập trình viên phần mềm bằng ngôn ngữ lập trình bậc cao với sự trợ giúp của trình soạn thảo văn bản cơ bản hoặc IDE lập trình. Tuy nhiên, CPU không thể nhận dạng code trực tiếp. Trước đó, code được biên dịch thành ngôn ngữ bậc thấp.

Các ngôn ngữ lập trình bậc thấp có lợi thế vì các chương trình và ứng dụng được viết bằng chúng có thể được thực thi trực tiếp trên phần cứng máy tính mà không cần thông dịch hoặc phiên dịc

Ngoài ra, các ứng dụng và chương trình này có thể chạy với dung lượng bộ nhớ rất nhỏ cũng như rất nhanh. Tuy nhiên, họ cần có kiến ​​thức sâu hơn về ngôn ngữ máy; do đó, chúng có thể khó sử dụng.

  Ngôn ngữ lập trình bậc cao - Cao thấp do đâu?

Hợp ngữ bao gồm các lệnh như ADD (thêm), SUB (trừ) và MOV (di chuyển). Các lệnh này chịu trách nhiệm thực hiện các thao tác cơ bản, chẳng hạn như thực hiện các phép tính và di chuyển các giá trị vào các thanh ghi bộ nhớ. Bằng cách sử dụng một trình dịch hợp ngữ, ngôn ngữ hợp ngữ có thể được dịch sang ngôn ngữ máy.

Mức thấp nhất của ngôn ngữ máy tính là ngôn ngữ máy hoặc mã máy, bao gồm mã nhị phân. Biên dịch mã nguồn bậc cao cho một bộ xử lý nhất định thường được sử dụng để tạo mã ngôn ngữ máy. Hầu hết các lập trình viên không bao giờ yêu cầu sửa đổi hoặc thậm chí xem mã máy. Chỉ lập trình viên xây dựng hệ điều hành và trình biên dịch phần mềm mới cần xem mã máy.

Tham khảo việc làm Back-end HOT trên TopDev

Ngôn ngữ lập trình bậc thấp

C hay C++ có phải là ngôn ngữ lập trình bậc thấp không?

Các ngôn ngữ lập trình C và C++ thuộc danh mục ngôn ngữ cấp trung. Các ngôn ngữ cấp thấp cung cấp ít hoặc không có sự trừu tượng hóa các khái niệm lập trình, trong khi các ngôn ngữ lập trình C và C++ cung cấp mức độ trừu tượng thấp nhất đối với hiệu suất và hiệu quả với số tiền ít nhất.

Những trừu tượng này như macro, hàm lambda, lớp giúp lập trình viên sử dụng chức năng phức tạp trong lập trình mà không cần viết code phức tạp hơn. Vì lý do này, ngôn ngữ C và C++ được coi là ngôn ngữ lập trình bậc thấp hơn, nơi hiệu suất tối đa là tối quan trọng. Tuy nhiên, sự trừu tượng hóa là cần thiết để giữ cho code có thể duy trì và dễ đọc.

  Học lập trình có khó không? Ngôn ngữ lập trình nào "dễ học"

Lập trình cấp thấp bằng ngôn ngữ lập trình bậc cao

Ngôn ngữ lập trình bậc thấp

Vào cuối những năm 1960, các ngôn ngữ lập trình bậc cao như ALGOL mở rộng, PL/S, BCPL, BLISS và C đã cung cấp một số quyền truy cập vào các chức năng lập trình cấp thấp. Cách tiếp cận nhúng code hợp ngữ trong ngôn ngữ bậc cao được gọi là hợp ngữ nội tuyến.

Ngoài ra, một số ngôn ngữ này chứa các chỉ thị tối ưu hóa trình biên dịch phụ thuộc vào kiến ​​trúc, cho phép trình biên dịch tùy chỉnh việc sử dụng kiến ​​trúc bộ xử lý đích.

Sự khác biệt giữa ngôn ngữ lập trình bậc cao và bậc thấp

Sự khác biệt chính giữa ngôn ngữ lập trình bậc cao và bậc thấp là code cấp cao dễ đọc, diễn giải và xây dựng hơn mã máy. Mặt khác, máy móc có thể dễ dàng giải thích ngôn ngữ bậc thấp so với con người.

C, C++, Java , Python , v.v. là những ví dụ về ngôn ngữ lập trình bậc cao. Hãy xem ngôn ngữ lập trình bậc cao và bậc thấp khác nhau như thế nào:

Ngôn ngữ lập trình bậc cao Ngôn ngữ lập trình bậc thấp
Nó là một ngôn ngữ lập trình theo nghĩa thân thiện với người dùng. Nó là một loại ngôn ngữ thân thiện với máy móc.
Những ngôn ngữ này được coi là bộ nhớ kém hiệu quả hơn. Những ngôn ngữ này được coi là bộ nhớ hiệu quả cao.
Nó là đơn giản để hiểu. Thật khó để hiểu.
Thật đơn giản để khắc phục sự cố. So sánh, nó là phức tạp để gỡ lỗi.
Thật dễ dàng để theo kịp với. So sánh, rất khó để duy trì.
Ngôn ngữ lập trình bậc cao là di động. Ngôn ngữ lập trình bậc thấp không di động được.
Nó tương thích với tất cả các hệ điều hành. Nó hoàn toàn phụ thuộc vào máy.
Để dịch, cần có trình biên dịch hoặc trình thông dịch. Để dịch, nó sẽ cần một trình biên dịch chương trình.
Nó thường được sử dụng trong lập trình. Nó không còn được sử dụng rộng rãi trong lập trình nữa.

Kết luận

Tôi hy vọng bài viết này sẽ hữu ích cho bạn. Nếu bạn có bất kỳ câu hỏi nào, tôi rất sẵn lòng trợ giúp!

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

Xem thêm:

Đừng bỏ lỡ hàng loạt IT job hot tại TopDev

Tạo Splash Screen cho Android như thế nào là “chuẩn” nhất?

Tạo Splash Screen cho Android như thế nào là

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

Các bạn thân mến, vâng bài viết này chúng ta sẽ thực hành tạo một Splash Screen cho app. Mình biết rằng rất dễ để các bạn có thể tạo ra một Splash Screen cho ứng dụng, chỉ cần lên mạng search cái là xong, không cần đến bài viết này của mình đâu. Và thực tế là mình cũng đã từng xây dựng Splash Screen cho nhiều app theo cách phổ biến trên mạng, rất nhanh chóng… cho đến khi mình đọc được một bài viết (mình có để link bài viết đó ở cuối bài hôm nay) và thử nghiệm với một số app nổi tiếng hiện nay thì thấy rằng… các Splash Screen mình đã xây dựng trước đó là chưa đúng.

Vậy tại sao Splash Screen lại nhiêu khê vậy? Đâu mới là Splash Screen đúng chuẩn Android? Và cách thức để tạo Splash Screen đó như thế nào? Thì bài viết này sẽ tập trung về các vấn đề đó. Bạn hãy cùng đọc, trao đổi và thực hành tạo một project với Splash Screen đúng chuẩn xem nó như thế nào nhé.

Splash Screen Là Gì?

Mình chắc chắn nhiều bạn đã biết Splash Screen là gì. Nhưng nếu chưa biết về nó, thì đây. Splash Screen là một màn hình đặc biệt, màn hình này được hiển thị đầu tiên nhất khi bạn mở một ứng dụng. Thông thường thì Splash Screen sẽ hiển thị logo của ứng dụng, nhiều app còn để câu slogan lên đó, có khi còn có thông tin version của ứng dụng đó nữa, vân vân… Splash Screen thường chỉ xuất hiện rất nhanh, dài lắm cũng chỉ khoảng vài giây. Mình ví dụ như khi bạn mở ứng dụng Maps lên, thì Splash Screen chính là màn hình này.

Splash Screen Google Map

Splash Screen Dùng Để Làm Gì?

Nếu bạn chỉ là một user bình thường, thì chắc chắn câu trả lời sẽ là, Splash Screen giúp app trông “ngầu” hơn, “pro” hơn, đẹp hơn.

Nhưng là một Android Developer, bạn nên biết ngoài tác dụng làm đẹp ra thì Splash Screen còn có các công dụng sau:

  • Splash Screen sẽ xuất hiện rất sớm, càng sớm càng tốt, ngay khi user khởi chạy ứng dụng. Nó sẽ giúp lấp đầy cái khoảng nháy đầu tiên, khi mà hệ thống bắt đầu đánh thức ứng dụng, và ứng dụng còn đang “trở mình” thức dậy. Khoảng nháy này xuất hiện khá nhanh, nhanh như thế nào thì còn tùy theo độ “nặng” của ứng dụng và cấu hình của phần cứng. Nhưng việc có khoảng nháy rất nhỏ này cũng đủ khiến các ứng dụng bị giảm điểm trong mắt một số user.
  • Cũng nhờ vào công dụng của Splash Screen trên đây, nên các app thường tận dụng trong lúc Splash Screen hiện lên sẽ tranh thủ làm vài thao tác ở background, như download các thông tin cần thiết từ server, đọc một đoạn văn bản dài,… để khi mà Splash Screen kết thúc và nhường màn hình cho các giao diện khác, thì mọi thứ đã sẵn sàng để người dùng tương tác. Chính vì vậy bạn có thể thấy một số app hiển thị Splash Screen hơi bị lâu là vậy.

  Tổng Hợp Các Tip Khi Sử Dụng Android Studio

  10 xu hướng ứng dụng di động dự đoán sẽ thống trị năm 2024

Splash Screen Theo Kiểu Thông Thường

Như mình đã nói ở trên, có vô vàn tài liệu trên mạng nói về việc xây dựng một Splash Screen cho Android app. Và các cách phổ biến nhất là gì?

  • Bạn sẽ tạo một Activity, và dĩ nhiên xây dựng giao diện cho Activity này. Có nghĩa là bạn xem Splash Screen cũng là một Activity bình thường vậy.
  • Bạn chỉ định Activity Splash Screen này là launcher Activity, tức là nó sẽ được khởi chạy đầu tiên khi app được kích hoạt.
  • Sau khi hiển thị giao diện của nó rồi, bạn cho Activity Splash Screen này ngủ trong khoảng 3 giây, hoặc cho làm vài tác vụ background nào đó như mình nói ở trên.
  • Hết 3 giây hay xong các tác vụ background, Activity Splash Screen kết thúc và nhường màn hình lại cho các Activity khác bên trong app.

Mình gọi đây là Splash Screen kiểu thông thường, vì mình cũng đã từng xây dựng nhiều Splash Screen như vậy, rồi đồng nghiệp của mình cũng xây dựng như vậy, và những app mà mình đã đọc qua source code cũng làm như vậy, ngay cả bạn thử chạy một số app khác trong máy của bạn thì nhiều app cũng làm như vậy (làm sao biết được? Chỉ cần đọc hết bài viết hôm nay bạn sẽ biết cách phân biệt các cách xây dựng Splash Screen của các app, mình hứa đấy).

Tham khảo việc làm Android Developer Hồ Chí Minh tại TopDev

Đọc đến đây ắt hẳn bạn sẽ nghĩ rằng, nếu nhiều app dùng đến, thì nó là đúng đắn, tại sao nói là sai, là không đúng chuẩn? Thứ nhất, bạn nên biết không phải cái gì đi theo số đông cũng đúng đắn. Thứ hai, mình không nói là Splash Screen theo cách thông thường này sai, nó chỉ là chưa hợp lý mà thôi, vì sao vậy, bạn xem.

– Điều kiện tiên quyết đầu tiên của Splash Screen là nó phải được hiện lên rất nhanh ngay khi app được kích hoạt, nhanh đến nỗi user không nhận ra có khoảng nháy ở thời điểm đó. Tuy nhiên, cách xây dựng Splash Screen thông thường thực ra cũng chỉ là tạo một Activity bình thường với layout do bạn xây dựng, Activity này cũng nằm cùng cấp với các Activity khác, cũng được khởi tạo chung khi mà ứng dụng đang “thức dậy”. Chính vì vậy mà sẽ luôn luôn có khoảng nháy khi bạn xây dựng Splash Screen kiểu thông thường này, không cách nào lấp đầy UI cho khoảng nháy đó.
– Thêm nữa bạn hãy quên đi Splash Screen và xem lại định nghĩa mới của Google về Launch Screen, chúng ta sẽ tập trung vào nó.

Đâu Là Một Splash Screen Đúng Chuẩn?

Không cần bàn cãi nhiều, một Splash Screen chuẩn là một Splash Screen phải được hiển thị cực kỳ nhanh, mượt mà, và dĩ nhiên phải đẹp nữa.

Đầu tiên mình mời bạn “ngắm” một Splash Screen “chính chủ” của Google, đó là Splash Screen của app Youtube.

youtube_splashcreen

Bạn có thể thấy icon Youtube dùng làm Splash Screen xuất hiện rất nhanh ngay khi nhấn. Mặt khác nó còn có hiệu ứng bung ra theo chuẩn Material Design nữa. Splash Screen bình thường của bạn có làm được không?

Mình cho bạn xem một app nữa, không phải “chính chủ” Google nhưng cũng áp dụng khá tốt triết lý Launch Screen của Google, đó là app Uber.

uber_splashscreen

Đến lúc này chắc chắn bạn đã biết tại sao mình viết bài hôm nay rồi đúng không nào, vậy hãy bắt tay vào xây dựng một Splash Screen đúng chuẩn ngay thôi.

Xây Dựng Splash Screen Đúng Chuẩn

Tạo Mới Project

Đầu tiên nếu chưa mở Android Studio thì bạn hãy mở lên nhé. Sau khi đã mở Android Studio xong, nếu bạn đang ở màn hình Welcome (hình bên trái ở dưới), thì hãy chọn Start a new Android Studio project. Còn nếu bạn đang ở màn hình chính của Android Studio (hình bên phải ở dưới), hãy nhấn vào menu File > New > New Project….

Android Studio project

Các bước tạo một project chắc bạn cũng biết rồi, hoặc bạn có thể xem Android Bài 3 để hiểu rõ hơn. Tuy nhiên có một lưu ý, để bắt đầu xây dựng project nhanh nhất có thể thì bạn nên chọn Empty Activity khi đến bước Add an Activity to Mobile như hình sau.

Android Studio project

Tạo Giao Diện Cho Splash Screen

Nên nhớ là với việc tạo một Splash Screen theo cách này, chúng ta hoàn toàn không dùng đến layout như với các cách xây dựng Activity khác, nhằm tăng tốc thời gian hiển thị. Vì vậy mà để tạo giao diện cho nó, mình sẽ tạo một XML ở drawable, mình sẽ tạo ra một Splash Screen có background màu xám, và hiển thị launcher icon ở giữa màn hình.

Trước hết mình sẽ định nghĩa một màu xám cho background ở file res/values/colors.xml, màu xám mà mình dùng là màu có mã Hexa là #D8D8D8, như hình dưới.

Tạo Giao Diện Cho Splash Screen

Và bây giờ mới là bước quan trọng nhất của giao diện Splash Screen. Để tạo mới một XML cho drawable, bạn hãy nhấn chuột phải vào thư mục res/drawable/ và chọn New > Drawable resource file như hình sau.

Tạo Giao Diện Cho Splash Screen

Với dialog xuất hiện tiếp theo, bạn sẽ đặt tên bất kỳ cho file XML ở mục File name, mình đặt tên cho nó là là bg_splashscreen. Nên nhớ là file resource thì không đặt tên có chữ in hoa hay khoảng trắng nhé bạn, bạn có thể tham khảo thêm bài viết về resource ở đây. Quay lại với dialog, ở mục Root element bạn gõ layer-list, nhưng bạn yên tâm, chỉ cần gõ vài từ thôi hệ thống sẽ gợi ý đầy đủ text cho bạn, bạn chỉ việc nhấn phím mũi tên và chọn đúng từ được gợi ý. Thao tác ở bước này giúp tạo một resource XML với thẻ gốc là thẻ layer-list, chi tiết về cách sử dụng resource XML bạn có thể theo dõi thêm ở các bài học Android theo chương trình của mình.

Tạo Giao Diện Cho Splash Screen

Giờ đây với file bg_splashscreen.xml vừa tạo, bạn hãy thêm nội dung cho nó như sau.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:drawable="@color/gray"/>

    <item
        android:drawable="@mipmap/ic_launcher"
        android:gravity="center">
    </item>

</layer-list>

Như mình có trình bày, việc tạo ra resource này sẽ mang đến một “giao diện” XML với màu nền là xám, và một icon launcher hiển thị ở giữa. Bạn có thể dùng một ảnh hiển thị cho toàn màn hình, giúp bạn thiết kế background cho Splash Screen đẹp đẽ hơn.

Tạo Theme Cho Splash Screen

Dĩ nhiên là bởi vì chúng ta không dùng cách thức tạo một layout thông thường cho Splash Screen, thì chúng ta phải sử dụng một cách khác, đó là dùng đến Theme.

Nếu bạn muốn biết rõ hơn khái niệm và cách sử dụng Theme thì bạn có thể xem thêm ở bài này.

Như vậy là với yêu cầu là tạo ra một Theme cho Splash Screen, chúng ta chỉnh sửa file res/values/styles.xml như sau.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="SplashscreenTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@drawable/bg_splashscreen</item>
    </style>

</resources>

Với chỉnh sửa trên thì mình tạo ra một Theme có tên là SplashscreenTheme, Theme này kế thừa từ một Theme gốc không có Action Bar, dĩ nhiên rồi vì Splash Screen sẽ cần tối đa không gian màn hình, và bởi cũng chỉ thoáng hiển thị thôi nên không cần các UI râu ria, như Action Bar chẳng hạn. Sau đó với thuộc tính android:windowBackground mình chỉ định đến file XML vừa tạo ra ở trên, giúp cho Theme này có thể dùng file XML đó để làm background cho nó.

Tạo SplashScreen Activity

Chúng ta vừa tạo giao diện và Theme cho Splash Screen rồi, tất nhiên là phải cần một Activity để dùng đến Theme đó chứ, và bước này chúng ta tạo ra một Activity mới đó.

Ở package bạn cần tạo Activity, trong ví dụ này mình chọn package đang chứa MainActivity.java, từ package đó bạn click chuột phải vào và chọn New > Activity > Empty Activity (hình dưới). Điều này giúp bạn tạo ra một Activity rỗng, tha hồ mà thêm vào các dòng code của riêng bạn mà không ngại có quá nhiều code mặc định trong đó.

Tạo Giao Diện Cho Splash Screen

Với dialog tiếp theo xuất hiện, bạn gõ tên Activity cần tạo vào ô Activity Name, mình gõ là SplashScreenActivity. À ngoài ra mình còn bỏ check Generate Layout File để mà nó đừng tự tạo ra file layout, như mình đã nói trên đây. Và mình cũng check vào Launcher Activity để khai báo nó là Activity launcher ở file Manifest. (Nếu bạn không check và bỏ check phức tạp ở bước này cũng không sao, chỉ cần bạn đặt tên cho Activity là được, sau đó bạn sửa code Java và sửa Manifest cho giống với các bước sau nữa là được)

Tạo Giao Diện Cho Splash Screen

Sau khi nhấn Finish thì bạn sẽ thấy source code của Activity vừa tạo hiện ra. Activity này sẽ không có hàm setContentView() là bởi bạn đã bỏ check Generate Layout File ở bước trên. Nhưng nếu bạn vẫn thấy hàm setContentView() ở file SplashScreenActivity.java này thì có thể xóa nó đi nhé.

Vậy chúng ta set giao diện cho Activity này như thế nào? Chúng ta sẽ dùng đến Theme vừa được tạo ra ở bước trên kia thay cho content layour. Mà để sử dụng Theme thì bạn nên khai báo ở Manifest ở bước sau. Bước này bạn chỉ cần chuyển đến MainActivity.java, tức là thoát khỏi Splash Screen sau khi nó được hiện ra, code như sau.

public class SplashScreenActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

Gắn Theme Cho SplashScreen Activity

Bước này bạn hãy mở file AndroidManifest.xml lên, nếu có nhiều hơn một Activity được định nghĩa là launcher thì bạn bỏ đi nhé, chỉ có SplashScreenActivity mới được là launcher thôi.

screen-shot-2017-02-20-at-11-36-48

Sau đó bạn nhớ định nghĩa Theme cho SplashScreenActivity là SplashscreenTheme nữa nhé. Tóm lại file AndroidManifest.xml sẽ trông như sau.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.yellowcode.splashscreendemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity" />

        <activity android:name=".SplashScreenActivity"
            android:theme="@style/SplashscreenTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Thực Thi Ứng Dụng

Đến đây thì bạn có thể run ứng dụng lên xem thành quả được rồi. Kết quả Splash Screen sẽ xuất hiện ra rất nhanh như sau.

myapp_splashscreen

Download Source Code Mẫu

Bạn có thể download source code mẫu của bài này ở đây.

Còn đây là link gốc mà mình đã tham khảo.

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

Xem thêm:

Tìm việc làm IT mọi cấp độ tại TopDev

Một số Patterns hay sử dụng trong React

Một số Patterns hay sử dụng trong React

Trong lập trình chúng ta thường sẽ gặp phải một số vấn đề chung lặp đi lặp lại trong các dự án khác nhau và sẽ có những kỹ thuật (lời giải) tương tự nhau để giải quyết bài toán đó. Khái niệm pattern chỉ những “mẫu” lời giải đó, nó thường được tổng hợp và khuyên dùng trong lập trình để xử lý và tránh các lỗi có thể gặp phải. Với React, chúng ta có một vài pattern được khuyên sử dụng và bài viết hôm nay chúng ta cùng tìm hiểu về chúng cùng các ví dụ cụ thể nhé.

Higher-Order Function/Component

Higher-Order functions là một hàm nhận một hàm khác dưới dạng đối số hoặc trả về một hàm dưới dạng đầu ra. Chúng ta có ví dụ dưới đây:

function greaterThan(n) {
  return (m) => m > n;
}

const greaterThan10 = greaterThan(10);

console.log(greaterThan10(11));
// true

Ở ví dụ trên, hàm greaterThan trả về 1 function so sánh giá trị truyền vào với đối số xác định trước, cụ thể với hàm greaterThan10 thì đối số là 10. Từ đó chúng ta có thể tạo ra các function khác nhau bằng cách call function greaterThan và đối số truyền vào. Đấy chính là lợi ích của higher-order function.

  Hệ thống 23 mẫu Design Patterns

  Bridge Pattern trong Java – Code ví dụ Composite Pattern

Từ khái niệm trên, trong React chúng ta cũng có khái niệm Higher-Order component (HOC), đó là 1 component mà:

  • Nhận đầu vào 1 component và trả về 1 component mới
  • Biến đổi 1 component thành 1 component khác

 Chúng ta có ví dụ dưới đây:

const withColor = Element => props => <Element {...props} color="red" />

const Button = () => {
  return <button>My Button</button>
}

const ColoredButton = withColor(Button)

Ở đây chúng ta sử dụng HOC withColor để tạo ra component ColoredButton từ component Button với mục đích là set mặc định giá trị màu đỏ cho button đó. 

Thực tế có rất nhiều thư viện sử dụng kỹ thuật này trong React, điển hình như Redux. Để có thể tạo ra những state dùng chung(store) và các action tác động lên toàn bộ component thì Redux tạo ra Provider để bọc toàn bộ các components trong ứng dụng, và đấy cũng chính là 1 HOC.

Tham khảo việc làm React mới nhất trên TopDev

State Hoisting

Bạn nào làm React chắc cũng đều nắm được về stateless và statefull component, hiểu đơn giản thì stateless sẽ không giữ biến state nào cả. Trong 1 project, việc tạo ra các stateless component được khuyến khích vì lúc đó bạn có thể yên tâm tái sử dụng hay xóa chúng đi mà không lo việc ảnh hưởng đến logic của toàn hệ thống. Chúng ta cùng xem xét bài toán dưới đây: 

<div>
  <CarHeader />
  <CarList />
</div>;

const CarHeader = () => {
  const [cars, setCars] = useState([]);

  useEffect(() => {
    const cars = getData(); //this fuctional function calls an API
    setCars(cars);
  }, []);

  return <div> No of Cars: {cars.length}</div>;
};

const CarList = () => {
  const [cars, setCars] = useState([]);

  useEffect(() => {
    const cars = getData(); //this fuctional function calls an API
    setCars(cars);
  }, []);

  return (
    <>
      {cars.map((car) => (
        <div>Car:{car.name}</div>
      ))}
    </>
  );
};

2 components CarHeader và CarList đều sử dụng cùng dữ liệu là danh sách car lấy từ API trả về, cách tốt hơn ở đây là sẽ khai báo state cars ở trong component cha, loại bỏ biến state trong 2 component con để biến chúng thành các stateless component.

useEffect(() => {
  const cars = getData(); //this fuctional function calls an API
  setCars(cars);
}, []);

return (
  <div>
    <CarHeader cars />
    <CarList cars />
  </div>
);

Kỹ thuật này gọi là state hoisting, ngoài việc tạo ra các staless component con, thì lúc này dữ liệu cũng được lấy từ 1 nguồn duy nhất (single source of truth) giúp các component đồng bộ với nhau, việc debug ứng dụng cũng trở nên dễ dàng hơn.

Ngoài việc đẩy data ra component cha để xử lý, thì chúng ta cũng sử dụng kỹ thuật này vơi các events trong các phần tử con có tương tác với người dùng, ví dụ như các thẻ Input.

const Name = ({ onChange }) => (
  <input onChange={(e) => onChange(e.target.value)} />
);

const NameContainer = () => {
  const [name, setName] = useState("");

  return (
    <>
      <div>Your name: ${name}</div>
      <Name onChange={(newName) => setName(newName)} />
    </>
  );
};

Trong ví dụ trên, thẻ input tạo ra trong component Name và chúng ta muốn lấy được dữ liệu ra trong component cha của nó, không tác động thêm state vào Name, cách giải quyết là đẩy event onChange ra ngoài để component cha (NameContainer) sử dụng, vẫn đảm bảo được tính “stateless” của Name.

Proxy Component

Proxy pattern là 1 thiết kế mẫu giúp bạn kiểm soát truy cập đến đối tượng ban đầu, giúp bạn hạn chế việc sai sót trong quá trình tái sử dụng component ban đầu cũng như tạo ra 1 component mới.

Ví dụ chúng ta có 1 component button được sử dụng trong App như sau:

<button type="button">
</button>

// button type
// 1. button
// 2. reset
// 3. submit

Nếu trong App của chúng ta sử dụng thẻ button này trực tiếp thì sẽ luôn phải khai báo type cho nó, bài toán đặt ra là nếu chúng ta không cho phép sử dụng type=submit trong ứng dụng của mình thì sẽ thế nào? Cách giải quyết là tạo ra 1 component mới với thuộc tính type=button để đảm bảo mỗi button được tạo ra luôn có chung thuộc tính type. Kỹ thuật này gọi là Proxy, nó giúp chúng ta đảm bảo tính nhất quán trong thuộc tính (attribute) của component, đồng thời hạn chế việc truy cập đến các thuộc tính khác trong component gốc.

const Button = (props) => {
  return <button type="button" {...props}></button>;
};

return (
  <>
    <Button />
    <Button className="CTA">Send Money</Button>
  </>
);

Chúng ta cũng có thể sử dụng kỹ thuật này cho các thuộc tính của style để tạo ra các Style component. 

import classnames from "classnames";

const PrimaryBtn = (props) => <Btn {...props} primary />;

const Btn = ({ className, primary, ...props }) => (
  <button
    type="button"
    className={classnames("btn", primary && "btn-primary", className)}
    {...props}
  />
);

<button type="button" className="btn btn-primary"></button>;

3 cách khai báo code trên sẽ cùng cho ra 1 kết quả giống nhau, trong trường hợp này PrimaryBtn component được sử dụng như 1 Proxy cho component button với cách khai báo gọn và thống nhất hơn.

Kết bài

Trên đây là 3 patterns sử dụng trong lập trình React mà bạn sẽ thường xuyên gặp và áp dụng. Áp dụng đúng và hợp lý các patterns sẽ giúp code của bạn clear và tránh các lỗi có thể xảy ra; nó cũng sẽ giúp bạn nâng cao kỹ năng lập trình của mình. Hy vọng bài viết hữu ích dành cho bạn, hẹn gặp lại các bạn trong các bài viết tiếp theo của mình.

Tác giả: Phạm Anh Khoa

Xem thêm:

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

Nhập/Xuất Trên Console

Nhập/Xuất Trên Console

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

Bài viết hôm nay sẽ hướng dẫn bạn sử dụng một “công cụ” để các bạn tiến hành nhập/xuất thông qua Console. Công cụ này giúp cho các bạn sau khi nhập dữ liệu vào từ bàn phím, nó sẽ lấy dữ liệu được nhập này rồi sau đó chuyển vào chương trình của bạn, để chương trình xử lý, rồi xuất ra kết quả thông qua màn hình Console.

Sau bài học hôm nay thì các bạn có thể test thoải mái các dòng code, để hỗ trợ tốt vào quá trình học Java của bạn. Nhưng trước hết, chúng ta hãy cùng tìm hiểu sâu hơn về khái niệm nãy nhờ được nhắc đi nhắc lại này.

Khái Niệm Console

Đầu tiên bạn có thể hiểu Console chúng như là một bảng điều khiển chuyên dụng. Như các Game Console chính là các thiết bị chuyên cho việc điều khiển game. Hay các trang web quản lý như quản lý nhân viên cũng có thể coi là các Console chuyên dụng cho việc quản lý.

Trong ngôn ngữ lập trình, Console được biết đến như là một cách điều khiển ứng dụng đơn thuần nhất thông qua các dòng text (dòng lệnh), nó được phân biệt với điều khiển bằng UI.

Và Console trong chương trình học của chúng ta là hình minh họa dưới đây, ở các bài làm quen sơ sơ trước, khi bạn thực thi chương trình thì cũng đã biết tới cửa sổ Console này rồi đúng không nào.

Màn hình Console trong InteliJMàn hình Console trong InteliJ

Nhập Trên Consolse

Chúng ta đang nói đến các cách thức để bạn nhập dữ liệu từ Console. Để bắt đầu, bạn hãy mở InteliJ lên. Bạn hãy mở lại project HelloWord mà chúng ta đã tạo ra từ bài hôm trước.

Đầu tiên mình muốn bạn thử khai báo một đối tượng Scanner như code bên dưới. Bạn code đi rồi mình sẽ nói rõ hơn lý do tại sao phải code như vậy ở bên dưới dòng code này.

Scanner scanner = new Scanner(System.in);

Các khái niệm lớp (class) hay đối tượng gì gì đó thì bạn sẽ được làm quen sau này, nó thuộc về kiến thức OOP như mình có nói đến ở đầu bài học. Nhưng bạn có thể hiểu trước là đối tượng cũng giống như biến vậy, bạn có thể khai báo nó với cái tên tùy ý (theo quy tắc đặt tên của biến). Như ở trên chúng ta khai báo một đối tượng của Scanner mang tên là scanner. Chỉ khác biến ở chỗ là đối tượng của lớp phải được khởi tạo bằng từ khóa new như trên. Khi đó tổng thể code của bạn như sau.

public class MyFirstClass {

    public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
 }

}

  Console Javascript quá kinh khủng

  Cài Đặt Các Công Cụ Phát Triển Cho Java

Lan Man Về Cách Thức Bạn Code

Mục này cho phép mình nói lan man về kinh nghiệm code một tí xíu. Đó là nhiều bạn sau khi gõ xong dòng code trên đây, có thể sẽ có báo lỗi từ InteliJ như hình sau.

Khi bạn code có thể gặp tình huống báo lỗi như nàyKhi bạn code có thể gặp tình huống báo lỗi như này

Sở dĩ có báo lỗi là vì hệ thống đang không biết lớp Scanner là gì :)). Đó là bởi vì trước đây bạn chỉ sử dụng các biến nguyên thủy, hoặc các lớp nằm trong package java.lang. Với việc sử dụng này thì chúng ta không cần phải quan tâm, sẽ chẳng có lỗi nào như bạn đã từng thực hành với các bài học trước. Chà vậy chúng ta cần quan tâm gì? Thực ra trong Java, mỗi khi bạn code, bạn phải chỉ định nguồn gốc của các lớp bạn sẽ dùng, thông qua từ khóa import. Các dòng import được khai báo ở đầu mỗi file. Mỗi dòng import như vậy bao gồm từ khóa import, theo sau nó là package có chứa lớp cần dùng (bạn có thể xem thêm kiến thức về package ở đây).

Theo đó, ở ví dụ trên chúng ta cần đến lớp Scanner. Thì chúng ta cần import đúng package mà hệ thống muốn.

Để import đúng package có lớp Scanner cần dùng trên đây thực ra là một điều cực kỳ dễ dàng, có nhiều cách để thực hiện điều này, bạn hãy chọn một trong những cách sau.

Tham khảo việc làm Java hấp dẫn cho Fresher

Sử Dụng Gợi Ý Hoàn Thành Code Từ IDE

Có thể nói đây là cách thức dễ nhất để InteliJ tự động hoàn thành việc import một package cho bạn.

Việc của bạn là hãy gõ vài từ vào IDE, bạn sẽ thấy các gợi ý hoàn thành dòng code như hình bên dưới. Bạn hãy nhấn Enter nếu gợi ý đầu tiên bạn thấy là đúng, hoặc bạn có thể đưa vệt sáng đến dòng gợi ý nào khác rồi nhấn Enter. Ngoài việc kết quả dòng code được tự động hoàn thành thì hệ thống cũng import sẵn package java.util.Scanner cho bạn mà bạn không cần phải nhớ chúng là ai và từ đâu đến đúng không nào.

InteliJ tự gợi ý hoàn thành dòng code, và nếu bạn chấp nhận, nó cũng tự import package cho bạnInteliJ tự gợi ý hoàn thành dòng code, và nếu bạn chấp nhận, nó cũng tự import package cho bạn

Bạn thử gõ hết câu lệnh trên với việc chọn những gợi ý ở các thành phần tiếp theo (scannernewScannerSystem) xem sao nhé. Kết quả sẽ không còn lỗi nữa.

Kêu IDE Import Giúp

Có đôi khi IDE không đưa ra bất kì gợi ý nào để hoàn thành dòng code như trên kia. Khi này bạn hãy cứ gõ hết tất cả dòng code cần thiết của bạn, đừng lo lắng nếu có báo lỗi. Sau khi gõ xong hết, thì bạn cứ để ý trên editor của IDE, chắc chắn sẽ xuất hiện các hướng dẫn tận tình giúp chúng ta sửa lỗi.

Như trường hợp dưới đây, sau khi gõ xong, bạn sẽ thấy các nơi báo đỏ, khi đưa con trỏ chuột vào những nơi bị tô đỏ đó, nếu là lỗi thiếu import, bạn sẽ nhìn thấy một popup hiện ra như thế này, chỉ cần nhấn chọn vào chữ Import Class là xong.

Sử dụng gợi ý import từ InteliJSử dụng gợi ý import từ InteliJ

Import Thủ Công

Tất nhiên cách này dành cho bạn nào biết chính xác lớp này nằm trong package nào rồi nên bạn có thể gõ import một cách thủ công.


Lan man hơi dài rồi, quay trở lại với việc bạn vừa khai báo đối tượng của lớp Scanner trên kia. Dòng tiếp theo bạn chỉ cần gọi

scanner.nextXxx();

 thì khi bạn chạy chương trình, khi hệ thống thực thi đến dòng này, nó sẽ dừng lại chờ, và lúc đó Console sẽ xuất hiện con nháy chờ người dùng nhập vào một giá trị có kiểu dữ liệu là Xxx rồi mới tiến hành gán giá trị này vào biến tương ứng và thực hiện tiếp các câu lệnh bên dưới.

Bạn hãy thử vài ví dụ sau cho từng

scanner.nextXxx();

 cụ thể nhé.

Ví Dụ Nhập Dữ Liệu Kiểu Chuỗi

Với ví dụ này bạn thử cho người dùng nhập vào tên từ Console rồi in ra dòng xin chào ngay trên Console luôn như sau.

Để đợi người dùng nhập vào tên bạn gõ dòng sau vào sau khi khai báo scanner.

String name = scanner.nextLine();

Khi đó tên người dùng nhập vào từ Console sẽ được gán vào biến kiểu String (đây là kiểu chuỗi mà bạn sẽ được làm quen sau) có tên là name. Nhưng để dễ dàng hơn cho người dùng, chúng ta nên có các dòng System.out để in ra chỉ dẫn cho người dùng trước dòng đợi nhập tên. Code tổng thể của chúng ta như sau.

import java.util.Scanner;;

public class MyFirstClass {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Please enter your name here: ");
        String name = scanner.nextLine();
        System.out.println("Hello! " + name);
    }

}

Khi này nếu bạn chạy chương trình, chỉ có dòng text “Please enter your name here: “ xuất hiện, đừng tắt cửa sổ Console nhé, hãy tiếp tục nhập vào một text, sau khi Enter bạn sẽ nhận được một text nữa in ra với nội dung “Hello!” và text bạn vừa nhập, text in ra đó chính là nội dung biến name được scanner lấy dữ liệu từ Console rồi gán vào đấy.

Kết quả thực thi chương trình khi nhập vào một StringKết quả thực thi chương trình khi nhập vào một String

Ví Dụ Nhập Dữ Liệu Kiểu int

Tương tự nếu ví dụ này hỏi người dùng nhập tuổi, bạn cũng nên có câu in ra gợi ý, dòng scanner.nextInt(), và dòng in ra kết quả sau đó. Code tổng thể như sau.

Scanner scanner = new Scanner(System.in);
System.out.println("How old are you? ");
int age = scanner.nextInt();
System.out.println("Your age is: " + age);

Ví Dụ Nhập Dữ Liệu Kiểu Float

Scanner hỗ trợ nhập cho hầu như tất cả các kiểu dữ liệu nguyên thủy (trừ kiểu char, vì thực ra kiểu char cũng có thể lấy ra từ việc nhập một String với một ký tự, bạn hãy xem phần bình luận bên dưới để biết cách nhập vào kiểu char nếu có nhu cầu nhé). Ví dụ sau nhập vào kiểu float và bạn hoàn toàn có thể áp dụng cho các kiểu dữ liệu nguyên thủy được hỗ trợ còn lại.

Scanner scanner = new Scanner(System.in);
System.out.println("How about your salary? ");
float salary = scanner.nextFloat();
System.out.println("Your salary is: " + salary);

Xuất Trên Console

Chắc bạn cũng biết, để xuất dữ liệu ra Console thì cứ gọi

System.out.println();

 thôi chứ gì. Dễ quá, các bài trước và bài hôm nay bạn đã làm quen rồi. Nhưng kiến thức về xuất dữ liệu ra Console còn vài thứ vui vẻ nữa, mời các bạn cùng xem tiếp.

Xuất Mặc Định

Mình dùng từ xuất mặc định là bởi vì chúng ta không can thiệp gì đến cách mà Console hiển thị một nội dung cả. Đó chính xác là cách gọi

System.out.println();

 như chúng ta đã làm quen. Mình thêm một vài lưu ý sau thôi.

  • Bạn có thể dùng câu lệnh print() thay vì println(). Nếu như với println() thì các bạn đã biết nó giúp xuất dữ liệu ra rồi kèm theo xuống hàng sau khi xuất. Thì print() chỉ xuất dữ liệu thôi và không xuống hàng. Bạn có thể thử áp dụng print() cho các thông báo chỉ dẫn như “Please enter your name here: “ trên kia để xem sự khác biệt nhé.
  • Nếu bạn muốn hiển thị các ký tự đặc biệt sau: dấu nháy đơn (‘), dấu nháy kép (“), và dấu gạch chéo (\). Thì bạn cứ kèm theo một gạch chéo (\) nữa ở trước các ký tự này. Chẳng hạn bạn muốn hiển thị dòng Thư mục chứa file “ấy” là C:\Location\Ay, thì bạn gõ lệnh xất như sau System.out.print(“Thư mục chứa file \”ấy\” là C:\\Location\\Ay”);.
  • Ngoài ra bạn còn có thể chèn thêm các ký tự giúp định dạng dữ liệu xuất, như “\t” sẽ chèn thêm một tab, hay “\n” sẽ giúp xuống dòng. Bạn thử tự kiểm chứng bằng cách gõ xòng lệnh này nhé System.out.print(“\tHello\nWorld”);.

Tuy nhiên, với kiểu xuất mặc định này, có đôi lúc chúng ta tưởng như việc xuất nội dung là bình thường, nhưng nó lạ lắm. Bạn hãy xem kết quả in ra Console bên dưới đây, rồi chúng ta sẽ xem xuất “không mặc định” nó sẽ như thế nào sau nhé.

double x = 10000.0/3.0;
System.out.println("The result is " + x);

Kết quả sẽ in ra nội dung

The result is 3333.3333333333335

. Thì cũng đúng thôi, kết quả phép chia cho ra dãy số vậy là đúng rồi. Thế nhưng nếu chúng ta muốn kiểm soát việc in ra Console sao cho dữ liệu xuất được đẹp hơn thì sao. Chẳng hạn bạn muốn in ra giá trị cho tiền tệ, khi mà sau dấu thập phân bạn muốn làm tròn đến 2 con số thôi. Khi đó bạn hãy đến với kiến thức về xuất theo định dạng như sau.

Xuất Theo Định Dạng

Nếu như với xuất mặc định, bạn đã biết là nên dùng một trong hai phương thức là print() hay println(). Thì xuất theo định dạng cung cấp cho bạn một phương thức hiệu quả hơn đó là printf() (chữ f cuối cùng của phương thức viết tắt của từ format, chính là định dạng).

Khi đó để kết quả của ví dụ trên in ra một con số làm tròn “đẹp đẽ” sao cho chỉ có 2 chữ số sau dấu thập phân thôi, bạn có thể viết lại như sau.

double x = 10000.0/3.0;
System.out.printf("The result is %.2f", x);

Kết quả in ra là:

The result is 3333.33

. Đẹp hơn đúng không nào, mình giải thích sơ qua cho các bạn hiểu cách làm việc của printf() ở bên dưới (nếu bạn nào muốn tìm hiểu kỹ hơn tất cả cách sử dụng của printf() thì có thể đọc bài viết này của mình).

printf() ở mức cơ bản cần bạn phải truyền vào 2 thành phần, cách nhau bởi dấu (,).

  • Thành phần thứ nhất nói cho phương thức này biết nội dung xuất ra màn hình, trong nội dung đó có chỉ định một hoặc nhiều dấu hiệu định dạng. Trong ví dụ trên thì dấu hiệu này là %10.2fDấu hiệu định dạng này mang ý nghĩa rằng bạn muốn in một số thực bất kỳ, nhưng nó phải được hiển thị bởi ký tự sau dấu thập phân.
  • Thành phần thứ hai của phương thức chính là giá trị cần định dạng. Hệ thống sẽ tự động tìm kiếm nơi mà bạn đã khai báo dấu hiệu định dạng trong chuỗi xuất ở thành phần thứ nhất, cụ thể là %10.2f như bạn thấy, và thay thế vào đó giá trị cần định dạng, cụ thể là biến x của chúng ta.

Kết Luận

Chúng ta vừa thực hành các câu lệnh nhập/xuất đáng giá từ console. Bạn đã đủ tự tin để nhập bất kỳ dữ liệu bạn muốn vào chương trình, và xuất dữ liệu một cách đẹp đẽ ra console rồi. Hãy đến các bài viết tiếp theo của mình để cùng nhau từng bước xây dựng các ứng dụng hoàn chỉnh nhé.

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

Xem thêm:

Đừng bỏ qua việc làm IT tất cả level có trên TopDev nhé!

Chức danh Senior, Developer là gì? Khác gì với coder nhỉ!

Chức danh Senior, Developer là gì? Khác gì với coder nhỉ!

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

Coder thường nói:
“Cứ code cho nó chạy được là mừng rồi”, “Code xong fix bug thấy bà”, bla bla bla…

Những anh Lead già làm chung chia sẻ và bản thân mình từng là developer và lead cũng thấy rằng Senior không phải là chức danh cho người làm lâu năm, thực tế khi làm chung với một số anh coder lâu năm thì thấy code vẫn ẩu, không rõ ràng và chất lượng chưa tốt qua việc bug phát sinh thường xuyên phải có tester và QC lại thì mới đảm bảo được!

Senior phụ thuộc vào công việc của công ty, công ty product hay outsourcing đối với mỗi công ty sẽ yêu cầu những skill khác nhau. Senior về product sẽ yêu cầu bạn chinh chiến khắp chốn skill áp dụng giải quyết vấn đề chiều rộng hơn sâu. Senior về outsourcing sẽ cần bạn ngồi lâu trong skill nào đó trở thành lão làng về nó giải quyết vấn đề theo chiều sâu chuyên môn về skill đó.

Thực tế, Senior là người developer biết giải quyết vấn đề một cách hiệu quả & triệt để, ít ảnh hưởng tới những yếu tố khác nhất. Ví dụ đơn giản, khi được khách hàng yêu cầu dựng một tính năng mới trong ứng dụng, đối với một Senior trước khi làm sẽ phải suy nghĩ thật kỹ về solution, architecture, extension, về mức độ ảnh hưởng tới những module đang chạy, tùy vào yêu cầu mà biết cần optimize cái gì, bởi vì nhiều khi đó là bài toán đánh đổi để cho hài hòa giữa nhiều yếu tố liên quan chặt chẽ tới nhau, như giữa tính bảo mật và hiệu năng, giao diện đẹp và trải nghiệm tốt,… Code viết phải gọn gàng, dễ bảo trì và mở rộng, để người khác không phải “gánh hậu quả” thay mình.

  Top 5 kinh nghiệm fix bug từ Senior Developer

Còn Coder, họ là ai? Họ rất yêu công nghệ, họ đang trăng mật với công nghệ mới, nhưng họ thiếu sự nhạy bén, tinh tế và khả năng suy xét thấu đáo, nên cứ code cho chạy thôi… nào thấy bug thì fix thôi.
Có lẽ trong chúng ta ai cũng từng nhiều lần tự chất vấn bản thân rằng chúng ta đang ở đâu trong cuộc đời? chúng ta đang làm gì, và làm vì điều gì khi thời giang trôi qua? Các developer sau khi đã trải qua nhiều năm say đắm với nghề, khi mà đã trôi qua rồi cái thời trăng mật với công nghệ, say mê tìm tòi viết ra những dòng code cực chất, hay nghiền ngẫm vọc những tool, framework, công nghệ mới hàng đêm, thì họ sẽ có lúc ngồi bình tĩnh lại tự hỏi có vẻ mình đã thay đổi?

Tham khảo một vài việc làm Java hấp dẫn dành cho các Coder!

Trong những buổi chiều “hội họp”, mình vẫn hay nghe những anh senior than thở rằng những công việc hằng ngày không còn hứng thú nữa vì họ cảm giác rằng chẳng còn gì họ làm mà mới mẻ khiến họ phải say mê, có nhiều sức ỳ nào đó đã trở nên quá lớn để họ tìm tòi tiếp.

Công nghệ mình cày cuốc bao nhiêu năm qua thực sự không phù hợp với mình, cảm thấy nhàm chán nhưng không có thời gian (thường thì đây là lời bao biện cho sức ỳ quá lớn, thứ sẽ xuất hiện khi bạn chẳng màng tới điều gì nữa) hoặc không còn hứng thú để học công nghệ khác vì chẳng tìm thấy sự phấn khích khi tiếp xúc với công nghệ mới như ngày xưa “Cái này cũng mới, hay đó nhưng cũng đang có cả một núi task đang chờ cho xong print này đã…”

Khi mình đã giỏi hơn, đã thu được một “kho tàng” kinh nghiệm thực chiến rồi thì đòi hỏi về mức lương tương xứng là điều dễ hiểu phải không? Nhận ra mình không được đền bù công sức và được tưởng thưởng xứng đáng với cấp bậc, kinh nghiệm và đóng góp trong công việc thì thật gây chán nản vô cùng. Đặc biệt ở những công ty nước ngoài, nơi khả năng ngoại ngữ cũng quyết định lớn tới sự thăng tiến và mức lương của bạn thì biết là mình thiếu ngoại ngữ đấy nhưng mà lại chẳng thể học vào được nữa và một phần có thể là quá lười với bao thứ giải trí xung quanh sau một ngày code mờ mắt. Cảm thấy ngành này với mình không có tương lai nên tìm MMO làm kiếm thêm cho bớt đau khổ, cho nhẹ gánh.

  Senior là gì? Phân biệt Senior và Junior thật chi tiết

Điều này nữa khá đúng với nhiều Senior đã có gia đình nhỏ và phải chăm lo cho nó. Sẽ có hai cách suy nghĩ: một bạn làm tất cả, tìm mọi phương cách để có thể lo lắng tốt cho gia đình mình. Hai là bạn nhận ra rằng công việc hiện tại quá tệ không đủ lo cho gia đình như bạn mong đợi nhưng mà không dám thay đổi, vì thay đổi thì lỡ có gì lại không thể lo cho gia đình, cho con cái của bạn.

Thật khó nghĩ, nhưng có lẽ bạn phải hiểu cuộc sống cũng như viết chương trình, sẽ có những bài toán đánh đổi và lâu lâu phải liều làm cái không rõ chút…

Bài viết gốc được đăng tải tại lcdung.top
Xem thêm Việc làm Developer hấp dẫn trên TopDev