Bài viết được sự cho phép của tác giả Trần Hữu Cương
Thay vì tạo thread bằng việc Extend Thread hoặc implement Runable và tự quản lý số lượng thread. Thì ta có một hướng tiếp cận khác đó là sử dụng Callable và Future. (Cho phép hủy các thread, kiểm tra thread đã hoàn thành chưa, quản lý số thread chạy cùng lúc …).
Callable, Future, Executors là gì?
Callablelà một interface trong java, nó định nghĩa một công việc và trả về một kết quả trong tương lai và có thể throw Exception.
Future là kết quả trả về của Callable, nó thể hiện kết quả của một phép tính không đồng bộ, cho phép kiểm tra trạng thái của phép tính (đã thực hiện xong chưa, kết quả trả về là gì…).
Executors là một class tiện ích trong Java, dùng để tạo thread pool, đối tượng Callable cho các xử lý bất đồng bộ.
Mỗi đối tượng Calculator có thể hiểu là một thread, khi nó được submit vào ExecutorService thì nó sẽ được thực thi.
Executors.newFixedThreadPool(10); tức là tạo ra một thread pool chứa tối đa 10 thread chạy cùng lúc.
executor.shutdown();: Thực hiện tắt executor khi không còn task (đối tượng Callable) nào ở bên trong (các task đã hoàn thành). Nếu bạn không có lệnh này thì chương trình của bạn sẽ chạy mãi vì nó luôn có một thread kiểm tra task trong executor để thực thi.
Khi bạn gọi f1.get() thì nó sẽ block thread chính lại để khi nào đối tượng c1 thực hiện xong và trả về kết quả.
Trường hợp đối tượng c1 mất quá nhiều thời gian để tính tổng 2 số thì cả chương trình sẽ bị delay rất lâu. Giải pháp cho trường hợp này là sử dụng method get() với thời gian timeout:
Ví dụ nếu sau 1 giây mà chưa có kết quả thì không chờ nữa: f1.get(1, TimeUnit.SECONDS)
Một số hạn chế của Future
Future không thông báo khi nó hoàn thành: (không biết được khi nào hoàn thành): ví dụ mình muốn sau khi f1 hoàn thành thì làm gì đó nhưng Future không hỗ trợ bắt được sự kiện hoặc xử lý callback khi f1 hoàn thành
Không thể thực hiện xử lý chờ hoặc xử lý theo thứ tự các future: ví dụ mình muốn f1 và f2 hoàn thành xong thì mới thực hiện f3 hoặc thực hiện theo thứ tự f1, f2, f3 nhưng Future không có cách nào xử lý được việc này.
Nếu muốn xử lý các vấn đề trên ta lại phải dùng while hoặc tạo 1 thread riêng và sử dụng method f1.isDone() để check khi nào future hoàn thành…
Từ Java 8 ta có thêm CompleteFuture để khắc phục những hạn chế bên trên. (Mình sẽ làm ví dụ CompleteFuture trong bài sau).
Drupal là một hệ quản trị nội dung (CMS) mã nguồn mở viết bằng PHP; trong hầu hết các bảng xếp hạng về top những CMS platform (nền tảng phát triển) phổ biến thì Drupal thường xuyên có mặt trong top 5. Điều đó cho thấy sự phổ biến và nhu cầu sử dụng rất lớn của CMS PHP này. Ở Việt Nam, nhu cầu tuyển dụng PHP luôn luôn đứng top đầu, và sẽ có nhiều nhà tuyển dụng ưu tiên cho những lập trình viên biết, thành thạo các thư viện, framework như Drupal. Bài viết hôm nay mình sẽ cùng các bạn đi tìm hiểu về CMS platform này và các kiến thức cần có để trở thành 1 Drupal Developer nhé.
Drupal là gì?
Như đã nói ở trên, Drupal là một hệ quản trị nội dung mã nguồn mở giúp phát triển website từ các blog cá nhân cho tới các trang web của chính phủ, doanh nghiệp, hay các trang thương mại điện tử.
Hiểu đơn giản thì với Drupal, bạn có thể tạo ra website bạn cần và có sẵn những ứng dụng giúp thay đổi, chỉnh sửa nội dung website của bạn. Drupal được viết bởi Dries Buytaert – một lập trình viên người Bỉ, và được giới thiệu lần đầu tiên vào năm 2000; hiện tại nó vẫn được tác giả update phiên bản 1 cách đều đặn, mới nhất thì phiên bản Drupal 10 đang được lên kế hoạch ra mắt vào tháng 12 này.
Drupal được viết bằng PHP và hoàn toàn miễn phí, vì thế nó được nhiều lập trình viên ưa chuộng. Tính đến tháng 3 năm 2021, cộng đồng Drupal bao gồm hơn 1,39 triệu thành viên, đóng góp hơn 46 nghìn module miễn phí để mở rộng, gần 3 nghìn theme miễn phí để thay đổi giao diện. Drupal có thể chạy trên bất kỳ nền tảng máy tính nào có máy chủ hỗ trợ PHP và cơ sở dữ liệu để lưu trữ nội dung, cấu hình.
Đa ngôn ngữ: Drupal hỗ trợ 100 ngôn ngữ cho phép bạn cài đặt, tạo và sử dụng website ở mọi nơi trên thế giới.
Hỗ trợ quản lý nhiều site: Drupal có công cụ giúp bạn quản lý nhiều site trong chiến dịch, thương hiệu hay tổ chức, vùng địa lý mà bạn quản lý. Điều đó giúp bạn không phải đăng nhập qua lại nhiều tài khoản khác nhau, tối ưu hóa việc quản lý nội dung
Khả năng tương thích cao: Drupal không chỉ hỗ trợ thiết kế trên trình duyệt web mà khả năng tương thích với các định dạng thiết bị khác, đặc biệt là trên di động rất tốt.
Tính tin cậy cao: Hệ thống Drupal có độ bảo mật cao, nhiều tính năng cảnh báo lỗ hổng bảo mật và tự vá lỗi. Ngoài ra nó cũng đã được kiểm chứng bởi rất nhiều nhà phát triển web trên khắp thế giới
Tính tùy biến cao: người dùng hoàn toàn có thể tự định nghĩa ra các cấu trúc dữ liệu của riêng mình trên hệ thống Drupal, điều này giúp giải quyết nhiều bài toán theo nghiệp vụ cụ thể.
Khi nhắc đến lập trình viên Drupal thì thường sẽ có 3 lĩnh vực chuyên môn chính:
Drupal Site Builder: là những người xây dựng những trang web Drupal bằng cách cài đặt, thiết lập trên giao diện Admin (trang quản lý) mà có thể không cần viết thêm code tùy chỉnh nào.
Drupal Themer: đây là những Frontend Developer giúp thiết kế và tạo ra các theme dành cho Drupal.
Drupal Module Developer: là những người viết code PHP để tạo ra các module dành cho Drupal, có thể tích hợp vào chạy như những tiện ích bổ sung trên nền web chính. Thông thường thì Backend Developer có những kỹ năng phù hợp để đảm nhiệm công việc này.
Như vậy lập trình viên Drupal không chỉ là những người trực tiếp viết code PHP nhằm tùy biến hay thêm mới các chức năng cho hệ sinh thái Drupal, mà đôi khi việc thành thạo làm việc với trang quản trị CMS Drupal cũng giúp chúng ta trở thành 1 Drupal Developer.
Để trở thành lập trình viên Drupal, đầu tiên bạn hãy xác định chuyên môn, vị trí của mình trong hệ thống CMS Drupal.
Nếu muốn trở thành những người xây dựng, quản trị trang web Drupal, hãy cố gắng tìm hiểu tất cả những gì mà CMS Drupal cung cấp cho bạn từ việc cài đặt, cấu hình đến việc vận hành, bảo trì. Kĩ năng và kiến thức liên quan đến server, hosting, database là cần thiết cho vị trí này.
Hãy hình dung những công việc cơ bản sau đây bạn sẽ đảm nhiệm
Cài đặt Drupal lên hosting của bạn
Chuẩn bị cấu hình Database để kết nối với Web của bạn
Tìm hiểu sử dụng các module trong phần quản trị (Admin) của Drupal CMS
Content: quản trị nội dung và tài nguyên
Structure: cấu hình layout, module hiển thị
Appearance: cài đặt themes
Configuration: cấu hình website
People: quản trị người dùng
Reports: các báo cáo, nhật ký liên quan
Helps: các hướng dẫn sử dụng
Nếu bạn yêu thích việc tạo ra các themes dành cho website Drupal của mình, yếu tố đầu tiên là bạn cần có kiến thức liên quan của 1 Frontend Developer; đó là HTML, CSS, JS. Để tạo ra và sử dụng theme trên hệ sinh thái của mình, Drupal quy định 1 số file cơ bản giúp bạn thiết lập theme:
template.php: khai báo các hàm dùng trong theme
theme-settings.php: khai báo tùy chỉnh , config của theme
html.tpl.php: hiển thị những thông tin cơ bản của website
node.tpl.php: hiển thị thông tin của các node trong drupal
themes_name.info: khai báo các file css, js tùy chỉnh
page.tpl.php: cấu trúc giao diện chính trong Drupal
Nếu bạn tự tin và yêu thích công việc viết code bằng PHP, hãy tạo ra các module Drupal với những kiến thức về ngôn ngữ lập trình PHP cùng hiểu biết về cấu trúc, source code Drupal của bạn. Trước tiên hãy đọc và tìm hiểu về cấu trúc cũng như các thành phần sẵn có trong Drupal được mô tả chi tiết trên trang chủ của nó, các bạn có thể tham khảo ở link dưới đây:
Hãy nắm vững các khái niệm sau trong Drupal để có thể viết được 1 module hoàn chỉnh:
Node: các kiểu nội dung trong Drupal như blog, post, page, recipe, …
Block: các khối trên trang
Hook: xử lý các event tương tác với nhân Drupal
Views: phẩn hiển thị, chế độ xem dành cho các users
Công việc tiếp theo của bạn là kết hợp các thành phần lại với nhau để tạo ra các module tùy theo mục đích bạn tạo ra.
Kết bài
Drupal Developer không chỉ là những người viết code, đấy là những người tham gia vào hệ sinh thái của Drupal và cùng tạo ra những website theo yêu cầu, và xây dựng nên hệ sinh thái phong phú cho nền tảng CMS Drupal. Hy vọng qua bài viết này các bạn đã nắm được phần nào những điểm mấu chốt về nền tảng CMS này cũng như có cái nhìn rõ hơn về cách để trở thành 1 lập trình viên Drupal. Cảm ơn các bạn đã đọc, hẹn gặp lại các bạn trong các bài viết sau của mình.
Bài viết được sự cho phép của tác giả Võ Quang Huy
Đây là những đoạn code bạn sẽ dùng thường xuyên trong quá trìnhlập trình theme wordpress. Bạn chỉ cần hiểu tác dụng của nó như thế nào sau đó copy và dán nó để chạy thôi. Mình đã viết sẵn cho bạn rồi, không cần phài suy nghĩ chi nhiều nhé he he.
1.Code lấy bài viết mặt định
<!-- Get post mặt định -->
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php endwhile; else : ?>
<p>Không có</p>
<?php endif; ?>
<!-- Get post mặt định -->
Đoạn code đặt trong index sẽ lấy list bài viết mới nhất, Đặt trong category sẽ lấy danh sách bài viết của category đó, đặt trong single sẽ lấy nội dung của bài đó!.
2.Code lấy 10 bài viết mới nhất theo category
<!-- Get post News Query -->
<?php $getposts = new WP_query(); $getposts->query('post_status=publish&showposts=10&post_type=post&cat=1'); ?>
<?php global $wp_query; $wp_query->in_the_loop = true; ?>
<?php while ($getposts->have_posts()) : $getposts->the_post(); ?>
<?php endwhile; wp_reset_postdata(); ?>
<!-- Get post News Query -->
Đây là code lấy nội dung bài viết được chỉ định số từ nhất định. Cách dùng <?php echo teaser(30); ?>, Với được code trên mình sẽ lấy 30 từ đầu tiên trong bài viết!
14.Code lấy tất cả hình ảnh trong nội dung bài viết.
function get_link_img_post(){
global $post;
preg_match_all('/src="(.*)"/Us',get_the_content(),$matches);
$link_img_post = $matches[1];
return $link_img_post;
}
Chèn code này trong file functions.php, để hiển thị chúng ta dùng forech nó ra nhé!
24. Code lấy ảnh đầu tiên trong bài viết làm ảnh đại diện
function catch_that_image() {
global $post, $posts;
$first_img = '';
ob_start();
ob_end_clean();
$output = preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post->post_content, $matches);
$first_img = $matches [1] [0];
if(empty($first_img)){ //Defines a default image
$first_img = "/images/default.jpg"; //Duong dan anh mac dinh khi khong tim duoc anh dai dien
}
return $first_img;
}
Cách sử dùng: Chèn đoạn code nào vào khu vực muốn hiển thị hình đại diện.
This is the most significant addition to our platform, previously called LeapXpert’s Federated Messaging Orchestration Platform (or FMOP™ for short), since its release in 2019.
Why now?
Because as business communication continues shifting to a new model, it requires new solution types.
Because enterprises are facing new constraints and want to reach new goals but are lacking the right solutions for these new problems.
This new platform aims at serving enterprises, both in regulated and non-regulated industries, and enables their employees to better communicate responsibly with their clients, partners, and colleagues.
So what’s new?
iMessage
As the new hybrid work model is here to stay, business communication is now all about convenience, speed, security, productivity, and engagement for both external and internal communications, to cover the different needs of clients, employees, and enterprises.
Clients want to communicate on their preferred messaging apps such as WhatsApp, WeChat, Signal, Telegram, etc. They often favor text messaging over other channels, including e-mail. Consumers have embraced native messaging channels such as iMessage, whose use is growing fast, especially in the US. In 2021, more than 70% of US consumers aged 18-24 owned an iPhone (from 47% in 2018) and many are heavy iMessage users.
That’s why we’re excited to announce the general availability of iMessage support. It’s the only robust and scalable iMessage support on the market.
A single employee identity
Employees want to choose the best communication channel that matches convenience, productivity, and enterprise policies while keeping personal and professional communications separate. Some want a unified messaging and voice solution – as voice is still a part of any business interaction. Some prefer to use native messaging channels when communicating externally and even internally. Wither others want to do more with their selected enterprise collaboration and productivity platform, such as Microsoft Teams.
This is why the new LeapXpert Communications Platform now provides:
A single employee identity across communication channels – The LeapXpert Communications Platform is based on a single employee identity or phone number across all supported communication channels. This phone number can be an individual business or personal number, or a pooled business number provided by mobile carriers or cloud telephony providers.
The new solution eases and improves client satisfaction and engagement while removing the complex management of phone numbers in siloed solutions and addressing the lack of available phone numbers globally.
Voice support
LeapXpert’s platform now supports incoming and outgoing voice calls (IP and PSTN calls) in addition to messaging and SMS, through the single employee phone number. Employees can use their existing enterprise apps like Leap Work mobile and desktop apps or integrated third-party applications like Teams Phone while keeping their business and personal conversations separate.
Governed and Native modes
If at first we required that our platform be accessed through enterprise applications, we listened to the market and understood that some prefer the native messenger experience, so we developed the only solution that supports both models.
The platform now adapts to different employee behaviors and preferences – application-based or native communication channel, BYOD or corporate device, single enterprise application for internal and external communication, or dedicated applications.
Leap Work for Microsoft Teams
Enterprises are looking for converged, secure, compliant, and open communication solutions breaking with the current siloed solution approach that is expensive and difficult to maintain.
Convergence includes internal and external communications in one platform like Teams or Slack, text and voice communications triggering for example IP or PSTN voice calls from text messages, and fixed and mobile communications integrating native mobile voice channels into collaboration and productivity applications like Microsoft Teams Phone Mobile solution.
Information protection, security, and data governance are becoming a top priority for many enterprises. They notice that more files are exchanged through messaging channels, and therefore risks of viruses and cyber attacks increase. They also must monitor business information access and sharing to protect themselves against possible internal misconduct affecting their business and brand.
Communications recordkeeping and regulatory compliance are driving lots of investments among financial institutions as regulators are cracking down on US banks with more than $1.8 billion in fines. A similar crackdown in Europe or other regions is likely underway.
Finally, an open platform is a must-have in a complex disaggregated technical environment where cloud, mobility, enterprise systems, communication supervision, and industry-specific solutions must work together.
This is why The LeapXpert Communications Platform now supports:
Leap Work for Microsoft Teams – The LeapXpert Communications Platform integrates with Microsoft Teams with Leap Work for Teams, our mobile and desktop app, available on the Teams store. It’s now possible to chat with external parties on their messaging app of choice from within Microsoft Teams. The native integration allows users to use the same Teams chat interface for internal and external communication increasing user productivity and improving client engagement. The platform ensures external conversations remain compliant and secure following enterprise governance guidelines.
All platform enterprise controls such as antivirus, antimalware, information barriers, and ethical walls are part of The LeapXpert Communications Platform and apply to the new features.
Growing ecosystem of partners
Thanks to its open interfaces, the new platform has increased its number of out-of-the-box integrations and technological partners in the last few months including Microsoft (Azure services and Teams), Blackberry and Mobileiron (Mobile Device Management), and OpenFin (Operating System for Finance). As system integration is painful for many enterprises, we want our platform to work seamlessly with leading market solutions and technologies.
What’s next?
Our new product, which supports all previous functionalities, has been renamed The LeapXpert Communications Platform. This name reflects the value LeapXpert brings to enterprises embracing the modern work environment:
A new way of conducting business communications that is responsible, secure, and compliant across the latest communications channels like consumer messaging apps, as well as traditional channels, such as voice calls.
Please contact us for a demo or join us in a series of upcoming events where we will be unveiling the solution in the US, Europe, and Asia.
Vietnam/Cairo, tháng 12/2022 – Tập đoàn Công Nghệ NFQ với trụ sở chính tại Đức và hơn 300 nhân sự lập trình viên chất lượng cao tại Việt Nam, chuyên cung cấp và xây dựng giải pháp phần mềm cho các khách hàng lớn trên khắp Châu Âu và Châu Á, đã và đang mở rộng thị trường quốc tế sang khu vực Châu Phi sau khi mua lại phần lớn cổ phần của Dlivr.io có trụ sở ở thủ đô Cairo – Ai Cập
Việc mở rộng tại thị trường Châu Phi và sáp nhập với Dlivr.io LLC lần này nâng tổng số nhân viên tại Tập đoàn NFQ lên đến hơn 900 nhân viên tại mười văn phòng trải khắp ba Châu lục trên toàn cầu.
Thông qua việc tăng cường hệ thống vận hành từ Châu Á và Châu Âu sang thị trường vẫn luôn được đánh giá cao về tiềm năng phát triển CNTT như Châu Phi, đánh dấu một bước tiến quan trọng trong lộ trình nâng cao năng lực cạnh tranh, cung ứng nguồn nhân lực CNTT chuyên môn cao trên quy mô toàn cầu của Tập đoàn NFQ.
Dẫn lời người đồng sáng lập Tập đoàn NFQ, ông Lars Jankowfsky:
“Châu Phi hiện đang đóng một vai trò quan trọng trong sự phát triển của hệ sinh thái CNTT trên toàn thế giới. Việc mở rộng trung tâm phát triển phần mềm này giúp cho NFQ có thể tiếp cận với nguồn nhân lực dồi dào của lục địa này cũng như mang đến những cơ hội tuyệt vời hơn cho các đối tác của NFQ có thể tiếp cận với nguồn nhân lực chất lượng cao trên toàn thế giới. Bên cạnh đó là cơ hội cho các nhân viên của NFQ có thể trao đổi, học tập, làm việc và phát triển, nâng cao các kỹ năng chuyên môn với những đồng nghiệp trên toàn cầu.”
Ông cho biết thêm:
“Qua kinh nghiệm mở rộng thành công trung tâm phát triển phần mềm khu vực Châu Á của NFQ tại TP.HCM năm 2015 từ 5 nhân sự lên hơn 300 nhân sự trong năm 2022 trải khắp Việt Nam và Thái Lan. Chúng tôi thấy nhiều điểm tương đồng khi chọn Cairo làm văn phòng đầu tiên của NFQ tại Châu Phi bởi trình độ học vấn, kỹ năng chuyên môn, Tiếng Anh và năng lực làm việc của các kỹ sư CNTT nơi đây được xem là một trong những nơi tốt nhất trên thế giới.”
Tại Cairo, nhà sáng lập và điều hành Dlivr.io – Senan Sharhan đang dẫn dắt một đội ngũ với gần 30 lập trình viên chuyên môn cao chuyên về thiết kế và lập trình những dự án công nghệ số tiên phong. Tại đây, công ty đã và đang phát triển những dự án đột phá, các phần mềm mang tính linh hoạt cao cho các công ty/tập đoàn thương mại điện tử tại Châu Âu và Ả Rập. Việc sáp nhập thêm các kỹ sư CNTT tay nghề kỹ thuật cao từ Dlivr.io lần này đã giúp Tập đoàn NFQ củng cố thêm tiềm lực của đội ngũ tại Châu Âu và Châu Á, đồng thời mở rộng nguồn khách hàng dồi dào vào các thị trường tiềm năng trong tương lai.
Sự kiện này khẳng định NFQ đang ngày càng vươn rộng ra toàn cầu.
Thông tin bổ sung
Thông tin thêm về NFQ
NFQ là công ty CNTT đa quốc gia với đội ngũ nhân viên lên đến 900 trải dài khắp thế giới. Tập đoàn NFQ chuyên cung cấp chiến lược công nghệ số và thực hiện các dự án cho các doanh nghiệp đang tìm kiếm cơ hội mở rộng kinh doanh và nâng cao khả năng cạnh tranh bằng việc đầu tư vào xây dựng phần mềm và các nền tảng công nghệ, số hóa doanh nghiệp, đưa trí tuệ công nghệ và khoa học số vào kinh doanh. NFQ cung cấp giải pháp về phát triển phần mềm, thiết kế giao diện người dùng (UI/UX), Tối ưu hóa tỉ lệ chuyển đổi (CRO) và tham vấn phát triển dịch vụ cho các doanh nghiệp làm ở các lĩnh vực khác nhau trên toàn thế giới như du lịch, bán lẻ đa kênh, vận tải, hậu cần, liên doanh… NFQ đã tạo tiếng vang trong việc phát triển và xây dựng các nhóm kỹ sư phần mềm CNTT có năng lực vượt bậc đang phụ trách chính trong dự án KAYAK và thúc đẩy công nghệ cho nền tảng đặt phòng hàng đầu như HomeToGo. NFQ cũng đã xây dựng thành công nền tảng tìm kiếm chuyến bay Swoodoo ở Đức và DACH, một trong những nền tảng được cho là dẫn đầu về kỹ thuật và giải pháp trong lĩnh vực này thời điểm bấy giờ.
Tại Việt Nam, NFQ đã xây dựng được một mạng lưới trung tâm phát triển phần mềm rộng khắp với hơn 300 nhân sự tại 4 văn phòng trên các thành phố lớn Hồ Chí Minh, Đà Nẵng, Cần Thơ, Hà Nội. NFQ Asia được chứng nhận là một trong những công ty công nghệ có môi trường làm việc tốt nhất tại Việt Nam trong suốt 4 năm vừa qua theo bình chọn từ ITviec.
Mục tiêu của NFQ là trở thành tập đoàn công nghệ uy tín, nổi tiếng hàng đầu, không chỉ ở chất lượng dịch vụ, sản phẩm mà còn ở môi trường làm việc.
Bài viết được sự cho phép của tác giả Phạm Minh Khoa
Để hiểu rõ hơn khái niệm Redux middleware, chúng ta cùng thử xử lý 1 bài toán như sau:
Bạn cần phải ngăn chặn người dùng (users) không được sử dụng các từ khóa bị cấm (ví dụ như vl, vkl, cmnr, …) trong bài viết của họ. Để đơn giản thì mình sẽ xử lý lúc người dùng submit bài viết (trong ví dụ sẽ chỉ check trong tiêu đề bài viết thôi nhé)
handleSubmit(event) {
event.preventDefault();
const { title } = this.state;
this.props.addArticle({ title });
this.setState({ title: "" });
}
Việc kiểm tra tất nhiên sẽ được đặt trước dòng this.props.addArticle và nó sẽ kiểu như này:
Việc làm như này tất nhiên cũng chẳng sao, tuy nhiên trong đoạn code trên chứa phần xử lý logic (business logic) và nó nằm trong UI Component; thế là không đạt được mục đích của Redux là chuyển logic ra khỏi React Component rồi. Redux middleware sinh ra để giải quyết bài toán trên cho mọi người. Hiểu 1 cách đơn giản thì Redux middleware cho phép chúng ta can thiệp vào giữa thời điểm dispatch 1 action và thời điểm action đến được reducer. Bạn có thể nhìn flow dưới đây để dễ hình dung.
Redux middleware là 1 function trả về 1 function, nhận next như 1 tham số. Bên trong function sẽ trả về 1 function khác nhận action như 1 tham số và cuối cùng là trả về next(action). Nó sẽ giống như thế này:
function forbiddenWordsMiddleware() {
return function(next){
return function(action){
// do your stuff
return next(action);
}
}
}
Ở đây bạn sẽ luôn luôn phải gọi next(action) ở trong middleware của bạn, nếu không thì Redux sẽ dừng lại, không có 1 action nào được đưa tới reducer. Trong middleware bạn cũng có thể truy cập vào state và sử dụng dispatch như sau:
function forbiddenWordsMiddleware({ getState, dispatch }) {
return function(next){
return function(action){
// do your stuff
return next(action);
}
}
}
Middleware trong Redux đóng vai trò rất quan trọng vì chúng sẽ chứa phần lớn logic ứng dụng của bạn với những lợi ích khi sử dụng:
Giúp tách biệt hầu hết logic ra khỏi giao diện (UI library)
Có khả năng tái sử dụng
Có thể test được 1 cách độc lập
Quay lại bài toán ban đầu, để sử dụng được middleware thì chúng ta phải apply nó vào trong store
import { createStore, applyMiddleware } from "redux";
import rootReducer from "../reducers/index";
import { forbiddenWordsMiddleware } from "../middleware";
const store = createStore(
rootReducer,
applyMiddleware(forbiddenWordsMiddleware)
);
export default store;
Khi submit action thêm mới bài viết (ADD_ARTICLE), middleware sẽ thực hiện việc check xem có từ khóa bị cấm hay không. Nếu không thì action thêm mới bài viết (ADD_ARTICLE) sẽ được thực hiện bình thường thông qua next(action). Nếu gặp từ khóa bị cấm, chúng ta sẽ dispatch 1 action khác mang tên là “FOUND_BAD_WORD” để gửi đến cho reducer. Code cụ thể sẽ được viết như dưới:
import { ADD_ARTICLE } from "../constants/action-types";
const forbiddenWords = ["spam", "money"];
export function forbiddenWordsMiddleware({ dispatch }) {
return function(next) {
return function(action) {
// do your stuff
if (action.type === ADD_ARTICLE) {
const foundWord = forbiddenWords.filter(word =>
action.payload.title.includes(word)
);
if (foundWord.length) {
return dispatch({ type: "FOUND_BAD_WORD" });
}
}
return next(action);
};
};
}
Ở ví dụ trong bài hôm nay, các xử lý của chúng ta đều là xử lý đồng bộ. Bài toán sẽ trở nên phức tạp hơn nếu như việc check từ khóa bị cấm cần thiết phải thông qua việc call API từ phía backend. Lúc đó cần xử lý bất đồng bộ. Tuy nhiên việc dispatch 1 action là đồng bộ; không thể thực hiện call 1 Promise trong này được. Nếu vẫn cố chày cối viết vào thì sẽ ra sao, thử xem nhé.
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Với lập trình hướng đối tượng, chúng ta thường xuyên làm việc với rất nhiều class trong một chương trình, các class được liên kết với nhau theo một mối quan hệ nào đó. Dependency là một loại quan hệ giữa 2 class mà trong đó một class hoạt động độc lập và class còn lại phụ thuộc bởi class kia. Sự phụ thuộc chặt chẽ này gây rất nhiều khó khăn khi hệ thống cần thay đổi, nâng cấp. Để giải quyết vấn đề này chúng ta có thể sử dụng Dependency Injection (DI), một dạng design pattern được thiết kế nhằm ngăn chặn sự phụ thuộc nêu trên.
DI – Dependency Injection
Dependency Inversion Principle (DIP), Inversion of Control (IoC), Dependency Injection (DI) là gì
Trước khi bắt đầu với Dependency Injection, các bạn hãy dành chút thời gian xem lại nguyên lý SOLID trong OOP. Nguyên lý cuối cùng, tương ứng với chữ D trong SOLID chính là DIP – Dependency Inversion Principle (nguyên lý đảo ngược sự phụ thuộc). Nội dung của nguyên lý này như sau :
Các module cấp cao không nên phụ thuộc vào các module cấp thấp. Cả 2 nên phụ thuộc vào abstraction.
Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại, chi tiết nên phụ thuộc vào abstraction. Các class giao tiếp với nhau thông qua interface, không phải thông qua implementation.
Chúng ta thường hay lẫn lộn giữa các khái niệm Dependency Inversion Principle (DIP), Inversion of Control (IoC), Dependency Injection (DI). Ba khái niệm này tương tự nhau, tất cả đều hướng đến một mục đích duy nhất là tạo ra ứng dụng ít kết dính (loosely coupling), dễ mở rộng (flexibility) cũng như giúp lập trình viên tập trung chủ yếu vào công việc business flow.
Dependency Inversion Principle (DIP): là một nguyên lý để thiết kế và viết code.
Inversion of Control (IoC): là một design pattern được tạo ra để code có thể tuân thủ nguyên lý Dependency Inversion. Có nhiều cách hiện thực Pattern này như ServiceLocator, Event, Delegate, … và Dependency Injection là một trong các cách đó.
Dependency Injection (DI): là một Design Pattern, một cách để hiện thực Inversion of Control Pattern. DI chính là khả năng liên kết giữa các thành phần lại với nhau, các module phụ thuộc (dependency) sẽ được inject vào module cấp cao.
Đơn giản chúng ta chỉ cần ghi nhớ:
DI is about wiring, IoC is about direction, and DIP is about shape.
IoC là hướng đi, DIP là định hình cụ thể của hướng đi, còn DI là một hiện thực cụ thể.
Dependency Injection (DI) là một design pattern, một kỹ thuật cho phép xóa bỏ sự phụ thuộc giữa các module, làm cho ứng dụng dễ dàng hơn trong việc thay đổi module, bảo trì code và testing.
DI cung cấp cho một đối tượng các thể hiện phụ thuộc (dependencies) của nó từ bên ngoài truyền vào mà không phải khởi tạo trực tiếp từ trong class sử dụng.
Nhiệm vụ của dependency injection:
Tạo các đối tượng.
Quản lý sự phụ thuộc (dependencies) giữa các đối tượng.
Cung cấp (inject) các phụ thuộc được yêu cầu cho đối tượng (được truyền từ bên ngoài đối tượng).
Nguyên tắc hoạt động của DI:
Các module không giao tiếp trực tiếp với nhau, mà thông qua interface. Module cấp thấp sẽ implement interface, module cấp cao sẽ gọi module cấp thấp thông qua interface.
Việc khởi tạo các module cấp thấp sẽ do DI Container/ IoC Container thực hiện.
Việc Module nào gắn với interface nào sẽ được config trong file properties, trong file XML hoặc thông qua Annotation. Annotation là một cách thường được sử dụng trong các Framework, chẳng hạn như @Inject với CDI, @Autowired với Spring hay @ManagedProperty với JSF.
Các thành phần tham gia Dependency Injection Pattern:
Client : là một class cần sử dụng Service.
Service : là một class/ interface cung cấp service/ dependency cho Client.
ServiceImpl: cài đặt các phương thực cụ thể của Service.
Injector: là một lớp chịu trách nhiệm khởi tạo các service và inject các thể hiện này cho Client.
Các dạng Dependency Injection
Constructor Injection: Các dependency sẽ được container truyền vào (inject vào) 1 class thông qua constructor của class đó. Đây là cách thông dụng nhất.
Setter Injection: Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter.
Fields/ properties: Các dependency sẽ được truyền vào 1 class một cách trực tiếp vào các field.
Interface Injection: Class cần inject sẽ implement 1 interface. Interface này chứa 1 hàm tên Inject. Container sẽ injection dependency vào 1 class thông qua việc gọi hàm Inject của interface đó. Đây là cách rườm rà và cũng ít được sử dụng.
Service Locator: nó hoạt động như một mapper, cho phép thay đổi code tại thời điểm run-time mà không cần biên dịch lại ứng dụng hoặc phải khởi động lại.
Ví dụ chúng ta có một class cho phép User có thể gửi message.
EmailService.java
package com.gpcoder.patterns.creational.dependencyinjection.message.simple;
public class EmailService {
public void sendEmail(String message) {
System.out.println("Message: " + message);
}
}
UserController.java
package com.gpcoder.patterns.creational.dependencyinjection.message.simple;
public class UserController {
private EmailService emailService = new EmailService();
public void send() {
emailService.sendEmail("Hello Dependency injection pattern");
}
}
Chương trình trên rất đơn giản, chỉ gồm có 2 class. Tuy nhiên, nó có một vài giới hạn như sau:
Lớp UserController phụ thuộc trực tiếp vào class EmailService. Mỗi khi có thay đổi trong lớp EmailService, chẳng hạn thêm tham số cho constructor của class này lên sẽ ảnh hưởng trực tiếp đến class UserController.
Một User khác không muốn sử dụng cách gửi message thông qua email, chẳng hạn qua sms, facebook, …
Khó khăn khi viết Unit Test cho UserController do phụ thuộc trực tiếp vào EmailService.
Bây giờ chúng ta sẽ áp dụng Dependency Injection để giải quyết các giới hạn trên.
MessageService.java
package com.gpcoder.patterns.creational.dependencyinjection.message.di;
public interface MessageService {
void sendMessage(String message);
}
EmailService.java
package com.gpcoder.patterns.creational.dependencyinjection.message.di;
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Email message: " + message);
}
}
MessageService.java
package com.gpcoder.patterns.creational.dependencyinjection.message.di;
public class SmsService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Sms message: " + message);
}
}
UserController.java
package com.gpcoder.patterns.creational.dependencyinjection.message.di;
public class UserController {
private MessageService messageService;
public UserController(MessageService messageService) {
this.messageService = messageService;
}
public void send() {
messageService.sendMessage("Hello Dependency injection pattern");
}
}
DependencyInjectionPatternExample.java
package com.gpcoder.patterns.creational.dependencyinjection.message.di;
public class DependencyInjectionPatternExample {
public static void main(String[] args) {
MessageService messageService = new EmailService();
UserController userController = new UserController(messageService);
userController.send();
}
}
Như bạn thấy, thay vì sử dụng trực tiếp lớp EmailService chúng ta sử dụng interface. Lớp UserController không trực tiếp khởi tạo message service mà nó được truyền từ bên ngoài vào. Chính vì vậy mà các lớp không còn phụ thuộc vào nhau, chúng ta có thể dễ dàng sử đổi hay thêm bất kỳ service nào khác mà không ảnh hưởng đến UserController. Đây chính là dạng Constructor Injection của Dependency Injection Pattern.
Tuy nhiên, chương trình trên vẫn còn một hạn chế là chúng ta phải khởi tạo một thể hiện cụ thể cho MessageService ở rất nhiều nơi, chương trình cũng rất khó khăn khi cần thay thế một service cho toàn bộ hệ thống. Để giải quyết vấn đề này, chúng ta có thể áp dụng Inversion of Control Container (IoC container), một nơi để quản lý các thành phần phụ thuộc này và cung cấp thể hiện cụ thể khi cần sử dụng.
Ưu điểm và khuyết điểm của Dependency Injection
Ưu điểm:
Reduced dependencies: giảm sự kết dính giữa các module.
Reusable: code dễ bảo trì, dễ tái sử dụng, thay thế module. Giảm boiler-plate code do việc tạo các biến phụ thuộc đã được injector thực hiện.
Testable: rất dễ test và viết Unit Test.
Readable: dễ dàng thấy quan hệ giữa các module vì các dependecy đều được inject vào constructor.
Khuyết điểm:
Khái niệm DI khá khó hiểu đối với người mới tìm hiểu.
Sử dụng interface nên đôi khi sẽ khó debug, do không biết chính xác module nào được gọi.
Các object được khởi tạo toàn bộ ngay từ đầu, có thể làm giảm performance.
Có thể gặp lỗi ở run-time thay vì compile-time.
Sử dụng Dependency Injection khi nào?
Một số trường hợp sử dụng DI:
Khi cần inject các giá trị từ một cấu hình cho một hoặc nhiều module khác nhau.
Khi cần inject một dependency cho nhiều module khác nhau.
Khi cần một vài service được cung cấp bởi container.
Khi cần tách biệt các dependency giữa các môi trường phát triển khác nhau. Chẳng hạn, với môi trường dev chỉ cần log việc gửi mail, trong môi trường product cần gởi mail thông qua một API thật sự.
Inversion of Control (IoC) dịch là đảo ngược điều khiển. Ý của nó là làm thay đổi luồng điều khiển của ứng dụng, giúp tăng tính mở rộng của một hệ thống.
IoC được chia thành 2 loại:
Dependency Lookup : sẽ tìm kiếm đối tượng phụ thuộc trong khung chứa IoC và sau đó chúng ta có thể dùng code để đưa đối tượng phụ thuộc vào trong đối tượng bị phụ thuộc. Dependency Lookup được chia thành hai loại khác nhau đó là:
Dependency Pull: các đối tượng phụ thuộc sẽ được lấy ra từ một nơi mà các đối tượng phụ thuộc đã được đăng ký chứ không phải lấy trực tiếp từ khung chứa.
Contextualized Dependency Lookup (CDL): việc lấy đối tượng phụ thuộc xảy ra trực tiếp với khung chứa luôn chứ không thông qua nơi mà đối tượng phụ thuộc đã đăng ký.
Dependency Injection : sẽ đưa luôn đối tượng phụ thuộc vào đối tượng bị phụ thuộc.
Hollywood principle cũng thường được gọi là một IoC hay DI:
Inversion of Control Container (IoC container) là gì?
Khi áp dụng kỹ thuật Dependency Injection, thì một vấn đề khác nảy sinh là làm thế nào chúng ta biết được một lớp sẽ phụ thuộc vào những lớp nào để khởi tạo nó. Để giải quyết điều này, người ta nghĩ ra Dependency Injection Container hay còn gọi là Inversion of Control Container (IoC container).
IoC Container được xây dựng dựa trên ý tưởng của IoC, nó có nhiệm vụ quản lý các thành phần khác nhau, cung cấp tài nguyên cho các thành phần khi chúng đòi hỏi tài nguyên dựa vào thông tin từ các file cấu hình. Nhờ đó việc quản ý sẽ dễ dàng hơn, tập trung hơn và đơn giản, hiệu quả hơn rất nhiều so với việc phải phân tán tài nguyên cho từng thành phần tự xử lý.
Về bản chất thì IoC Conainter như một tấm bản đồ, nó cho ta biết một lớp phụ thuộc vào những lớp nào khác bằng kỹ thuật Reflection, hoặc từ danh sách đã được đăng ký trước.
Sức mạnh của IoC Container được thể hiện thông qua việc nó được áp dụng trong các Framework. Một đặc điểm quan trọng của Framework là các phương thức được định nghĩa bởi người dùng thông thường được gọi từ trong bản thân Framework chứ không phải từ code ứng dụng của người dùng. Framework đóng vai trò của chương trình chính trong việc điều phối và sắp xếp hoạt động ứng dụng. Sự đảo ngược điều khiển này tạo ra cho Framework sức mạnh thông qua việc mở rộng. Chính IoC mang đến sự khác biệt giữa một Framework và một thư viện.
Thư viện là tập hợp các tính năng mà chúng ta có thể sử dụng, nó được tổ chức thành các class. Sau mỗi lần gọi một phương thức, thư viện sẽ làm một số việc và sau đó trả quyền điều khiển về cho người dùng.
Framework là một biểu hiện của thiết kế trừu tượng với nhiều hành vi được xây dựng sẵn bên trong, để sử dụng nó chúng ta cần chèn các hành vi của mình vào các nơi khác nhau trong Framework bằng các class hoặc plugin. Code của Framework sẽ gọi đến code của chúng ta tại những điểm cần thiết.
Tự xây dựng 1 framework đảo ngược điều khiển (IoC)
Chúng ta tiếp tục với ví dụ trên bằng cách áp dụng IoC để quản lý việc khởi tạo đối tượng.
Để xây dựng một framework đảo ngược điều khiển, ta dùng kỹ thuật Reflection để khởi tạo đối tượng động. Trước tiên ta cần đọc file cấu hình để lấy ra thông tin về tên lớp hiện thực cần được dùng.
Tạo file một Injector để đọc thông tin cấu hình và khởi tạo đối tượng cho ứng dụng.
Injector.java
package com.gpcoder.patterns.creational.dependencyinjection.ioc;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.management.InstanceNotFoundException;
public class Injector {
private static final String IOC_CONFIGURATION_FILE_NAME = "ioc.properties";
private Injector() {
throw new UnsupportedOperationException();
}
public static Object getInstance(String key) throws InstanceNotFoundException {
try (InputStream input = new FileInputStream(IOC_CONFIGURATION_FILE_NAME)) {
// load a properties file
Properties prop = new Properties();
prop.load(input);
// get the property value
String className = prop.getProperty(key);
return Class.forName(className).newInstance();
} catch (IOException | InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
throw new InstanceNotFoundException(
"Can't create instance of " + key + " base on the configuration of " + IOC_CONFIGURATION_FILE_NAME);
}
}
}
Chương trình của chúng ta được viết lại như sau:
package com.gpcoder.patterns.creational.dependencyinjection.ioc;
import javax.management.InstanceNotFoundException;
import com.gpcoder.patterns.creational.dependencyinjection.di.MessageService;
import com.gpcoder.patterns.creational.dependencyinjection.di.UserController;
public class DependencyInjectionPatternExample {
public static void main(String[] args) throws InstanceNotFoundException {
MessageService messageService = (MessageService) Injector.getInstance("messageService");
UserController userController = new UserController(messageService);
userController.send();
}
}
Như bạn thấy, bây giờ chương trình của chúng ta chỉ còn một nơi để khởi tạo và inject đối tượng, khi muốn thay đổi message service chỉ cần thay đổi trong file properties.
So sánh Dependency Injection Pattern với các Pattern khác
So sánh Dependency Injection Pattern với Singleton Pattern
Dependency Injection (DI) có nhiều ưu điểm hơn Singleton, ở một số ý sau:
Dễ dàng thay thế:Singleton thì lúc nào cũng chỉ có thể truy xuất 1 Object duy nhất, không thay thể bằng cái khác được. Với DI có thể thay thế bằng object khác tại thời điểm run-time.
Linh hoạt:Singleton thì luôn chỉ có một Object. Với DI có thể dùng riêng từng thể hiện cho mỗi Object hoặc một thể hiện dùng chung cho nhiều Object.
Kế thừa:Singleton thì không thể thừa kế. Với DI thì không giới hạn.
Một nhược điểm của DI so với Singleton là chi phí khởi tạo lớn hơn, do sử dụng Reflection để truy xuất các property trong object.
Với các hệ thống lớn, phức tạp, có khả năng thay đổi, mở rộng thì nên dùng DI. Với những trường hợp object muốn truy xuất được sử dụng ở khắp mọi nơi trong dự án, ở khắp các tầng trong hệ thống có thể sử dụng Singleton.
So sánh Dependency Injection Pattern với Factory Pattern
Cả hai Dependency Injection (DI) và Factory đều nhằm mục đích cung cấp một cách tiện lợi cho việc tạo một thể hiện của một class. Hai Pattern này đều dựa trên quy tắc “lập trình cho interface chứ không phải để implement interface đó”.
Một vài khác biệt chủ yếu giữa DI và Factory Pattern là:
DI giúp chúng ta tạo ra ứng dụng ít kết dính, với Factory Pattern mỗi class có một dependency với Factory method.
Sử dụng Factory Pattern khó khăn khi viết Unit test do phụ thuộc vào các dependency. Ngược lại với DI thì dễ dàng viết Unit do không phụ thuộc vào dependency.
Hạn chế của DI so với Factory Pattenr là cần phải cấu hình và cần một container để inject các dependency.
So sánh Dependency Injection Pattern với Service Locator Pattern
Cả hai Dependency Injection (DI) và Service Locator (SL) đều tuân theo DIP principle. Nó giúp chúng ta tạo ra ứng dụng ít kết dính, dễ hiểu, dễ viết test, dễ mở rộng, bảo trì.
Sự khác biệt giữa DI và SL:
Sự khác biệt chủ yếu giữa DI và SL là cách cài đặt (implement) để cung cấp một thể hiện cho các lớp của ứng dụng. DI sử dụng một builder object để khởi tạo các đối tượng và cung cấp (inject) các phụ thuộc được yêu cầu cho đối tượng từ lớp bên ngoài. SL sử dụng một locator object để giải quyết (resolve) sự phụ thuộc trong một lớp.
Khi sử dụng SL, các đối tượng được yêu cầu một cách rõ ràng để nhận một thể hiện của đối tượng và mỗi class có một dependency với SL. Trong khi sử dụng DI không có yêu cầu rõ ràng, dependency injector chỉ được gọi một lần dựa vào config tại thời điểm startup để inject các dependency vào main class.
SL có thể ẩn các dependency với class client, nhưng client cần phải thấy được Locator. Với DI, client không thấy được class Injector.
SL cần cung cấp ít nhất một tham số để nhận về thể hiện của một đối tượng do đó gây khó khăn khi viết unit test hơn. Với DI, chúng ta có thể pass một mock object để test.
Hạn chế của DI so với SL là cần phải cấu hình và cần một container để inject các dependency.
SL dễ code, dễ hiểu hơn so với DI. Tuy nhiên, nó thích hợp với các dụng nhỏ. DI thích hợp với các ứng dụng lớn, có nhiều class phụ thuộc.
Lời kết
Dependency Injection và IoC container là những khái niệm rất quan trọng, hầu hết các ứng dụng, framework hiện tại đều sử dụng nó. Chúng ta cần tìm hiểu để biết rõ DI và IoC được ứng dụng trong trường hợp nào. Nếu áp dụng hợp lý code của chúng ta sẽ ít kết dính hơn (loose coupling), dễ bảo trì, dễ test hơn, tổ chức ứng dụng hợp lý và gọn gàng hơn.
Hy vọng bài viết này đã giúp bạn hiểu hơn về Dependency Injection (DI) cũng như những ưu điểm
Bài viết được sự cho phép của tác giả Phạm Minh Khoa
Như tiêu đề, Widgetbook là 1 package giúp tạo Storybook dành cho Flutter; nó giúp developers thiết lập danh mục các widgets của họ, thử nghiệm 1 cách nhanh chóng trên các thiết bị và themes; đồng thời có thể dễ dàng chia sẻ cho designers và khách hàng.
Use cases cho Widgetbook
Xây dựng các widgets 1 cách độc lập và test chúng 1 cách trực quan
Widgetbook cung cấp 1 môi trường để xây dựng các UIs 1 cách độc lập. Chúng cho phép bạn có thể phát triển các widgets mà không bị ảnh hưởng từ các phụ thuộc thành phần khác của màn hình. Bạn có thể nhanh chóng hiển thị UIs trên các thiết bị giả lập khác nhau, giúp bạn có thể kiểm tra (test) và phát triển các lỗi giao diện.
Dễ dàng phát triển ra lỗi khi text quá dàiNhư trường hợp này thì lỗi xảy ra với dark mode
Có 1 cái nhìn tổng quan về tất cả các widgets của bạn
Khi projects của bạn càng ngày càng nhiều widgets được tạo ra, thì việc có 1 quyển từ điển để dễ dàng tìm kiếm, tra cứu cách sử dụng của những widgets sẵn có trong projects là 1 điều hết sức cần thiết. Đây cũng là ý nghĩa của việc tạo ra Storybook.
Nâng cao khả năng hợp tác với designer, PO và khách hàng
Widgetbook cung cấp services giúp bạn có thể đẩy storybook widgets và màn hình của bạn lên host giúp khách hàng và các bên liên quan có thể dễ dàng review trên các thiết bị và themes khác nhau 1 cách dễ dàng; từ đó giúp giảm bớt tối đa thời gian họp và chỉnh sửa cho phần UIs trong dự án.
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Khi làm việc với đối tượng Stream trong Java, đôi khi chúng ta sẽ có những đối tượng Stream của những đối tượng List, Set hay là Array. Ví dụ như:
List<String> students1 = new ArrayList<>();
students1.add("Khanh");
List<String> students2 = new ArrayList<>();
students2.add("Thanh");
students2.add("Dung");
List<List<String>> students = Arrays.asList(students1, students2);
Stream<List<String>> stream = students.stream();
Ở đây, chúng ta có đối tượng List chứa những đối tượng List của những đối tượng String và khi convert đối tượng này qua đối tượng Stream, chúng ta có đối tượng Stream chứa đối tượng List của những đối tượng String.
Để giải quyết vấn đề này, chúng ta có thể sử dụng phương thức flatMap() trong đối tượng Stream trước khi chúng ta cần thao tác điều gì đó trên đối tượng Stream. Sử dụng phương thức flatMap() chúng ta có thể chuyển đổi đối tượng Stream của những đối tượng List, Set or Array thành đối tượng Stream của những đối tượng đơn giản hơn.
Ví dụ như:
List<String> students1 = new ArrayList<>();
students1.add("Khanh");
List<String> students2 = new ArrayList<>();
students2.add("Thanh");
students2.add("Dung");
List<List<String>> students = Arrays.asList(students1, students2);
Stream<List<String>> stream = students.stream();
Stream<String> flatMap = stream.flatMap(l -> l.stream());
Bài viết được sự cho phép của tác giả Nguyễn Hồng Quân
Mấy nay nghe báo chí ca ngợi về blockchain & Web3 quá nên mình quyết định bước chân vào lĩnh vực này để tìm hiểu coi nó có ứng dụng thực tế gì không. Sau một tháng đọc tài liệu và viết code thử, mình nghĩ là đã tìm thấy câu trả lời.
Mình tìm hiểu về blockchain & Web3 với tâm thế của một người làm kĩ thuật, tức là mình không chỉ đọc khơi khơi. Mình muốn lập trình, làm ra được một ứng dụng cụ thể từ blockchain. Trong số các hệ thống blockchain, mình chọn Solana để nghiên cứu. Mình chọn nó là vì:
Nó cho phép lập trình bằng ngôn ngữ Rust. Mình ưu tiên Rust không chỉ vì lý do cảm tính (yêu thích) mà còn vì lý do thực dụng: Đầu tư vào Rust để sau khi làm về blockchain, mình có thể sử dụng Rust để làm việc cho các mảng khác (web, hệ thống nhúng v.v…). Nếu mình theo Ethereum thì phải học ngôn ngữ Solidity, nhưng Solidity chỉ có giá trị với smart contract. Rời blockchain ra thì chẳng dùng Solidity được vào việc gì khác, phí thời gian học tập.
Solana có tốc độ xử lý giao dịch nhanh. Theo mình, muốn có ứng dụng thực tế thì phải nhanh. Tương tự như bạn vô một website mà tải chậm thì lần sau bạn chẳng muốn ghé lại nữa.
Trong một tháng đấy mình vừa đọc tài liệu kĩ thuật, vừa tập tành viết code. Việc viết code không xuôi chèo mát mái tí nào vì đa số các tài liệu hướng dẫn bị lạc hậu hơn phiên bản phần mềm, không làm theo được. Mò mẫm tới lui thì cũng viết ra được một vài ứng dụng chạy được:
Mình cũng bỏ công nghiên cứu thực sự, đến khi đi ngủ cũng ráng đọc thêm về nó, và đêm qua thì lần mò tới mục này: Developing with Rust – Restriction
Một điểm rất quan trọng là ứng dụng trên chain của Solana không thể dùng std::net, tức là không thể tạo socket và sử dụng các giao thức mạng, trao đổi thông tin qua mạng với các máy khác.
Để thấy việc truyền nhận thông tin qua mạng quan trọng thế nào, lấy ví dụ về hệ thống kiểm soát, điều khiển trang trại của AgriConnect:
Hệ thống có các nút cảm biến. Các thiết bị này đo nhiệt độ, độ ẩm rồi gửi dữ liệu về một máy điều khiển trung tâm. Việc này đòi hỏi có mạng.
Máy điều khiển trung tâm lưu các dữ liệu vào hệ thống database (PostgreSQL). Việc trao đổi với hệ thống database cũng thông qua giao thức mạng.
Người quản lý trang trại muốn xem diễn biến nhiệt độ, độ ẩm thì dùng trình duyệt (trên điện thoại, laptop) truy cập vào website của máy điều khiển trung tâm. Việc tương tác giữa trình duyệt và website cũng tiến hành qua mạng.
Người quản lý trang trại thiết lập lịch tưới trên website. Lịch tưới này cũng được lưu vào database. Các việc này cũng tiến hành qua mạng.
Máy điều khiển trung tâm căn cứ vào số liệu nhiệt độ, độ ẩm thu được, so sánh với lịch tưới đã được cài đặt, sẽ ra lệnh tắt, mở bơm tưới. Tín hiệu điều khiển này được gửi qua mạng đến máy bơm đặt ở trang trại.
Bởi vậy, ứng dụng blockchain, Web3 mà không sử dụng được mạng thì coi như cụt tay. Nói “blockchain, web3 là tương lai” thì nổ quá. Mà hạn chế này cũng không phải của riêng Solana. Có vẻ bản chất của blockchain khiến phải có hạn chế này, vì Ethereum cũng bị như thế.
Bài viết được sự cho phép của tác giả Trần Văn Dem
Khi xây dựng hệ thống backend chúng ta thường xuyên phải làm việc với transaction – đây là một khái niệm rất quen thuộc với các lập trình viên backend. Việc nắm bắt và sử dụng thành thạo các loại này là việc cần thiêt để xây dựng một hệ thống backend tốt.
Tuy nhiên trong nhiều trường hợp database chúng ta sử dụng lại không hỗ trợ transaction hoặc việc insert vào các loại cơ sở dữ liệu quan hệ được xử lý bởi các hệ thống acsync điều này khiến chúng ta phải xử lý các transaction trên logic trong application của mình.
Những hệ thống trước đây tôi xây dựng đều phải xử lý điều này và sau khi tìm được một cách hay ho có thể sử dụng lại thì tôi quết định viết bài chia sẻ cho mọi người.
Tại đây tôi sẽ lưu các sản phẩm khách hàng mua thành công vào một TxnHashMap là implement của một HashMap nhưng áp dụng cho transaction. Kết quả của lệnh in là
interface Txn : Class này đại diện cho một transaction trong hệ thống, đảm bảo các TxnElement được hoạt động. Chứa tất cả thay đổi của TxnElement trong một tracsaction để thực hiện commit hoặc rollback khi cần.
TxnManager : Class quản lý cách transaction của hệ thống hoạt động.
interface TxnElement : Muốn sử dụng được transaction thì cần phải implement lại interface này. Trong ví dụ trên là TxnHashMap.
Tại đây tôi chỉ implement TxnHashMap để sử dụng trên RAM của chương trình trong thực tế mọi người có thể tự impl các class khác nhau để phục vụ cho các mục đích khác nhau. Ví dụ thao tác với 1 key trên redis, gọi hệ thống ngoài,…
Nếu mọi người dùng được cách implement này thì cho mình 1 sao nhé.
Bài viết được sự cho phép của tác giả Lại Đình Cường
Dùng nhiều tên miền cho 1 trang web sẽ hữu ích trong một vài trường hợp và tùy vào nhu cầu của người dùng. Bài viết này mình sẽ hướng dẫn cho các bạn cách trỏ nhiều tên miền chạy chung cho 1 trang web. Việc này khác với chuyện trỏ nhiều tên miền chạy độc lập trên 1 hosting nha mọi người. Đầu tiên thì bạn phải trỏ IP hoặc nameserver về hosting đang sử dụng trước nhé.
Cách dùng nhiều tên miền cho 1 web
Tiếp đến, các bạn đăng nhập vào trong hosting, tùy vào mã nguồn sử dụng mà cách làm có thể hơi khác nhau. Trong bài viết này mình sẽ hướng dẫn cho các bạn cách làm trên hosting cPanel, DirectAdmin và Plesk.
Tạo parked domain (domain alias) cho tên miền chính
Đối với hosting Plesk thì các bạn đăng nhập vào bảng điều khiển và nhấn vào nút + Add Domain Alias trong khu vực các nút chức năng phía trên tên miền để tạo parked domain.
Đối với hosting cPanel thì các bạn đăng nhập vào bảng điều khiển và nhấn vào link Aliases trong khu vực chức năng Domains để tạo parked domain.
Đối với hosting DirectAdmin thì các bạn vào bảng điều khiển và nhấn vào link Domain Pointers trong khu vực Advanced Features để tạo parked domain.
Tiếp theo, các bạn vào file manager của hosting hoặc vào admin dùng trình chỉnh sửa file hoặc dùng FTP client để thay đổi nội dung tập tin wp-config.php của WordPress thành như sau:
Lưu ý: Nếu đã có sẵn dòng define WP_SITEURL và WP_HOME thì các bạn thay đổi lại giá trị, còn nếu chưa có thì các bạn thêm vào nhé.
Cập nhật tập tin .htaccess để tránh lỗi font, css và js
Bạn mở tập tin .htaccess lên và tìm xem có dòng dưới hay chưa, nếu chưa có thì thêm vào trước dòng # BEGIN WordPress:
<IfModule mod_headers.c> <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js)$"> Header set Access-Control-Allow-Origin "*" </FilesMatch></IfModule># BEGIN WordPress
Cập nhật lại canonical url để không bị ảnh hưởng SEO
Bạn thêm đoạn code sau vào tập tin functions.php của giao diện, và cái này chỉ thực hiện đối với bạn nào đang sử dụng plugin Yoast SEO nhé. Nếu bạn đang dùng plugin khác để làm SEO WordPress thì gửi lại bình luận để mình cập nhật cho các bạn:
/** * Update canonical url to main url prevent lost SEO * * @param $canonical * * @return mixed */functionhocwp_theme_custom_wpseo_canonical_filter($canonical){ $canonical = str_replace(home_url(), 'maydothinghiem.com.vn', $canonical); return$canonical;}add_filter('wpseo_canonical', 'hocwp_theme_custom_wpseo_canonical_filter');
Chú ý: Các bạn thay maydothinghiem.com.vn thành tên miền chính các bạn đang dùng nhé.
Tự động thay đổi đường link custom post type
Nếu các bạn đang sử dụng custom post type và có bỏ link tĩnh vào menu thì các bạn có thể sử dụng đoạn code sau:
Như vậy là qua bài viết này mình đã hướng dẫn cho các bạn cách dùng nhiều tên miền cho cùng 1 web. Cụ thể hơn, mình đã hướng dẫn cho các bạn cách tạo parked domain hay còn gọi là domain alias cho hosting với từng ví dụ cụ thể. Hy vọng rằng bài viết này sẽ giúp ích được cho mọi người, hãy để lại bình luận và share bài viết này nếu bạn cảm thấy hữu ích nhé. Chúc bạn thành công.
Với những bạn đang bắt đầu học lập trình hoặc vừa mới đi làm, đôi khi các bạn sẽ bị… bí, không biết code hoặc giải quyết vấn đề như thế nào (Thật ra mình đi làm lâu rồi nhiều khi cũng bị).
Cảm giác … không biết code như thế nào, không biết giải quyết vấn đề ra sao rất là khó chịu. Gặp nhiều bạn sẽ dễ nản, chán code, chán ngành.
Do vậy, hôm nay mình chia sẻ 5 kinh nghiệm hay ho trị bệnh … bí code, các bạn có thể áp dụng thử nhé! Theo kinh nghiệm của mình thì 96.69% các trường hợp đều áp dụng được và có hiệu quả nha!
1. Google vấn đề để xem người khác giải quyết ra sao
Nói thật, 99% những lỗi bạn gặp khi code, người khác đã gặp rồi, nên chỉ cần Google là sẽ tìm ra được cách giải.
Đa phần các bạn mới học code thường chưa biết nhiều keyword, nên không biết Google thế nào cho đúng. Đây là 1 số kinh nghiệm Google của mình:
Đọc message lỗi, copy message lỗi bỏ vào Google, nhớ bỏ tên biến/tên hàm/tên project ra
Ghi rõ ngôn ngữ/công nghệ để search cho dễ (vd “JS remove special character”, “Python connect MongoDB”)
Kết quả thường có trên Stackoverflow, hoặc 1 số thread Github
Bạn cũng đừng ngại hay nghĩ mình code dở vì phải Google cách giải 1 bài nào đó. Bản thân mấy ông senior đi làm lâu lâu vẫn Google xem cách làm nào tối ưu nhất, ít code nhất; hoặc quên code phải Google kiếm code để copy vào ấy.
Mấy ông senior/team lead vẫn Google thường xuyên nha =))
2. Tách thành nhiều vấn đề nhỏ hơn cho dễ xử lý
Với các bạn bắt đầu làm đồ án, mới đi làm, các bạn sẽ bị khó khăn khi muốn làm 1 chức năng. Vì chức năng đó lớn quá, chưa có kinh nghiệm các bạn không biết bắt đầu từ đâu cả.
Cách giải quyết cũng khá đơn giản, chỉ cần tách vấn đề ra thành nhiều vấn đề nhỏ hơn là được. Ví dụ bạn muốn làm chức năng đăng nhập:
Đăng nhập phải có form để điền username, password. Vậy bạn phải design và code cái form cho người dùng điền 2 cái đó vào.
Đăng nhập phải check username, password đã có trong database chưa. Nếu chưa có thì sao. Bạn phải viết code back-end hoặc SQL để check cái này.
Làm sao để back-end nhận username, password nhận được từ phía người dùng? Phải viết code trong controller để đọc dữ liệu. Sau đó đưa chúng vào hàm check mật khẩu phía trên
Sau khi kiểm tra đúng mật khẩu thì làm gì? Code chức năng cần làm khi đúng mật khẩu (Login, đưa user vào session v…v)
Đấy, khi tách vấn đề thành nhiều vấn đề nhỏ hơn, bạn có thể dễ dàng code từng thứ rồi ghép chúng lại với nhau. Bản thân mình cũng hay dùng to-do list như hình dưới để code, code xong check là được.
Mình cũng hay tách chức năng lớn thành nhiều task nhỏ cho dễ xử lý (chữ hơi xấu hihi)
3. Thử giải quyết vấn đề dễ hơn trước
Nhiều khi, bạn gặp một vấn đề không quá lớn, nhưng lại hơi khó, không biết cách giải quyết ra sao.
Trong trường hợp này, hãy thử giải quyết vấn đề dễ hơn trước. Ví dụ, bài tập yêu cầu bạn tính tuổi trung bình của sinh viên trong trường.
Tuy nhiên, dữ liệu chỉ cho số báo danh, tên họ, ngày tháng năm sinh. Bạn có thể thử giải bài toán dễ hơn:
Giả sử ta có tuổi của toàn bộ sinh viên trong trường
Tuổi trung bình sẽ bằng tổng số tuổi chia cho số sinh viên
Vậy làm sao để có tuổi của sinh viên? Lấy năm hiện tại trừ cho năm sinh là ra.
Làm sao để có năm sinh? Dùng hàm nào đó để lấy số năm từ ngày tháng năm sinh trong dữ liệu là được.
Ta có thể suy ngược ra cách giải: Lấy năm hiện tại trừ đi năm sinh của từng sinh viên để có tuổi, sao đó cộng toàn bộ chia cho số sinh viên.
Các bạn thấy không? Chỉ cần thử giải bản dễ hơn, các bạn sẽ dần dần mò ra được cách giải thôi!
4. Đọc lại document, hỏi ý kiến đồng nghiệp
Đi làm, có lúc các bạn sẽ phải dùng framework do công ty/đối tác tự phát triển, mò Google không ra. Hoặc công ty có chuẩn/coding standard gì đó, bạn không biết code theo ra sao.
Lúc này, hãy chịu khó đọc lại kĩ document, coding guideline, code example để xem họ hướng dẫn code ra sao, dùng những hàm nào.
Nếu xui hơn … không có cả document hay unit test để đọc (vì team bị dí quá làm gì có thời gian viết), bạn có thể tranh thủ hỏi sếp, hỏi đồng nghiệp. Do họ đã có kinh nghiệm làm việc với dự án, biết những cách nên làm bạn sẽ đỡ tốn công mày mò nhiều.
Nhớ tìm hiểu kĩ trước khi hỏi, gom hết lại hỏi 1 lượt, chứ đừng hỏi lắt nhắt ảnh hưởng công việc người ta nhé!
Thà chai mặt hỏi đồng nghiệp, còn hơn mò mò code lung tung hỏng code nhé!
5. Đi uống, đi dạo đi ngủ (1 mình)
Trong khi làm việc, hẳn bạn đã từng trải qua cảm giác code hoài không được, chạy bị lỗi không biết tại sao, càng ngồi lâu càng bực mình mà không giải quyết được vấn đề.
Lúc này, cách hay nhất là bạn nên … đứng dậy, gác vấn đề qua một bên. Sau đó đi rót nước uống, làm một cốc cà phê, hoặc đi dạo vòng vòng trong công ty rồi quay lại.
Lúc này, bộ não của bạn sẽ được refresh lại, đôi khi bạn sẽ tự … bật ra cách giải, nhìn ra bạn đã sai chỗ nào! Hoặc có thể đi giải quyết vấn đề khác, sau đó đi ngủ 1 giấc, sáng hôm sau quay lại bỗng dưng não lại nghĩ ra cách giải quyết vấn đề cũ.
Nghe hơi vô lý đúng không nào? Không tin thì các bạn cứ thử xem sao nhé, nếu không hiệu quả cứ lên đây đòi tiền thằng Code Dạo.
Dắt gấu chó, lộn, dắt gấu và chó đi dạo sẽ giúp bạn refresh đầu óc, giải quyết vấn đề nha!
Tạm kết
Đấy, trong bài này, mình đã chia sẻ với các bạn những kinh nghiệm hay ho. Bản thân mình thấy cách 1 và cách 5 là hiệu quả nhất! Còn bạn thấy cách nào hay ho thì cứ chia sẻ trong mục comment nhé!
Bài viết được sự cho phép của tác giả Trần Hữu Cương
Khi lập trình với Java chắc hẳn bạn đã bắt gặp khái niệm serialize nhất là khi đọc ghi object ra file, mapping với cơ sở dữ liệu…
Java Serializable là gì?
Serialization trong Java là cơ chế chuyển đổi trạng thái của một đối tượng (giá trị các thuộc tính trong object) thành một chuỗi byte sao cho chuỗi byte này có thể chuyển đổi ngược lại thành một đối tượng.
Quá trình chuyển đổi chuỗi byte thành đối tượng gọi là deserialization.
Một object có thể serializable (có thể thực hiện Serialization) nếu class của nó thực hiện implements interface java.io.Serializable
Trong Java, khi trao đổi dữ liệu giữa các thành phần khác nhau (giữa các module cùng viết bằng Java) thì dữ liệu được thể hiện dưới dạng byte chứ không phải là đối tượng. Do đó ta cần có một cơ chế để hiểu các đối tượng được gửi và nhận.
Quá trình serilization hoàn toàn độc lập với platform (không phụ thuộc vào hệ điều hành) nên việc chuyển đổi giữa byte và object giữa các module được đảm bảo.
Ví dụ mình có 2 module, một module thực hiện chuyển đối tượng Customer thành byte và ghi ra file .Một module thực hiện đọc byte từ file và chuyển ngược lại thành đối tượng Customer.
(Trong thực tế thì 2 module có thể trao đổi qua database, network chứ không phải qua file)
Method readObject() sẽ chuyển byte thành đối tượng.
Vì mình ghi ra file dạng đối tượng Customer nên sau khi readObject() mình sẽ ép thành kiểu đối tượng Customer (Nếu bạn khi ra file dạng Map, List thì lúc đọc các bạn phải ép đúng kiểu tương ứng.
Kết quả:
Customer after deserialization:Customer [id=1, name=kai, address=null]
Trường address là transient nên sau khi deserialization sẽ không có dữ liệu.
Một số lưu ý về Serialization trong Java
Nếu class cha implement Serializable thì các class con không cần thực hiện implement Serializablenữa.
Các thuộc tính static và transient sẽ không được serialization.
Hàm khởi tạo (constructor) sẽ không được gọi khi một đối tượng được deserialization.
Khi thực hiện serialization một đối tượng thì tất cả các thuộc tính bên trong nó đều phải là serializable (áp dụng với các thuộc tính có kiểu đối tượng, ví dụ object Person có thuộc tính Address thì thuộc tính Address đó cũng phải implement Serializable nếu không sẽ bị lỗi java.io.NotSerializableException khi thực hiện serialization đối tượng person).
Tiền phụ cấp chi trả cho người lao động được xác định cho các mục đích phụ cấp khác nhau. Do đó một số phụ cấp được tính vào đóng BHXH, tính Thuế TNCN. Các bạn lưu ý là trong bài học này, khi mình nhắc đến các khoản phụ cấp nào phải chịu Thuế TNCN và không chịu thuế TNCN của người lao động là khoản được chi trả bằng tiền vào lương. Tuy nhiên, công ty chỉ thu thuế TNCN khi tổng thu nhập của họ đạt ngưỡng chịu thuế, còn dưới thì mặc nhiên là không thu bạn nhé!
Chi tiết các khoản lương, thưởng, phụ cấp theo lương, khoản phúc lợi hỗ trợ khác mình có trích dẫn bên dưới để các bạn tiện tham khảo. Mình chỉ làm rõ thêm một số mục theo mình là quan trọng và bạn cần nắm thêm như sau:
Tiền ăn ca có đóng BHXH và Thuế TNCN không?
Về thuế TNCN
– Công ty tự tổ chức nấu ăn, mua suất ăn hoặc cấp phiếu ăn cho người lao động => Thì không tính vào thu nhập chịu thuế TNCN.
– Công ty không tổ chức bữa ăn giữa ca, ăn trưa mà chi tiền cho người lao động theo mức chi phù hợp với hướng dẫn của Bộ LĐTBXH tối đa cho khoản hỗ trợ ăn ca này là 730.000 đồng/người/tháng thì không tính thuế TNCN. Nếu chi vượt thì sẽ tính thuế trên phần vượt.
Căn cứ pháp lý: Điều 2 Thông tư số 111/2013/TT-BTC ngày 15/08/2013 của Bộ tài chính; Điều 22 Thông tư số 26/2016/TT-BLĐTBXH ngày 01/09/2016 của Bộ LĐTBXH.
Như trong bài học trước mình đã trích dẫn khá chi tiết, thì tiền hỗ trợ ăn ca sẽ không đóng BHXH. Nên một số công ty thường chia thu nhập thành khoản hỗ trợ ăn ca này khá cao để giảm mức đóng BHXH.
Mọi người cần lưu ý tính hợp lý của khoản phụ cấp này và phải có thể hiện trong Hợp đồng lao đồng, quy chế lương thưởng nhé! Đồng thời phải cân đối với chính sách thu thuế TNCN, chi phí hợp lý của doanh nghiệp.
Hỗ trợ đi lại, nhà ở, điện thoại có giới hạn là bao nhiêu?
Các khoản hỗ trợ đi lại, nhà ở, điện thoại là những khoản không phải đóng BHXH nhưng phải đóng thuế TNCN. Nhiều công ty đang lạm dụng điều này để giảm mức đóng BHXH của người lao động đến mức tối đa.
Và các khoản hỗ trợ đi lại, nhà ở, điện thoại…này phải đóng Thuế TNCN. Các bạn lưu ý ở đây là mình xét các khoản này được trả bằng tiền vào lương chứ không phải trả qua công ty thứ ba hay là công ty thực hiện thuê nhà, tự trả cước điện thoại cho nhân viên.
Với quy định của BHXH thì hiện tại chưa có mức trần tối đa cho khoản hỗ trợ đi lại, nhà ở, điện thoại này. Tuy nhiên, công ty cần cân đối mức hợp lý; Và cần có quy định cụ thể mức hỗ trợ này với từng chức danh trong quy chế lương thưởng công ty chứ không phải muốn phân bỗ bao nhiêu cũng được trên bảng lương thì sẽ bị coi là lách luật.
Tiền lương tháng đóng BHXH bắt buộc không bao gồm các khoản chế độ và phúc lợi khác, như tiền thưởng theo quy định tại Điều 103 Bộ luật lao động, cho nên khoản tiền thưởng tháng 13, thưởng Tết sẽ không đóng BHXH. Được quy định tại Điều 89 Luật BHXH 2014, Điều 17 Nghị định 115/2015/NĐ-CP và Điều 30 Thông tư 59/2015/TT-BLĐTBXH.
Theo Khoản 2 Điều 2 Thông tư 111/2013/TT-BTC quy định thu nhập của người lao động (NLĐ) từ tiền lương, tiền công là khoản thu nhập chịu thuế thu nhập cá nhân. Trong đó bao gồm các khoản thưởng bằng tiền hoặc không bằng tiền dưới mọi hình thức. Do đó, khoản thu nhập của NLĐ từ thưởng Tết là khoản thu nhập chịu thuế TNCN.
Khoản thưởng KPI có đóng BHXH và Thuế TNCN không?
Trong bài học này mình chỉ xem xét ở mức độ đơn giản để trả lời câu hỏi Khoản lương, thưởng KPI có đóng BHXH và Thuế TNCN không , chi tiết hơn mình sẽ có một bài phân tích sâu hơn bạn nhé! và tiền thưởng KPI có thể được trả hàng tháng hoặc quý tùy theo quy định của mỗi công ty.
Theo Điều 3 Thông tư 10/2020/TT-BLĐTBXH thì các khoản bổ sung xác định được mức tiền cụ thể cùng với mức lương thỏa thuận trong hợp đồng lao động và trả thường xuyên trong mỗi kỳ trả lương sẽ phải đóng BHXH. Tuy nhiên, khoản thưởng KPI lại không cố định và phụ thuộc vào kết quả hoàn thành công việc nên sẽ không phải đóng BHXH.
Lưu ý: Thưởng KPI phải có thang bảng đánh giá đi kèm, có tiêu chí và các chỉ số đo lường rõ ràng và số tiền KPI háng tháng không cố định bạn nhé!
Theo Khoản 2 Điều 3 Luật Thuế thu nhập cá nhân 2007, sửa đổi năm 2012 thì tiền lương, tiền công và các khoản có tính chất tiền lương, tiền công và các khoản phụ cấp, trợ cấp được tính là thu nhập chịu thuế TNCN của người lao động.
Phần lương theo KPI (hoặc thưởng KPI) được tính và chi trả theo hiệu quả công việc; Và không thuộc các khoản trợ cấp, phụ cấp được miễn thuế TNCN. Do đó, tiền lương KPI cũng sẽ được cộng vào tổng thu nhập chịu thuế để tính thuế .
Trên đây mình đã cùng nhau tìm hiểu một số khoản tiền lương, phụ cấp nào phải đóng BHXH và thuế TNCN hay không. Hy vọng các bạn đã có cái nhìn bao quát hơn về vấn đề này. Nếu bạn có bất kỳ thắc mắc nào, vui lòng để lại comment bên dưới. Mình sẽ trả lời cho các bạn trong thời gian sớm nhất.
Tuyển Dụng Nhân Tài IT Cùng TopDev Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products
Omnichannel là thuật ngữ khá quen thuộc trong lĩnh vực kinh doanh Online trên thế giới. Tuy nhiên, không phải ai cũng biết Omnichannel là gì? Lợi ích của Omnichannel mang đến cho doanh nghiệp ra sao? Làm sao để áp dụng Omnichannel hiệu quả? Cùng tìm hiểu về Giải pháp quản lý bán hàng đa kênh – Omnichannel.
——————————
“Kinh doanh online đa kênh Omnichannel’ giúp gì cho bạn?
Tìm hiểu Omnichannel là gì và lợi ích khi sử dụng
OmniChannel được biết đến là một mô hình kinh doanh bán lẻ tiềm năng, thu hút nhiều nhà kinh doanh/ doanh nghiệp đẩy mạnh triển khai trong những năm gần đây.
Omnichannel là giải pháp bán hàng đa kênh, quản lý tập trung các kênh bán hàng online và offline: website, sàn TMĐT, mạng xã hội, cửa hàng vào cùng một nền tảng. Ngoài hoạt động bán hàng truyền thống tại cửa hàng, kinh doanh online trên đa kênh trở thành một giải pháp tất yếu giúp nhà bán lẻ kinh doanh đa kênh hiệu quả, tối ưu và tăng trải nghiệm cho khách hàng, từ đó đem lại nguồn doanh thu, lợi nhuận tối ưu.
Haravan – Giải pháp tăng trưởng kinh doanh online đa kênh cho mọi quy mô
Giải pháp Haravan quản lý bán hàng đa kênh cho mọi nhà kinh doanh
Được thành lập từ năm 2014, Haravan là công ty công nghệ hàng đầu Việt Nam trong lĩnh vực cung cấp các giải pháp bán lẻ Omnichannel, Thương mại điện tử và Engagement Marketing cho doanh nghiệp và người kinh doanh tại Việt Nam.
Với nền tảng công nghệ tiên phong hỗ trợ nhà bán lẻ tăng trưởng và kinh doanh online dễ dàng, Haravan giúp tối đa hiệu quả kinh doanh, đồng thời tạo trải nghiệm cá nhân hóa cho khách hàng ở đa kênh Online và Offline.
Quản lý bán hàng đa kênh hiệu quả bằng giải pháp công nghệ Haravan
Ngoài hệ thống quản lý bán hàng trên đa kênh tinh gọn, Haravan còn mang đến cho các nhà bán lẻ/ doanh nghiệp các giải pháp bán hàng và marketing hiệu quả với đa dạng tính năng, tiện ích có sẵn trên hệ thống.
Giải pháp bán hàng đa kênh tin dùng bởi nhiều thương hiệu
Nền tảng Haravan gồm trang quản trị tinh gọn, dễ sử dụng giúp nhà kinh doanh có thể vận hành và theo dõi mọi hoạt động bán hàng, đồng bộ dữ liệu trên đa kênh:
☑ Website Thương mại điện tử chuyên nghiệp
☑ Bán hàng trên mạng xã hội: Facebook, Instagram, Livestream, Zalo
☑ Kết nối bán hàng trên sàn Thương mại điện tử: Shopee, Lazada, Tiki, TikTok Shop
☑ Quản lý bán hàng trực tiếp tại cửa hàng POS
☑ Giải pháp quảng cáo trên Google, Facebook và TikTok
Cùng các tiện ích và tính năng hỗ trợ nhà bán hàng theo dõi hiệu suất kinh doanh, và tối ưu, tăng trải nghiệm về giao hàng, thanh toán:
☑ Báo cáo, thống kê hiệu quả bán hàng toàn diện
☑ Quản lý thu chi, công nợ nhà cung cấp
☑ Kết nối sẵn các nhà vận chuyển và cổng thanh toán online phổ biến
Haravan nhận giải thưởng Best Solution Awards 2021
Năm 2021, Haravan vinh dự nhận giải thưởng Best Solution Awards 2021 với giải pháp Haravan Omnichannel. Đây là cột mốc đánh dấu cho sự thành công của Haravan cũng như sự công nhận của các chuyên gia trong ngành và sự tin tưởng của các doanh nghiệp bán lẻ với các giải pháp kinh doanh online đa kênh của Haravan.
Đến nay, Haravan đã được hơn 50.000 người kinh doanh tin dùng làm nền tảng để tăng trưởng trong thời đại kinh tế số, trong đó có các thương hiệu nổi bật trong nước và quốc tế như: Nestle, Dell, L’Oréal, AEON, Maison, Vinamilk, Thiên Long, Biti’s, The Face Shop, Juno, The Coffee House,… Haravan cũng là đối tác công nghệ chiến lược của Google và Meta (Facebook) trong việc cung cấp giải pháp công nghệ kinh doanh & Marketing tại Việt Nam.
Apache HTTP Server, hay thường được gọi là Apache là phần mềm web server được sử dụng nhiều nhất trên thế giới. Ban đầu được dựa trên NCSA HTTPd server. Apache bắt đầu được phát triển vào khoảng đầu năm 1995 khi NCSA bị đình trệ và đóng 1 vai trò quan trọng trong sự phát triển ban đầu của World Wide Web, nhanh chóng vượt qua NCSA HTTPd như HTTP server ưu thế và trở nên phổ biến nhất kể từ tháng 4/1996. Vào năm 2009, nó trở thành phần mềm web server đầu tiên phục vụ hơn 100 triệu website.
Apache được phát triển và duy trì bởi 1 cộng đồng mở của các nhà phát triển dưới sự bảo trợ của Apache Software Foundation. Thường được sử dụng trên hệ thống giống Unix (thường là Linux), ngoài ra còn hỗ trợ rộng rãi các hệ điều hành khác bao gồm eComStation, Microsoft Windows, NetWare, OpenVMS, OS/2 và TPF. Apache là miễn phí và là phần mềm mã nguồn mở.
Vào tháng 11/2015, Apache được đánh giá phục vụ 50% của tất cả các website đang hoạt động và 35% top server trên tất cả các lĩnh vực.
2. Nginx là gì?
Nginx (phát âm là “engine x”) là 1 web server tập trung mạnh mẽ vào khả năng xử lý đồng thời cao, hiệu suất và sử dụng ít bộ nhớ. Nó cũng có thể hoạt động như một reverse proxy server cho các giao thức HTTP, HTTPS, SMTP, POP3 và IMAP, cũng như cân bằng tải (load balancer) và HTTP cache.
Được tạo ra bởi Igor Sysoev năm 2002, Nginx chạy trên Unix, Linux, các biến thể BSD, Mac OS X, Solaris, AIX, HP-UX và Microsoft Windows. Nginx là miễn phí và là phần mềm mã nguồn mở.
Apache web server là server phổ biến nhất trên Internet từ năm 1996.
Nginx được Igor Sysoev tạo ra năm 2002 nhằm giải quyết nhu cầu cần phục vụ 1 số lượng lớn các request đồng thời và vấn đề C10K (tức là hệ thống cần xử lý được khi có 10.000 khách hàng sử dụng cùng 1 thời điểm).
2. Kiến trúc
Apache hoạt động dựa trên kiến trúchướng quy trình. Nginx hoạt động dựa trên kiến trúc hướng sự kiện.
Apache cung cấp một loạt các module đa xử lý (MPMs) để quy định cách mà nó phục vụ các request của người dùng. Các loại MPMs mà chúng ta có thể lựa chọn gồm:
Prefork: Nếu sử dụng MPM này thì mỗi request đến sẽ được một process xử lý, điều này sẽ tốn nhiều RAM nếu như có nhiều request đến (sẽ có nhiều process được tạo ra), tuy nhiên ưu điểm là nếu một process có vấn đề thì không ảnh hưởng đến các process khác. Số lượng process được tạo ra chúng ta có thể quy định trong file cấu hình của apache.
Worker: Nếu sử dụng MPM này thì mỗi request đến sẽ được xử lý bởi một thread thay vì một process (các thread có thể share memory chung với nhau), do đó sẽ tiết kiệm RAM nhiều hơn. Số lượng thread và process sinh ra, số thread trong một process, … chúng ta có thể quy định trong file cấu hình. Nhược điểm của MPM này là nếu như một thread có vấn đề sẽ ảnh hưởng đến các thread khác trong cùng process, hơn nữa nếu cấu hình keep-alive thì tất cả các process/thread đều được giữ lại để phục vụ cho đến khi hết thời gian keep-alive.
Event: Tương tự như Worker, có nghĩa là cũng sử dụng thread để phục vụ các request thay vì dùng process, tuy nhiên với Event MPM, thread riêng biệt sẽ dùng để phục vụ request và được giải phóng ngay sau khi xử lý xong, không phục thuộc vào trạng thái kết nối HTTP. Điều này đã được đánh dấu ổn định với việc phát hành của Apache 2.4.
Tuy nhiên, việc xử lý các truy vấn từ client đến server bằng các thread, mỗi truy vấn client sẽ được server xử lý bằng một thread riêng biệt cho đến khi nó hoàn thành nhiệm vụ sẽ làm ổ cứng trên server sẽ mất nhiều thời gian hơn để giải phóng các thread đã hoàn thành nhiệm vụ, và việc tạo ra nhiều thread cũng sẽ làm server tiêu hao rất nhiều tài nguyên (CPU, RAM).
Do ra đời sau Apache, Nginx đã khắc phục được hạn chế trên của Apache do sử dụng các thuật toán xử lý không đồng bộ, đơn luồng và hướng sự kiện.
Hướng sự kiện có nghĩa rằng các thông báo hoặc tín hiệu được sử dụng để đánh dấu sự khởi đầu hay kết thúc của 1 process. Như vậy, các tài nguyên có thể được sử dụng bởi các process khác cho đến khi 1 process khởi tạo sự kiện được kích hoạt và tài nguyên có thể được phân bố và phát hành tự động. Điều này dẫn đến việc sử dụng tối ưu hóa bộ nhớ và CPU.
Không đồng bộ có nghĩa là các thread có thể được xử lý đồng thời, giúp tăng cường việc chia sẻ tài nguyên mà không bị chuyên dụng hoặc bị chặn.
Đơn luồng có nghĩa là nhiều client có thể được xử lý bởi 1 worker process duy nhất với các tài nguyên không bị chặn.
Nginx sinh ra các worker process, mỗi worker process có thể xử lý hàng ngàn kết nối bằng cách thực hiện một cơ chế lặp nhanh chóng để liên tục kiểm tra và xử lý các sự kiện.
Mỗi kết nối được xử lý bởi worker được đặt trong sự kiện vòng lặp. Bên trong vòng lặp, các sự kiện được xử lý đồng bộ, cho phép công việc được xử lý một cách không chờ đợi. Khi kết nối đóng lại thì worker process bị xóa khỏi vòng lặp.
Với phương thức xử lý kết nối này cho phép Nginx tiến đến quy mô vô cùng xa chỉ với nguồn lực hạn chế. Vì máy chủ là đơn luồng và không tạo ra process hoặc thread mới cho mỗi request mới nên tương đối là hiệu quả, giúp giảm thiểu tài nguyên cần sử dụng.
Các Apache server có thể xử lý nội dung tĩnh bằng cách sử dụng các phương pháp dựa trên file thông thường của nó. Hiệu suất của các hoạt động này chủ yếu phụ thuộc vào các module đa xử lý MPMs đã được trình bày ở trên.
Apache cũng có thể xử lý nội dung động bằng cách nhúng một bộ xử lý của ngôn ngữ trong câu hỏi vào trường hợp worker của nó. Điều này cho phép nó thực hiện nội dung động bên trong các web server của mình mà không cần phải dựa vào các thành phần bên ngoài. Các bộ vi xử lý động có thể được kích hoạt thông qua việc sử dụng các module có thể tự động load được.
Nginx không có khả năng xử lý các nội dung động mà chỉ phục vụ các nội dung tĩnh.
Để xử lý các request PHP và các request khác đối với nội dung động, Nginx phải gọi đến một bộ vi xử lý bên ngoài để thực thi và đợi khi kết quả được gửi trở lại, sau đó sẽ chuyển các kết quả này đến client. Đối với người quản trị, điều này có nghĩa là cần phải cấu hình giữa Nginx và bộ vi xử lý dựa trên những giao thức mà Nginx có thể kết nối được, bao gồm: http, FastCGI, SCGI, uWSGI, memcache. Điều này có thể là hơi phức tạp.
4. Cấu hình
Các file .htaccess được sử dụng trong việc cấu hình máy chủ Apache. Công dụng của file .htacess này bao gồm: rewrite URL, hạn chế truy cập, ủy quyền và xác thực, thậm chí là chính sách bộ nhớ đệm.
Ưu điểm:
Thực thi ngay lập tức: Vì htaccess được đọc trên mọi yêu cầu, những thay đổi được thực hiện trong những tập tin này có hiệu lực ngay lập tức, trái ngược với các tập tin cấu hình chính mà đòi hỏi các máy chủ được khởi động lại thì các thiết lập mới có hiệu lực.
Hỗ trợ người dùng không có đặc quyền: cho phép người dùng cá nhân có khả năng thay đổi cấu hình trang web của họ trong khi các tập tin cấu hình máy chủ chính không cần phải được thay đổi.
Nhược điểm:
Giảm hiệu suất: cụ thể, khi được cấu hình để sử dụng .htaccess, thì Apache sẽ tìm kiếm tất cả những folder có chứa .htaccess để thực thi, và nó sẽ thực thi tất cả những file .htaccess tìm được. Do vậy, sẽ làm website của bạn trở nên ì ạch một cách không cần thiết.
Bảo mật: việc cho phép người dùng cá nhân thay đổi cấu hình của một máy chủ có thể gây ra vấn đề liên quan đến bảo mật nếu không được thiết lập đúng cách.
Nginx không có file cấu hình .htaccess giống như ở Apache. Điều đó mang lại sự kém linh hoạt hơn nhưng cũng có lợi thế riêng của nó.
Cải tiến đáng chú ý nhất của .htaccess cũng như cấu hình phân cấp thư mục là giúp tăng hiệu suất. Tuy nhiên, việc tìm kiếm các thư mục có chứa .htaccess để thực thi nhiều khi khiến website của bạn trở nên ì ạch hơn. Bằng cách không cho phép ghi đè thư mục, Nginx có thể xử lý các request nhanh hơn bởi việc tìm kiếm trong 1 thư mục đơn và file đọc cho mỗi request.
Một lợi thế khác là về vấn đề bảo mật. Cấu hình phân cấp thư mục cho phép người dùng cá nhân thay đổi cấu hình có thể gây ra các vấn đề bảo mật. Nginx đảm bảo các quản trị viên duy trì quyển kiểm soát toàn bộ web server để ngăn ngừa các sai lầm bảo mật có thể xảy ra.
5. File và giải thích dựa trên URI
Do Apache được tạo ra chỉ để làm web server. Nó hoạt động chủ yếu với thư mục file hệ thống.
Nginx được tạo ra để làm cả web server và proxy server. Do cấu trúc cần được đáp ứng cho cả 2 vai trò này nên nó hoạt động chủ yếu với các URI, chuyển đổi các file hệ thống khi cần thiết.
Nginx không cung cấp cơ chế để xác định cấu hình cho 1 thư mục file hệ thống mà thay vào đó là phân tích URI của chính nó.
Nginx không kiểm tra file hệ thống cho đến khi nó đã sẵn sàng để phục vụ các request, điều này giải thích lý do tại sao nó không thực hiện một hình thức của các file .htaccess giống với Apache.
6. Module
Hệ thống module của Apache cho phép bạn tự động load hoặc không load module để áp ứng nhu cầu của bạn trong quá trình chạy các server. Phần lõi Apache luôn hiện diện, trong khi các module có thể bật hoặc tắt, thêm hoặc loại bỏ các chức năng bổ sung và gắn vào server chính.
Module của Apache là không giới hạn để thực hiện các nội dung động. Hơn nữa, chúng có thể được sử dụng để rewrite URL, chứng thực client, tăng độ bền cho máy chủ, đăng nhập, bộ nhớ đệm, nén, proxy, hạn chế tốc độ và mã hóa.
Nginx cũng thực hiện 1 hệ thống module nhưng lại khá là khác với Apache. Trong Nginx, module không load được, vì vậy chúng phải được chọn và biên dịch vào phần mềm lõi. Đối với nhiều người thì điều này không hề linh hoạt 1 chút nào. Tuy nhiên nó cũng có thể hữu ích với trường hợp bạn chỉ muốn thêm những chức năng bạn muốn vào server mà thôi.
7. Hỗ trợ, tương thích, tài liệu
Bởi vì Apache đã được phát triển từ rất lâu cộng với các tính năng mạnh mẽ của nó mà nguồn tài liệu của nó thực sự lớn, được hỗ trợ và tương thích với nhiều dự án, nhiều công cụ khác. Ngoài ra, các quản trị viên dường như cũng có nhiều sự quen thuộc với Apache hơn là các web server khác.
Nginx cũng đang nhận được nhiều sự hỗ trợ cũng như được sử dụng rộng rãi do sự hiệu quả mà nó mang lại, tuy nhiên, nó vẫn cần bắt kịp Apache ở 1 số lĩnh vực chủ chốt. Về tài liệu, trước đây, thật khó khăn để tìm tài liệu tiếng Anh về Nginx do nó được phát triển ở Nga. Ngày nay thì nguồn tài liệu đã được bổ sung đầy đủ và phong phú hơn.
III. Kết hợp Nginx và Apache
Rõ ràng, cả Apache và Nginx đều có những ưu và nhược điểm khác nhau, tùy vào nhu cầu sử dụng mà ta có thể lựa chọn web server nào cho phù hợp. Tuy nhiên, ta hoàn toàn có thể tận dụng thế mạnh của cả Apache và Nginx bằng cách kết hợp chúng với nhau.
Apache tốt hơn Nginx trong việc phục vụ các trang web động, nhưng Nginx lại tốt hơn Apache trong việc phục vụ các trang web tĩnh. Do đó, để tận dụng ưu thế của cả 2 web server này, khái niệm reverse proxy đã ra đời.
Ở đây, Nginx được sử dụng như 1 reverse proxy của Apache. Đối với nội dung tĩnh là lợi thế của Nginx, các file sẽ được Nginx phục vụ một cách nhanh chóng và trực tiếp cho client. Còn đối với nội dung động là lợi thế của Apache, Nginx sẽ chuyển cho Apache thực hiện sau đó trả kết quả về cho Nginx, rồi Nginx trả kết quả đó lại cho client. Nói 1 cách đơn giản hơn là dùng Nginx để xử lý tập tin tĩnh (CSS, JS, HTML, …) và dùng Apache xử lý các tập tin động (PHP,…).
Do bản thân Nginx rất đa nhiệm, nên việc kết hợp với Apache không hề gây ra ảnh hưởng tiêu cực nào, mà còn phát huy tối đa lợi thế của cả 2 web server này, giúp tiết kiệm tài nguyên và làm tăng tốc độ tải cho website. Hơn nữa, bằng việc giảm bớt các yêu cầu gửi đến Apache đòi xử lý sẽ làm giảm bớt sự tắc nghẽn khi các process hoặc thread của Apache bị chiếm đóng. Ngoài ra, bạn cũng có thể thêm các backend server nếu cần thiết để tăng hiệu suất và tăng khả năng phục hồi cho cấu hình.
Hy vọng bài viết này sẽ giúp bạn hiểu rõ hơn về Nginx và Apache, biết được những ưu nhược điểm của cả 2 để từ đó chọn được web server phù hợp với trang web của mình. Đừng quên truy cập TopDev để cập nhật các kiến thức liên quan đến ngành IT và việc làm Apache mới nhất bạn nhé!.
Bài viết được sự cho phép của tác giả Phạm Minh Khoa
CI là gì?
CI là Continuous Integration. Nó là phương pháp phát triển phần mềm yêu cầu các thành viên của team tích hợp công việc của họ thường xuyên, mỗi ngày ít nhất một lần. Mỗi tích hợp được “build” tự động (bao gồm cả test) nhằm phát hiện lỗi nhanh nhất có thể.
Cả team nhận thấy rằng cách tiếp cận này giảm thiểu vấn đề tích hợp và cho phép phát triển phần mềm nhanh hơn.
Các bước trong một kịch bản CI thường như sau:
Đầu tiên, developer commit code lên repo.
CI server giám sát repo và kiểm tra xem liệu có thay đổi nào trên repo hay không (liên tục, chẳng hạn mỗi phút 1 lần)
Ngay khi commit xảy ra, CI server phát hiện repo có thay đổi, nên nó nhận code mới nhất từ repo và sau đó build, chạy unit và integration test
CI server sẽ sinh ra các feedback và gửi đến các member của project
CI server tiếp tục chờ thay đổi ở repo
Mỗi lần developer làm xong task, họ phải chạy một private build (tức là chạy phần mềm trên local trước), check choác cẩn thận và commit code lên repo khi đã thấy ổn. Bước này xảy ra thường xuyên và ở bất kỳ thời điểm nào trong ngày. Việc build tích hợp sẽ không xảy ra khi những thay đổi này chưa ảnh hưởng đến repo (kiểu như bạn commit mà chưa được merge vậy).
Một trong những tuyên ngôn của CI là “Build Software at Every Change”. Mục đích là để tránh những câu kiểu như “Ớ, phần này chạy trên máy em bình thường mà”. Vấn đề sẽ được tìm ra sớm bằng cách build thường xuyên, và để CI hoạt động hiệu quả trong project, tốt nhất là developer phải commit code thường xuyên hơn. Đợi hơn một ngày để commit code lên repo có thể khiến việc tích hợp tốn thời gian và code mình dùng có thể không phải là code mới nhất.
Giảm thiểu rủi ro nhờ việc phát hiện lỗi và fix sớm, tăng chất lượng phần mềm nhờ việc tự động test và inspect (đây cũng là một trong những lợi ích của CI, code được inspect tự động dựa theo config đã cài đặt, đảm bảo coding style, chẳng hạn một function chỉ được dài không quá 10 dòng code …)
Giảm thiểu những quy trình thủ công lặp đi lặp lại (build css, js, migrate, test…), thay vì đó là build tự động, chạy test tự động
Sinh ra phần mềm có thể deploy ở bất kì thời gian, địa điểm
CD là gì?
Trong khi Continuous Integration là quy trình để build và test tự động, thì Continuous Delivery (tạm dịch là chuyển giao liên tục) lại nâng cao hơn một chút, bằng cách triển khai tất cả thay đổi về code (đã được build và test) đến môi trường testing hoặc staging.
Continuous Delivery cho phép developer tự động hóa phần testing bên cạnh việc sử dụng unit test, kiểm tra phần mềm qua nhiều thước đo trước khi triển khai cho khách hàng (production). Những bài test này bao gồm UI testing, load testing, integration testing, API testing… Nó tự động hoàn toàn quy trình release phần mềm.
Continuous Delivery được thực hiện bằng cách sử dụng Deployment Pipeline.
Deployment Pipeline chia quy trình chuyển giao phần mềm thành các giai đoạn. Mỗi giai đoạn có mục tiêu xác minh chất lượng của các tính năng mới từ một góc độ khác nhau để kiểm định chức năng và tránh lỗi ảnh hưởng đến người dùng. Pipeline sẽ cung cấp phản hồi cho nhóm trong việc cung cấp tính năng mới. Ở góc độ trừu tượng hơn, deployment pipeline là quy trình để chuyển phần mềm từ version control đến tay người dùng. Mỗi thay đổi đến phần mềm sẽ đi qua một quy trình phức tạp để được phát hành.
Có một khái niệm nữa là Continuos Deployment, và hai khái niệm này thường hay bị nhầm lẫn với nhau. Nếu Continuous Delivery là triển khai code lên môi trường staging, và deploy thủ công lên môi trường production, thì Continuous Deployment (cũng viết tắt là CD) lại là kỹ thuật để triển khai code lên môi trường production một cách tự động, và cũng nên là mục tiêu của hầu hết công ty.
Về cơ bản thì môi trường staging là môi trường giống với production, nên đã làm Continous Delivery được thì cũng làm Continous Deployment được. Tuy nhiên, thực tế lại không dễ dàng như vậy. Lý do thứ nhất là chúng ta có thể deploy tự động lên staging, nhưng liệu chúng ta có dám deploy tự động với production, cho dù là mọi cấu hình đều giống nhau thì thực tế staging và production server vẫn là hai server riêng biệt, và vì thế không thể đảm bảo mọi thứ chạy đúng trên staging sẽ chạy đúng trên production, thế nên deploy lên production thường phải làm thủ công để chắc chắn là các bước build, test được thực hiện chính xác. Lý do thứ hai đơn giản hơn, đó là rất khó để test tự động hoàn toàn, và bởi vậy khó mà tự động deploy được.
Dù Continous Deployment có thể không phù hợp với mọi công ty, nhưng Continuous Delivery thì tuyệt đối là yêu cầu cho việc thực hiện triết lý DevOps. Chỉ khi code được chuyển giao liên tục, chúng ta mới có thể tự tin rằng những thay đổi từ code sẽ phục vụ cho khách hàng sau chỉ vài phút với một nút ấn.
Đây có thể là một lợi ích vô cùng hữu ích của CI/CD, nó cho phép làm giảm thiểu đi những rủi ro nhờ việc phát hiện và sửa lỗi sớm, giúp tăng chất lượng sản phẩm nhờ khả năng tự động kiểm tra và quan sát. Không những vậy, những quy trình thủ công lặp đi lặp lại hằng ngày cũng được giảm tải, thay vào đó là xây dựng và kiểm thử tự động mà không cần đến sự giúp đỡ của con người. Một đặc điểm nữa của CI CD chính là có thể deploy, triển khai phần mềm ở bất cứ địa điểm và thời gian nào.
Thay đổi code nhỏ
Một lợi ích vô cùng lớn của CI/CD chính là cho phép chúng ta tích hợp nhiều loại mã nhỏ cùng một lúc. Những thay đổi mã này được thực hiện một cách đơn giản và xử lý nhanh hơn so với những đoạn mã khổng lồ, từ đó làm giảm đi khả năng sinh ra những vấn đề liên quan đến việc thay đổi sau này.
Những sự thay đổi mã nhỏ này có thể được thực kiểm tra ngay sau khi chúng được tích hợp vào kho mã. Các nhà phát triển có thể dễ dàng nhận ra vấn đề trước khi lượng lớn công việc tăng lên một cách chóng mặt. Đây thực sự là một lợi thế đối với những nhóm phát triển lớn hoặc người làm việc từ xa giao tiếp được hiệu quả hơn.
Hạn chế những ảnh hưởng của lỗi hiệu quả
CI/CD được thiết kế với hệ thống sao cho khi có lỗi nào đó xảy ra thì những kết quả tiêu cực sẽ bị giới hạn trong phạm vi ảnh hưởng nhất định nào đó. Việc hạn chế các vấn đề này giúp làm giảm khả năng hư hỏng từ đó làm cho hệ thống được bảo trì và xử lý một cách dễ dàng hơn.Với hệ thống CI CD, có thể đảm bảo cho việc cách ly lỗi sẽ được phát hiện một cách nhanh chóng và dễ dàng thực hiện hơn. Chính vì vậy, hậu quả của các lỗi trong ứng dụng sẽ được giới hạn trong phạm vi ảnh hưởng của nó.
Hy vọng bài viết này về CI/CD là gì sẽ giúp ích cho quá trình setup CI/CD trong hệ thống của bạn, cũng như tăng tốc quá trình phát triển dự án. Nếu thấy bài viết hay và hữu ích, hãy chia sẻ cho các anh em khác để cùng trao đổi và giao lưu.
Bài viết được sự cho phép của tác giả Phạm Minh Khoa
Cypress là gì?
Cypress là tool phục vụ cho UI Automation test và chính xác là dành cho web. Nó có chức năng tương đương với Selenium, nhưng được viết bằng javascript và có cách hoạt động hoàn toàn khác biệt.
Nó được giới thiệu là nhanh, đáng tin cậy hơn selenium và có thể dùng cho nhiều level test, từ Unit, Integration đến End-to-end Test. Vì nó được định hình là framework nên chắc chắn nó sẽ có nhiều tính năng tốt hơn selenium, cái đơn thuần là library.
Cypress hỗ trợ chúng ta làm gì?
Thiết lập tests
Viết tests
Chạy tests
Debug tests
Đằng sau Cypress là một máy chủ Node.js. Quá trình Cypress và Node.js liên tục liên lạc, đồng bộ hóa và thực hiện các nhiệm vụ thay mặt cho nhau. Có quyền truy cập vào cả hai phần (front and back) cho phép khả năng phản hồi các sự kiện của ứng dụng trong thời gian thực, đồng thời hoạt động bên ngoài trình duyệt cho các tác vụ yêu cầu đặc quyền cao hơn.
Browser này sẽ được hiển thị với 2 iframes. 1 cái là cypress (domain: localhost) và 1 cái là application của chúng ta (domain riêng). Bởi vì các iframes trên browser không thể trao đổi hoặc tương tác lẫn nhau nếu khác domain nên 1 script được cài vào trong application để đổi domain của app thành localhost. Từ đó, cypress có thể access đến các object khác trong app như DOM, Window, LocalStorage…
Cypress cũng tương tác với Nodejs để có thể xin cấp quyền từ hệ điều hành (OS) cho các tác vụ như chụp ảnh hoặc quay video.
Vì browser được khởi tạo cùng với proxy nên cypress quản lý được network ra vào của browser đó, từ đó edit được request và response.
Tất nhiên tùy vào bài toàn của từng project mà 2 test tool này được chọn và sử dụng với các mục đích khác nhau. Ngoài ra các bạn có thể tham khảo so sánh npm trends ở link dưới đây:
Hy vọng rằng bài viết này sẽ giúp bạn hiểu rõ hơn về Cypress cũng như những điểm khác nhau của Selenium và Cypress. Đừng quên theo dõi TopDev để cập nhật các việc làm FrontEndmới nhất nhé.
Trong thời đại công nghệ 4.0 hiện nay, nhu cầu tuyển dụng Developer luôn ở mức cao. Đặc biệt, sự phát triển mạnh mẽ của hệ điều hành iOS thì vị trí iOS Developer càng thu hút được nhiều sự quan tâm từ các bạn trẻ. Vậy bạn đã biết gì về iOS Developer? Công việc cụ thể của lập trình viên iOS là gì? Hãy cùng TopDev tìm hiểu dưới bài viết này nhé!
iOS Developer là gì?
iOS không còn quá xa lạ với người dùng Việt, đây là hệ điều hành chạy trên các dòng điện thoại iPhone của Apple. Android và iOS là hai hệ điều hành đang thống lĩnh trên thị trường, được nhiều nhà sản xuất phần mềm quan tâm.
Với hệ điều hành này, người dùng có thể thoải mái tương tác thông qua các thao tác trên màn hình cảm ứng. Những thao tác này được các lập trình viên thiết lập trước và không ngừng được cải thiện, nâng cấp để tăng khả năng xử lý và trải nghiệm cho người dùng.
Đây cũng chính là một phần công việc của các iOS Developer. Các iOS Developer sẽ sử dụng ngôn ngữ lập trình Swift để thiết kế, phát triển phần mềm tương thích với hệ điều hành của Apple.
Một lập trình viên iOS thường thực hiện những công việc như thế nào? Dưới đây là một số công việc các iOS Developer thường làm:
Lên ý tưởng, thiết kế và xây dựng ứng dụng mới liên quan đến hệ điều hành iOS.
Thảo luận và lên ý tưởng với các Developer khác để phát triển ứng dụng.
Viết mã để kiểm tra tính năng và khả năng hoạt động của ứng dụng.
Phát hiện lỗi và sửa lỗi để tối ưu hiệu suất hoạt động ứng dụng.
Không ngừng theo dõi và nâng cấp các tính năng mới cho ứng dụng.
Các kỹ năng cần có của một iOS Developer
Khả năng làm việc với mô hình Agile
Một lập trình viên iOS cần phải làm việc thành thạo với mô hình Agile. Áp dụng mô hình này giúp cải thiện tốc độ bàn giao dự án, tăng hiệu suất công việc và công việc đi theo kế hoạch rõ ràng. Một iOS Developer am hiểu mô hình Agile sẽ có khả năng làm việc tốt hơn, dễ dàng thăng tiến.
Thành thạo các kỹ năng về UI, UX và không gian lý luận
UI là một yếu tố liên quan đến giao diện của ứng dụng, thu hút người sử dụng ứng dụng của bạn. UX sẽ liên quan đến vấn đề về trải nghiệm của người dùng trên ứng dụng. Công việc của các lập trình viên iOS là phải tạo ra được một ứng dụng vừa có giao diện bắt mắt và vừa phải dễ sử dụng.
Kỹ năng Networking
Một ứng dụng không thể hoàn thành chỉ với một lập trình viên mà cần sự trao đổi, thảo luận của cả team. Vì vậy, kỹ năng networking sẽ giúp cho công việc của các iOS Developer thuận lợi hơn, công việc đạt được hiệu quả như mong muốn.
Sự phát triển mạnh mẽ của công nghệ, đặc biệt là các thiết bị di động đã kéo thu nhu cầu về nhân lực ngành công nghệ tăng cao. Cùng với đó, Apple là một “gã khổng lồ” trong giới công nghệ với dòng điện thoại iPhone chạy hệ điều hành iOS đang ngày càng “bành trướng” thị trường của mình. Chính vì thế, cơ hội việc làm cho các lập trình viên iOS Developer vô cùng rộng mở.
Không chỉ riêng gì Việt Nam, nguồn nhân lực lập trình viên iOS luôn là “cơn khát” với các công ty công nghệ. Nếu bạn đang tìm kiếm một việc làm iOS thì nhất định không thể bỏ qua TopDev. Tại TopDev, bạn sẽ dễ dàng tìm được các công việc iOS Developer với mức lương và đãi ngộ siêu hấp dẫn.
Với nhu cầu tuyển dụng cao nên mức lương cho vị trí iOS Developer cũng ở mức cao. Mức lương trung bình của một lập trình viên iOS rơi vào khoảng 14 – 16 triệu đồng/tháng với người có kinh nghiệm 1 – 2 năm. Còn đối với sinh viên mới ra trường chưa có kinh nghiệm thì mức lương khởi điểm khoảng 8 – 10 triệu đồng/tháng. Những người có thâm niên trong nghề thì đạt được mức lương trên 40 triệu đồng/tháng là điều không quá khó. Tùy vào năng lực, kinh nghiệm, chuyên môn của mỗi người mà sẽ có mức thu nhập khác nhau.
Có thể thấy, iOS Developer là một nghề đầy hứa hẹn trong tương lai. Đặc biệt, khi Việt Nam đang trên đà phát triển mạnh mẽ về kinh tế, đặc biệt là trong lĩnh vực công nghệ thông tin.
Tóm lại
Với những chia sẻ trên, mong rằng bạn đã có thêm thông tin về nghề iOS Developer cũng như những kỹ năng, yêu cầu của công việc này. Hãy lên kế hoạch cho mình để bắt đầu chinh phục con đường trở thành một lập trình viên giỏi trong tương lai bạn nhé.
Hoặc, bạn có thể tham khảo tin tuyển dụng iOS Developer trên TopDev, để có thể hiểu rõ hơn về những yêu cầu, nhiệm vụ của một lập trình viên iOS. Chúc các bạn tìm được công việc ưng ý.