Header image

Explore all articles in How-to

Productivity app features that resonate with remote workers

How-to

+0

    Productivity App Features That Resonate With Remote Workers

    Even as the pandemic fades into the past, remote and hybrid work have remained widely practiced. And one of the main factors underpinning this trend is the emergence of remote working productivity apps that enable teams to perform highly irrespective of individual members' locations. Many of these apps were already used in workplaces before the pandemic, but some gained more acceptance amongst remote workers. That said, let’s discuss the standout features of productivity apps for remote work: eLearning Capabilities One of the trickier aspects of remote work has been how to get new recruits up to speed. Training can be hard to conduct when physical in-person meetings aren’t an option. You must figure out how to transition smoothly from face-to-face conversations to presentations and walkthroughs. Then, there’s the distribution of learning materials. And as always, you eventually have to assess the trainee to determine how ready they are for specific tasks. This is where virtual classroom software has won the hearts of many. The ideal tools, in this case, should enable the trainer to create courses, stock libraries and deliver exams. Photo by Wes Hicks on Unsplash Top-notch learning management systems also provide ingenious features like surveys and quizzes that keep trainees more engaged during learning and assessment. And to promote flexibility, such tools also facilitate self-paced learning while providing detailed reports and analyses for each trainee. Some popular solutions encapsulating eLearning capabilities include TalentLMS, AbsorbLMS, Trainual, ProProfs LMS and more. Team Building When an entire team is in the same physical workspace, it's easier to organize and hold fun activities outside their work assignments to strengthen bonds and get everyone into a single mission. However, once everyone is scattered across different locations, all this becomes harder. Photo by ål nik on Unsplash In fact, productivity may decrease as some team members feel less heard and spend more time figuring out how to assert themselves. Others may get caught up in a vicious cycle of second-guessing their own ideas and decisions as they feel they have limited guidance. On that note, team leaders need to dedicate some time to team building, and they can do it using apps that provide features like scavenger hunts, puzzles and other games that bring people closer. Common virtual team-building apps include Playmeo, Scavify, Kahoot!, Good & Co Teamwork, Heads Up! and RallyBright. Remember that not all these tools are about playing games. Some deliver quizzes you can use to profile each team member and see how best they can work together based on their individual strengths and weaknesses. Multimedia Communication While email has massively evolved over the years, it still feels like a formal letter. Moreover, the attachment feature doesn’t fully support the wide range of variations in how remote workers interact. For example, a team member overseas may want to share a video feed of their surroundings since they are near a revered landmark or monument. Another team member may receive a work-related message at a party where texting or calling may be inconvenient, but a quick voice note can work. In essence, remote teams need to be able to communicate in a manner that prioritizes their work but also channels the vibe in their respective remote workspaces. Photo by LinkedIn Sales Solutions on Unsplash This is best achieved with a strategic mix of video conferencing, file sharing, notifications and reminders, text messaging and group chat, postcards and more. To minimize the cold and ultra-serious atmosphere typically associated with work emails, you can try a solution like Today.ly. What’s unique about such a tool is that on top of offering all the typical communication channels, its interface emulates a real work environment. You can see groups meeting in conference rooms and follow how individuals come and go in real-time. The app also enables you to view availability and instantly start a conversation with a teammate by simply clicking on their avatar instead of having back and forth emails for sending meeting links and updating the times on invitations. Task and Process Automation For many remote workers, their schedules are constantly in flux. They aren't considerably detached from other aspects of their life like childcare and home management in the same way that office workers are. Secondly, remote teams often include members in different time zones, so some work needs to be ready and getting submitted at a time when the person working on it is sleeping. This can be something like transferring figures from survey forms into a report, sending out newsletters, populating tables, sending reminders, and more. For the lucky ones, it’s one simple task. But in other cases, the work involves more elaborate processes demanding contributions and approvals from various personnel. Accordingly, task management and process automation tools are the best way to tackle this challenge. But before you start, you need to ascertain the different levels at which automation takes place. Firstly, there's the lower level, where you need automation tools for specific tasks. Photo by Yuyeung Lau on Unsplash A good example is marketing automation tools like ActiveCampaign, MailChimp, HubSpot and Klaviyo for sending emails to customers. Above this level, you’re creating end-to-end workflows involving multiple tasks. Consequently, you’ll need tools like Integrify, ClickUp, Wrike, Kissflow, Smartsheet, Zapier and Adobe Workfront. With such tools, you should look out for those that come with pre-built templates and drag-and-drop builders or an equivalent that requires as little code as possible (preferably no code). This way, anyone in the organization can easily create and edit automations without involving IT. The bigger picture As you can see, depending on an organization’s size and the diversity of work they do, the remote work toolset can quickly expand. From accounting to HR, legal, IT and marketing, plenty of work could use a digital solution or two. Therefore, when shopping for Work From Home (WFH) tools for your teams, you should pay close attention to their integrations. You don’t want to end up with many tools that can't link to each other. This will leave you with more work, constantly transferring data between different software and increasing the likelihood of errors. Lastly, it helps to go for tools that have reliable customer support. It's even better if the support agents are available 24/7 since problems could come in from team members in various time zones. Wrapping Up WFH productivity apps can benefit an organization on various fronts, like increasing efficiency, improving team morale and reducing operational costs. That’s why you should think broadly when choosing them. To get professional assistance in selecting and managing these tools, contact us for a free consultation.

    17/11/2022

    479

    How-to

    +0

      17/11/2022

      479

      Productivity App Features That Resonate With Remote Workers

      How to exercise value-driven app development that drives revenue

      How-to

      Software Development

      +0

        How To Exercise Value-Driven App Development That Drives Revenue

        Many software development teams spend long periods developing and rolling out features they've invested in, only to get lackluster results in customer satisfaction and overall revenue. On the other hand, some teams roll out a seemingly silly feature that eventually gets everyone giggling when using their app and drives more engagement. So how do some teams get it right while others fail? Let’s lay out some key value-driven app development strategies that can help you boost revenue: Involve industry experts When development teams are creating software for a client, they often talk to one person on the client’s side or a few people in higher managerial positions. Instead, they should be speaking to people at various levels of the organization to determine how one department's actions affect another department's work. Additionally, if the product isn't just for internal use by one client but for a whole industry, it's essential to talk to different people within that industry. This helps you learn what they are getting wrong individually and as a group. You can discover which approaches are unique to one organization and which workflow practices are industry-standard. From here, you’ll know the must-have features that appeal to a larger group, then create a list of optional features that highlight the ingenious ways a few entities in that industry are tackling inefficiencies. Consequently, you can test these extras individually to see if they'll be relevant for the whole industry or if they only worked for one organization due to their unique characteristics. Source: Photo by Accuray on Unsplash Remember, HR in an ecommerce company won't be exactly the same as HR in a hospital, so if you know the product is aimed at a specific industry, find out that industry's major pain points before you start development. But what if the app is for the general public? So let’s say you’re trying to make the next WhatsApp or TikTok. In that case, it helps to speak to experts in fields like messaging and communication, behavioral psychology and other broad studies. You should also identify people who have previously worked at firms that do what you’re trying to improve. For example, a former PayPal worker could help you learn what’s missing in modern fintech products, depending on their role at the company. Define value at each stage It’s possible to make an app better in a particular area, like how fast it displays search results, but still not offer value. To create value and drive app revenue, you need to ask yourself, “What are users willing to pay for?” For example, many people are willing to pay for an app that helps them quickly get food from their favorite restaurants. So after ascertaining what people are paying for, find out what's missing in that product/service. What could be better than selecting the dish you want and receiving it quickly? The answer to this question starts with breaking down that entire process into various stages. These may include; finding a good dish, making changes to an order (increasing quantity, choosing different toppings, zinger or regular, extra cheese), notifying the provider that you aren't at your usual address, using alternative payment methods at checkout etc. Source: Image by macrovector on Freepik By dividing the process into such stages, it's easier to determine what can go wrong in a particular phase or what can be added. Ultimately, something valuable changes the user's behavior in one way or another. For example, a favorites menu makes users spend less time scrolling through entire catalogs. They'll only do this when they are tired of their favorites. So in that sense, a better-looking strip of thumbnails might make a user feel good, but the ability to see which item is unavailable or which currently has a discount is more valuable. The ability to quickly see what's new, exclude items below or above a specific price, and other capabilities like that speak to someone who desires to pay. Therefore, whenever your team decides to improve an app, you should represent goals as something that induces an action that could culminate in a sale. For example, goals should sound like, "Make it possible to search by price," "Add option to change the delivery address for each order,” and "Add suggestions that would go well with the item ordered right before checkout.” Shorten the feedback loop It’s common for organizations to champion customer-centric product development, but listening to the user is only half the battle. To grow app revenue, you must transcend discovering what the people want and providing it. You should understand what they are saying and act on it faster than the competition. To achieve this, you ought to categorize feedback based on different criteria, such as; How detailed is it? Is it a score or an entire paragraph?Is it a request for a new feature, a review of the whole app or a small comment on how responsive and helpful an existing feature is?How much does it cost to collect that feedback (the tech tools you need, the amount of time you spend collecting data, the number of people involved in the process and more)? Source: Photo by Austin Distel on Unsplash Teams often need to pay more attention to how organized they need to be to collect user opinions or observe and analyze user behavior. They need to remember that it can be tricky to put together a representative focus group, find a usability testing tool that tracks indicators in the desired manner, communicate feedback across the team and arrange meetings to brainstorm in response. By categorizing feedback, it's easier to visualize the entire journey of a user's opinion, the time it's received, and the different people that weigh in on how to respond to it up until it manifests in the next version of the product. Subsequently, you spend less time collecting irrelevant data or sitting on important information. Wrapping Up Value is subjective. This is what makes value-driven app development quite challenging. At the end of the day, there'll always be some hit-and-miss scenarios, but if you want professional help practicing value-driven app development that drives revenue, contact us for a free consultation.

        08/11/2022

        416

        How-to

        +1

        • Software Development

        08/11/2022

        416

        How To Exercise Value-Driven App Development That Drives Revenue

        React application rs

        How-to

        Software Development

        +0

          A Better Way To Use Services In React Application

          Sometimes you have/want to create and use a service in your application for the DRY principle. But do you know exactly what is a service? And what is the best way to use services in React applications? Hi everyone! It's nice to meet you again in React related series. In the previous article, we discussed about effective state management in React, we learned about Context: what is it? when to use it? One of the use cases is using a context to share a collection of services through the components tree, but what kind of things can be called a service? And how is it integrated into React application? Let's discover the following sections: What is a Service? Service is just a group of helper functions that handle something particularly and can be reused across application, for example: Authentication Service that includes authentication status checking, signing in, signing out, getting user info …Http Service that handles request header, request method, request body … How to use? There are different kinds of implementation and usage, I just provide my favorite one that follows Angular module/services provider concepts. Create a service A service is a JavaScript regular class, nothing related to React. export default class ApiService { constructor() {} _setInterceptors() {} _handleResponse_() {} _handleError_() {} get() {} post() {} put() {} delete() {} } export default class AuthService { constructor() {} isAuthenticated() {} getUserInfo() {} signIn() {} signOut() {} } Create a Context Create a context with provider and pass services as props. import { createContext, useState } from 'react'; import { ApiService, AuthService } from '@services'; const services = { apiService: new ApiService(), authService: new AuthService() }; const AppContext = createContext(); const { Provider } = AppContext; const AppProvider = ({ children }) => { return <Provider value={{ services }}>{children}</Provider>; }; export { AppContext, AppProvider } Use a context Place a context provider at an appropriate scope, all consumers should be wrapped in it. import { AppProvider } from './context/AppContext'; import ComponentA from './components/ComponentA' const App = () => { return ( <AppProvider> <div className="app"> <ComponentA /> </div> </AppProvider> ); }; export default App; Inside a child component, use React hooks useContext to access services as a context value. import { useContext, useEffect } from 'react'; import { AppContext } from '../context/AppContext'; const ChildComponent = () => { const { services: { apiService, authService } } = useContext(AppContext); useEffect(() => { if (authService.isAuthenticated()) { apiService.get(); } }, []); return <></>; } export default ComponentA; Above are simple steps to integrate services with context. But it would be complicated in the actual work. Consider organizing context with approriate level/scope. My recommendation is to have two kinds of service contexts in your application: App Services Context to put all singleton services. Bootstrap it once at root, so only one instance for each is created while having them shared over the component tree.For others, create separate contexts and use them anywhere you want and whenever you need. Alternatives Service is not the only one way to deal with reusable code, it depends on what you intend to do, highly recommend to: Use a custom hook, if you want to do reusable logic and hook into a state.Use a Higher-order component, if you want to do the same logic and then render UI differently. Reference Does React Context replace React Redux?React RetiX - another approach to state management Author: Vi Nguyen

          31/08/2022

          3.6k

          How-to

          +1

          • Software Development

          31/08/2022

          3.6k

          A Better Way To Use Services In React Application

          aws-infra

          How-to

          Online-Merge-Offline Retail

          +0

            Mini Apps – Ứng Dụng Công Nghệ Là Chìa Khoá Thành Công Với Doanh Nghiệp Của Bạn (Part 3)

            Giới thiệu Chào các bạn, như vậy sau 2 bài viết trong chuỗi Seri tìm hiểu về Line Mini App của mình, chắc hẳn mọi người cũng đã nắm được cơ bản về việc tạo channel cũng như khởi tạo LIFF app rồi. Ở bài viết này, chúng ta sẽ tìm hiểu cách để triển khai ứng dụng LIFF app theo đề bài ban đầu. Tạo một ứng dụng chuyên tích điểm dành cho khách hàng thường xuyên check-in tại cửa hàng, và khi khách hàng đạt ngưỡng một số điểm nhất định, chúng ta sẽ gửi thông báo tới khách hàng và tặng khách hàng mã Voucher giảm giá sản phẩm, với yêu cầu đơn giản này, chúng ta hãy cùng xem ứng dụng mini app có thực sự tiện lợi không nhé. Đọc kỹ yêu cầu, chúng ta có 2 yêu cầu chính trong ứng dụng này. Chức năng tích điểm khi check-in tại cửa hàng, mỗi khi khách hàng tới cửa hàng sẽ nhấn nút check-in và hệ thống sẽ lưu lại và tặng điểm cho mỗi lần khách hàng thực hiện thao tác này.Chức năng gửi Voucher cho khách hàng khi tích đủ số Point nhất định. Lựa chọn giải pháp Khi tiến hành với việc triển khai giải pháp bằng việc lựa chọn công nghệ thích hợp, việc đầu tiên chúng ta cần phải nghĩ tới ngay đó là hiệu quả và chi phí vận hành. Rõ ràng, có rất nhiều giải pháp để triển khai một hệ thống, tuy nhiên để cân bằng trạng thái P/P (Price-Performance Ratio - tỷ lệ cân bằng giữa giá và hiệu suất) là điều rất cần thiết. Ở bài này, chúng ta sẽ cùng tìm hiểu về một trong những giải pháp đáp ứng được P/P, đang được rất nhiều hệ thống nhỏ sử dụng hiệu quả, giải pháp liên quan tới Cloud và Serverless, cụ thể trong bài viết này, chúng ta sẽ cùng tìm hiểu và triển khai về AWS Cloud và Serverless (Lambda + API Gateway) Dưới đây là mô hình AWS infrastructure cơ bản để demo sản phẩm này. Giải thích thành phần: API Gateway: cổng kết nối trung gian dịch vụ giữa ứng dụng LIFF và các dịch vụ bên trong (Lambda), là nơi thiết kế các API truy xuất dữ liệu.CloudFront: là CDN dùng để kết nối tới các host chứa dữ liệu, dữ liệu bài viết này là source code của ứng dụng Web, chúng ta sử dụng Single Page Web App cho ứng dụng sắp triển khai.S3: hiện là nơi lưu trữ dữ liệu source code của web app (SPA).Lambda: là một dạng computing được viết theo từng function, thay cho máy chủ để tính toán, truy xuất dữ liệu từ DB và trả về kết quả, chúng ta không cần máy chủ trong ứng dụng này, mọi chi phí sẽ dựa theo lượng request sử dụng.DynamoDB: là cơ sở dữ liệu (Database Engine) lưu trữ thông tin của user, trong khuôn khổ bài viết này, chúng ta sẽ lưu trữ số Point của end-user.CloudWatch: là nơi lưu trữ log của Lambda và dùng để trigger sự kiện theo schedule, ở bài viết này chúng ta sẽ dùng CloudWatch trigger mỗi 5 phút/ lần để gửi mã Voucher thử nghiệm nếu user đã đủ point.Messaging API: Là API do LINE cung cấp, dùng để gửi message tới user đang sử dụng LINE app và đã đăng ký với channel ứng dụng của chúng ta đang triển khai.LIFF SDK: là SDK dùng để tích hợp với Web app mà ta sẽ triển khai. Như vậy, chúng ta đã đi sơ qua các thành phần và giải pháp sẽ triển khai ứng dụng, bước tiếp theo chúng ta cần đăng ký tài khoản AWS và cùng thử xem sơ qua cách tính chi phí vận hành của ứng dụng với mô hình này nhé. Tìm hiểu về AWS và đăng ký tài khoản Ở phần trên, chúng ta sẽ thực hiện giải pháp sử dụng AWS Cloud làm mô hình Serverless cho ứng dụng, để bắt đầu, bạn cần hiểu sơ về AWS Cloud. Amazon Web Services (AWS) là nền tảng đám mây toàn diện và được sử dụng rộng rãi nhất, cung cấp trên 200 dịch vụ đầy đủ tính năng từ các trung tâm dữ liệu trên toàn thế giới. Hàng triệu khách hàng—bao gồm các công ty khởi nghiệp tăng trưởng nhanh nhất, các tập đoàn lớn nhất cũng như các cơ quan hàng đầu của chính phủ—đều tin tưởng vào AWS để giảm chi phí, trở nên linh hoạt hơn và đổi mới nhanh hơn. Đăng ký tài khoản AWS của bạn ngay. Sau khi đã đăng ký được tài khoản, bạn tiến hành đăng nhập, để đảm bảo tuân thủ Security Best Practice, bạn không nên sử dụng Root user, nhưng trong phạm vi khuôn khổ bài viết, chúng ta sẽ sử dụng root user để triển khai. Đừng quên tìm hiểu thêm lý do vì sao không nên xài root user. Giao diện đăng nhập AWS sau khi đăng nhập thành công sẽ như thế này. Như vậy là xong, bạn đã hoàn tất việc tạo 1 tài khoản AWS, lưu ý, mọi dịch vụ trên AWS đều có thể mất phí, vì vậy bạn cần hiểu rõ về dịch vụ mình cần sử dụng, để không mất quá nhiều tiền cho sản phẩm thử nghiệm của mình nhé, trong khuôn khổ bài viết chúng ta không thể phân tích chi tiết về phí dịch vụ, nhưng hãy luôn lưu ý vấn đề này khi sử dụng AWS Cloud. Kết thúc Trong khuôn khổ bài viết này, chúng ta đã hình dung được mô hình cấu trúc (AWS infrastructure) AWS khi triển khai ứng dụng LIFF App cùng với Serverless. Ở bài tiếp theo, chúng ta sẽ xây dựng một ứng dụng và triển khai (deploy) ứng dụng này lên Cloud, các bạn cùng chờ bài viết tiếp theo nhé. Cùng đón đọc các phần trước của series này nhé! Author: Kiet Vo

            03/06/2022

            490

            How-to

            +1

            • Online-Merge-Offline Retail

            03/06/2022

            490

            Mini Apps – Ứng Dụng Công Nghệ Là Chìa Khoá Thành Công Với Doanh Nghiệp Của Bạn (Part 3)

            intro2

            How-to

            Online-Merge-Offline Retail

            +0

              Mini Apps – Ứng Dụng Công Nghệ Là Chìa Khoá Thành Công Với Doanh Nghiệp Của Bạn (Part 2)

              Giới thiệu Ở bài viết trước, chúng ta đã hiểu được Line Mini App là gì, cũng như những ví dụ minh họa cơ bản về những trường hợp nên sử dụng Mini App trên Line. Trong khuôn khổ bài viết này, chúng ta sẽ làm quen với việc tạo một ứng dụng Line Mini App và tích hợp nó vào trong Line. Trước khi bắt đầu tạo một ứng dụng Line Mini App sẽ cần phải xác định trước những yêu cầu của nền tảng mà bạn đang tính xây dựng, thông thường sẽ liên quan tới luật và chính sách của quốc gia sở tại, vậy nên bạn nên đọc kỹ phần chính sách và điều khoản để đáp ứng được các yêu cầu. Đối với Line, yêu cầu đó có thể bao gồm: thông tin khách hàng, thông tin doanh nghiệp, nội dung chia sẻ và vấn đề liên quan tới bản quyền, … và lưu ý quan trọng, trong quá trình phát triển ứng dụng bạn có thể hoạt động tự do. Tuy nhiên, để ứng dụng được Publish, bạn cần được review và chấp nhận từ công ty Line. Để tìm hiểu kỹ hơn về điều khoản và chính sách liên quan tới Line Mini App, bạn có thể xem bảng chi tiết tại đây. Lưu ý, với mỗi quốc gia sẽ có chính sách riêng biệt hãy xem kỹ nội dung theo quốc gia bạn đang hướng tới để áp dụng phù hợp với giải pháp định chọn. Sau khi đã xác định và hiểu rõ, bạn có thể bắt đầu tiến hành tạo một ứng dụng Line Mini App theo các bước trong mục tiếp theo. Tạo ứng dụng Line Mini App Để bắt đầu với một ứng dụng, giả sử chúng ta đang xây dựng ứng dụng Line Mini App là một ứng dụng chuyên tích điểm dành cho khách hàng thường xuyên check-in tại cửa hàng, và khi khách hàng đạt ngưỡng một số điểm nhất định, chúng ta sẽ gửi thông báo tới khách hàng và tặng khách hàng mã Voucher giảm giá sản phẩm, với yêu cầu đơn giản này, chúng ta hãy cùng xem ứng dụng mini app có thực sự tiện lợi không nhé. Dưới đây, là các bước cần chuẩn bị trước khi tạo ứng dụng Mini App. Chuẩn bị tài khoản Line Việc đầu tiên, bạn cần truy cập tới trang quản trị dành cho nhà phát triển ứng dụng (nhấn tại đây). Bạn có thể đăng nhập với tài khoản Line hoặc tài khoản doanh nghiệp trên Line, để tìm hiểu kỹ hơn về tài khoản doanh nghiệp, hãy tham khảo tại đây. Sau khi đã đăng nhập thành công, màn hình quản trị sẽ hiển thị như dưới, bạn cần tạo 1 Provider để thử nghiệm, nhấn vào nút Create Điền tên Provider, ở đây chúng ta đặt tên Test-Mini-App, sau đó nhấn Create Sau khi quá trình tạo Provider hoàn tất, bạn được chuyển tới màn hình mới, với 3 Tabs chính:Channels: đây là tất cả các kênh mà nền tảng Line hỗ trợ để bạn có thể xây dựng các dịch vụ, trong khuôn khổ bài viết này, chúng ta chỉ cần quan tâm tới 2 channel là Line Login Channel và Line Messaging API ChannelRoles: đây là nơi bạn có thể thêm thành viên, nhà phát triển và người kiểm thử (Tester) để có quyền kết nối tới các channel bạn đã tạo.Settings: là những cài đặt cơ bản quan tới Provider. Lựa chọn giữa LIFF hoặc Line Mini App Sau khi khởi tạo tài khoản và tạo Provider ở bước trên, ở bước này chúng ta có thể tiến hành khởi tạo Line Mini App channel để bắt đầu, tuy nhiên, để có thể tạo được 1 Line Mini App channel, bạn sẽ qua bước kiểm tra và xác nhận từ LINE. Việc này sẽ tốn thời gian, vậy nên trong khuôn khổ bài viết này, chúng ta sẽ cùng tìm hiểu tới LIFF (LINE Front-end Framework), là nền tảng tương tự như Line Mini App và không cần phải chờ đợi review từ LINE. Trước hết, chúng ta sẽ xem qua những điểm khác biệt giữa LIFF và Line Mini App Điểm chung: Cả 2 đều chạy trên nền tảng Web và chạy bởi trình duyệt LIFF, được nhúng vào trong ứng dụng Line.Cả 2 đều có thể tích hợp nhiều công nghệ web mới nhất để cung cấp nhanh dịch vụ. Điểm riêng: LIFF appLINE MINI AppMôi trường- Chạy trên ứng dụng LINE.- Chạy được trên hầu hết các trình duyệt phổ biến.- Chỉ chạy được duy nhất trên ứng dụng LINE (điện thoại)LINE review và chấp nhậnKhông cần, bạn có thể phát hành bất cứ lúc nào.- Phải được review và chấp nhận bởi LINE.- Sau khi thỏa mãn điều kiện review, ứng dụng Line Mini App sẽ được xuất hiện bằng chức năng tìm kiếm và tại tab Home của ứng dụng LINE.Service message chat roomKhông có sẵnBạn có thể sử dụng, chức năng có sẵn trên toàn bộ ứng dụng Line Mini Apps. Tham khảo: tại đây Trong khuôn khổ seri này, chúng ta sẽ lựa chọn LIFF app, là phương án nhanh nhất để bắt đầu, sau khi phát triển hoàn tất, chúng ta có thể tiến hành chuyển đổi sang Line Mini App channel. Tiếp theo, hãy tạo 2 channels như đã đề cập bên trên, bao gồm: Line Login channel: hãy để mọi thông tin là mặc định, lưu ý vài điểm sau.Region: chọn JapanCompany or owner's country or region: JapanChannel name: DEV-Login channelChannel description: Line Mini AppApp Type: chọn WebMessaging API channel: hãy để mọi thông tin là mặc định, lưu ý vài điểm sau.Company or owner's country or region: JapanChannel name: DEV-Messaging APIChannel description: Line Mini AppCategory: Local Business and E-commerceSubcategory: Shopping & retail Như vậy, là xong phần chuẩn bị cơ bản liên quan tới quản trị trên nền tảng Line, bạn sẽ cần chuẩn bị thêm về tài liệu để khởi tạo một ứng dụng mini app trên Line, hãy cùng tìm hiểu về LIFF (LINE Front-end Framework), một nền tảng chạy trên web app được cung cấp bởi LINE. Khởi tạo LIFF apps. Ở bước bên trên, chúng ta đã khởi tạo thành công 1 Provider có chứa sẵn 2 Channels là Login channel và Messaging API channel, ở bước này chúng ta sẽ tiến hành khởi tạo 1 LIFF app và cấu hình LIFF app có thể tương tác với 2 channel này nhé. Line Mini App là ứng dụng chạy trên nền tảng web và nó chạy trên LINE.LIFF app (LINE Front-end Framework) là một framework dùng để xây dựng 1 ứng dụng web, được cung cấp bởi LINE, sử dụng LIFF, bạn sẽ giảm rất nhiều thời gian để xây dựng, xử lý, vì mọi thứ đã được LINE định nghĩa và cung cấp bên trong LIFF. Phiên bản mới nhất hiện tại của LIFF là version 2 (LINE Front-end Framework v2)Bạn có thể sử dụng tính năng thử nghiệm (playground) với LIFF playground để dễ hình dung hơn các tính năng của LIFF. Bước 01: Truy cập vào Login channel và tạo 1 LIFF app. Bước 02: Nhập thông tin, ví dụ như bên dưới Tên trườngMô tảGiá trịLIFF app nameTên của ứng dụng.demo-appSizeLà kích thước của LIFF brower khi bật lênFullEndpoint URLLà tên miền của ứng dụng, chúng ta sẽ cập nhật lại sauhttps://localhost.com:3000Scopeskhai báo quyền cần cấp để xin dữ liệu khi chứng thực với LINEprofile, openidBot link featureoffScan QRonModule modeoff Bước 03: Sau khi đã điền đủ thông tin, nhấn vào nút Add, và quá trình tạo 1 LIFF app đã hoàn tất. Kết thúc Như vậy, với những bước trên, bạn đã hoàn thành được việc đăng ký tài khoản LINE, khởi tạo 1 ứng dụng LIFF trên LINE console. Bài tiếp theo, chúng ta sẽ sang một seri mới liên quan tới kỹ thuật, đó là làm thế nào để triển khai ứng dụng LIFF và chạy nó trên nền tảng LINE. Author: Kiet Vo

              20/05/2022

              822

              How-to

              +1

              • Online-Merge-Offline Retail

              20/05/2022

              822

              Mini Apps – Ứng Dụng Công Nghệ Là Chìa Khoá Thành Công Với Doanh Nghiệp Của Bạn (Part 2)

              line-mini-app-main-contents

              How-to

              Online-Merge-Offline Retail

              +0

                Mini Apps – Ứng Dụng Công Nghệ Là Chìa Khoá Thành Công Với Doanh Nghiệp Của Bạn (Part 1)

                Giới thiệu Thị trường thương mại điện tử, chuyển đổi số, số hóa dữ liệu, bán hàng online … là một trong rất nhiều từ khóa mà chúng ta đã và đang được nghe hàng ngày trên thế giới Internet. Tuy nhiên, để hiểu và áp dụng được những từ khóa đó vào thực tế một cách hiệu quả nhằm giải quyết được bài toán vận hành, chi phí, cũng như các vấn đề tồn đọng hiện tại thì thực sự không hề đơn giản chút nào. Chính vì vậy, việc lựa chọn giải pháp phù hợp để đảm bảo được hiệu quả vận hành, mang lại trải nghiệm tốt với khách hàng là một trong những chìa khóa quan trọng để doanh nghiệp có thể từng bước tiến tới thành công hơn, nhưng vẫn đảm bảo được các tiêu chí về chi phí, hiệu quả và độ tiện dụng. Chuỗi bài viết sau đây mình sẽ giới thiệu và chia sẻ những kinh nghiệm về một mô hình ứng dụng đang được phát triển mạnh mẽ tại nhiều thị trường lớn trên thế giới, tựa bài viết nói về Mini Apps/ Mini programs và cách tạo ra một ứng dụng Mini App tại thị trường Nhật Bản. Mini Apps - Chìa khoá để thành công với mô hình OMO OMO - hay có thể hiểu và gọi với cái tên Online-Merged-with-Offline là hình thức kết hợp giữa mô hình Online và Offline của 1 doanh nghiệp, 1 đơn vị bán hàng, … nhằm cung cấp trải nghiệm cho người dùng 1 cách tốt nhất, hiệu quả và tiết kiệm chi phí. Nó giống như việc bạn muốn mua 1 sản phẩm tại cửa hàng, nhưng thay vì phải tới cửa hàng, xem sản phẩm, sử dụng thử, và thanh toán với nhiều thủ tục khác, … thì bạn có thể giảm rất nhiều thao tác để giúp cho người dùng vừa có thể trải nghiệm sản phẩm tại cửa hàng (Offline), vừa có thể thanh toán và nhận hàng ngay tại nhà (Online) và còn nhiều điều tuyệt vời hơn nữa tùy theo giải pháp mà bạn chọn để tăng hiệu quả và giúp bạn đo lường kết quả rõ ràng. Để có thể làm được điều này, bạn có thể kết hợp với công nghệ (technology) thông qua các ứng dụng, web hoặc các phương tiện truyền thông, … nhưng trong bài viết này, chúng ta sẽ tập trung vào 1 giải pháp, đó là ứng dụng và web. Nếu bạn là chủ 1 cửa hàng, chắc hẳn đa số các bạn đều đã được tư vấn về việc triển khai 1 ứng dụng hoặc website của cửa hàng/ doanh nghiệp, để tạo profile cho khách hàng, giúp bạn chăm sóc khách hàng tốt hơn, tăng độ uy tín của cửa hàng, … Tuy nhiên, việc có hàng nghìn, hàng triệu ứng dụng, website hiện tại làm cho khách hàng cảm thấy bị choáng ngợp và cảm thấy lười trong việc sử dụng và tải về. Cũng giống như việc, bạn đang quan tâm 5-10 cửa hàng chuyên về ẩm thực, mỗi cửa hàng đều triển khai 1 website/ứng dụng riêng biệt, mỗi ứng dụng đều có chức năng tích điểm cũng như nhắc nhở giống nhau, nghĩ thử xem, trên điện thoại của bạn cần phải tải về 10 ứng dụng tương tự như vậy chỉ để phục vụ cho cùng 1 nội dung, chỉ khác cửa hàng, và sau đó nếu vô tình bạn cần phải đổi điện thoại, bạn lại phải lặp lại thao tác tải về, … Nghĩ tới thôi, chắc hẳn ai cũng cảm thấy bị stress và lâu dần chắc hẳn bạn sẽ bỏ hẳn hoàn toàn ứng dụng của cửa hàng đó. Tôi đã bỏ hẳn ứng dụng đặt vé xem phim của các hãng lớn như CGV, Lotte, … và chỉ tải về 1 ứng dụng đặt vé duy nhất là 123Phim chỉ để giảm dung lượng chiếc điện thoại và đăng nhập 1 nơi duy nhất, vẫn đủ chức năng cần. Cũng vì lý do đó, giải pháp mô hình Mini Apps/ Mini Programs đã được triển khai và cũng là 1 trong những mô hình chuyển đổi số đang được áp dụng rộng rãi và thành công tại rất nhiều quốc gia trên thế giới, đi đầu vẫn là Trung Quốc, Nhật Bản, Hàn Quốc, Mỹ … với thành công trong việc đưa các tiểu ứng dụng (mini app) tích hợp vào bên trong 1 ứng dụng khác như Line, WhatsApp, Wechat,… người dùng bây giờ thay vì chỉ xài 1 ứng dụng nhắn tin thông thường, thì nay họ đã có thể sử dụng rất nhiều tiện ích ứng dụng khác (mini app) bên trong ứng dụng tin nhắn này. Cập nhật: Mini app đã và đang được triển khai và phát triển mạnh hơn bên ngoài các ứng dụng nhắn tin, bạn có thể triển khai mini app trên các ứng dụng thương mai điện tử khác như: Shopee, Lazada, Shopify, …. tùy theo mức độ hỗ trợ của nền tảng. Lấy ví dụ như đại dịch Covid-19 vừa rồi, nếu việc triển khai hàng loạt ứng dụng chỉ với 1 mục đích duy nhất là kiểm soát đại dịch Covid, nhưng nếu mỗi tiện ích chỉ phục vụ cho 1 mục đích cụ thể khác nhau, thì người dùng sẽ cần phải tải về rất nhiều ứng dụng trong thiết bị, điều này gây trải nghiệm không tốt, tốn kém và đôi lúc gây tác dụng ngược tới tâm lý người sử dụng. Vậy thì, đây chính là từ khóa để bạn nghĩ tới Mini App. Dưới đây là danh sách 1 vài ứng dụng cho phép tích hợp Mini App/ Mini Programs vào ứng dụng. STTỨng dụngThị trường1LineNhật Bản, Đài Loan, Thái Lan2WhatsAppMỹ, Global3WeChat/WeixinTrung Quốc, Global4ZaloViệt Nam, Myanmar5KakaotalkHàn Quốc Ưu điểm khi sử dụng Mini App Lượng người dùng sẵn có và rất lớn, vì ứng dụng nhắn tin này phục vụ cho đa số dân cư tại quốc gia sử dụng nên số lượng người dùng ứng dụng là rất lớn.Chủ sở hữu uy tín và là các tập đoàn lớn.Hỗ trợ và nhà phát triển cũng như doanh nghiệp.Tiết kiệm rất nhiều chi phí vận hành, bạn trả tiền cho những gì bạn sử dụng.Chỉ cần cài đặt duy nhất 1 ứng dụng.Bạn có thể làm báo cáo, thống kê lượt sử dụng của khách hàng, tận dụng hành vi mua sắm của khách hàng trên nền tảng. Nhược điểm: Phụ thuộc vào tính năng mở, hỗ trợ của nền tảng bạn sử dụng. Trong chủ đề ngày hôm nay, mình sẽ chia sẻ về Line Mini App - là 1 trong nền tảng và giải pháp đang được triển khai mạnh mẽ tại Nhật Bản, nội dung bài viết xoay quanh cách việc bạn xác định vấn đề của doanh nghiệp, định hình vấn đề để tìm ra giải pháp phù hợp hướng tới sử dụng Mini App để giải quyết bài toán của bạn. Chuỗi bài viết này sẽ xuyên suốt cho tới khi bạn có thể tạo ra 1 ứng dụng Mini App tích hợp trên Line cơ bản. Line Mini App Line là 1 trong những nền tảng ứng dụng nhắn tin phổ biên bậc nhất tại Nhật Bản, với lượng người dùng rất lớn, tiện lợi và gắn liền với đời sống người dân Nhật, ứng dụng này dần trở nên phổ biến và hầu như mọi người Nhật đều có ứng dụng này trên thiết bị thông minh (điện thoại, máy tính, máy tính bảng, …) của mình. Line cũng đang phát triển mạnh và lan tỏa ra 2 thị trường khác bao gồm Đài Loan và Thái Lan. Nghĩ đơn giản hơn, nếu bạn ở Việt Nam, bạn thường dùng ứng dụng Zalo để nhắn tin, công việc thì cũng giống như tại Nhật bạn buộc phải cài ứng dụng Line vậy. Ứng dụng nhắn tin Line đã và đang được sử dụng với tất cả người dân Nhật Bản, độ tiện dụng của nó chắc hẳn người Nhật nào cũng đã nhận ra. Chính vì lẽ đó, Line cũng đã tận dụng nền tảng của mình để phát triển và phát hành ra cho nhà phát triển những công cụ, tiện ích và thư viện để nhà phát triển có thể tạo ra những ứng dụng tích hợp vào bên trong nền tảng Line, việc tạo ra những ứng dụng nhỏ chạy trên nền tảng Web và tích hợp vào Line được gọi là Line Mini App. Ứng dụng Line Mini App hiển thị các sản phẩm và mua hàng trên ứng dụng Một vài ví dụ về ứng dụng của Line Mini App đang được đẩy mạnh tại thị trường Nhật, bao gồm: Cửa hàng bán quần áo, mỹ phẩm.Ứng dụng tích điểm, chăm sóc khách hàng.Ứng dụng nhắc nhở khách hàng về sức khỏe, tài chính, lời khuyên, …Ứng dụng thông báo tới khách hàng, chia sẻ thông tin khuyến mãi, giảm giá, happy hours, …Ứng dụng cho việc thanh toán, sử dụng Line Pay hoặc các hệ thống payment tùy chỉnh.… và còn vô vàn trải nghiệm khác. Ứng dụng Line Mini App: Đăng ký đặt chỗ tại cửa hàng cắt tóc Để hiểu sâu hơn về cách tạo ra 1 ứng dụng, chúng ta sẽ cùng đi hết Seri của chuỗi bài viết để biết cách tạo 1 ứng dụng Line Mini App để giải quyết bài toán hiển thị thông tin cửa hàng và nắm được những use-case mà chúng ta có thể làm việc được khi người dùng sử dụng cửa hàng trên mini app này như thế nào nhé. Kết luận Mini App đã và đang là làn sóng chuyển đổi số phổ biến tại rất nhiều quốc gia lớn, và nó sẽ là giải pháp tuyệt vời cho các doanh nghiệp, tổ chức thậm chí chính phủ dùng để triển khai ứng dụng mình trên một nền tảng khác, với chi phí thấp, tính khả dụng cao và nó thực sự linh hoạt khi kết hợp cùng với nền tảng nhắn tin, mạng xã hội để tiếp cận khách hàng một cách đơn giản nhất, giúp người tiêu dùng gắn kết hơn với nền tảng này. Bài tiếp theo, chúng ta sẽ nói về Làm thế nào để tạo ra một ứng dụng Line Mini App trên nền tảng Line, các bạn có thể theo dõi tiếp nhé. Liên kết Hình ảnh, tài liệu tham khảo Author: Kiet Vo

                13/05/2022

                658

                How-to

                +1

                • Online-Merge-Offline Retail

                13/05/2022

                658

                Mini Apps – Ứng Dụng Công Nghệ Là Chìa Khoá Thành Công Với Doanh Nghiệp Của Bạn (Part 1)

                img-001

                How-to

                Software Development

                +0

                  Những Concepts Cốt Lõi Để Trở Thành Bậc Thầy Của Mọi FrontEnd Frameworks

                  Ngày nay, Front-end web development không chỉ giới hạn ở HTML, CSS và JavaScript. Nhu cầu trải nghiệm web của người dùng ngày một cao, điều đó đòi hỏi FE phải mở rộng thêm nhiều libraries, frameworks để đáp ứng được công nghệ mới và gia tăng UI/UX. Vì thế rất nhiều frameworks được ra đời, và danh sách này sẽ còn gia tăng và phát triển trong rất nhiều năm tới. Đi kèm với đó, rất nhiều cuộc tranh cãi về việc đâu là framework tốt nhất, đâu là framework được developers chọn nhiều nhất, và dĩ nhiên, chưa bao giờ có câu trả lời thoả đáng bởi vì mỗi frameworks đều có những ưu và nhược điểm khác nhau. Cuộc chiến giành thị phần của 3 ông lớn Reactjs, Angular, Vuejs ngày một nóng hơn, bên cạnh đó những Ember.js, Foundation, jQuery, Svelte,… vẫn đang trên đường tìm sự công nhận. Như lịch sử đã chứng minh, web development là một lĩnh vực phát triển với tốc độ mạnh mẽ, bạn sẽ ngụp lặn trong thế giới web nếu như không chuẩn bị sẵn sàng để chuyển từ framework này sang framework khác. Việc tiếp cận framework mới thực sự sẽ rất dễ dàng khi bạn nắm vững một vài concept chính trong bài viết này, và bạn sẽ trở thành một FE developer được săn đón trong nhiều năm tới, bất kể bạn đang chọn framework nào. 1. Components - cấu thành cơ bản nhất Component là khái niệm cơ bản nhất mà một FE developer phải nắm, nó là nền tảng của sự phát triển giao diện người dùng nhưng cũng là khái niệm quan trọng nhất thúc đẩy sự phát triển của Frontend frameworks hiện đại ngày nay. Nếu không thực sự hiểu về components, ứng dụng web của bạn có thể sẽ phình to rất nhanh. Vậy component là gì ? Một component là 1 tổ hợp của các phần tử HTML đi kèm với markup (styling) và các script xoay quanh các phần tử đó. Tất cả các thành phần nhỏ nhất của web sẽ nhóm lại theo các tính năng tương ứng, và quy về component. Lấy ví dụ: để show ra Todo list có 5 items, thì chúng ta sẽ phải xây dựng 2 components: Todo item: chứa giao diện của 1 item và các chức năng cần thiết như show content, edit & delete chính mình.Todo list: chứa 5 components Todo item và có chức năng show ra các items, phân trang nếu như có quá nhiều items,…. 3 thứ tạo nên components là Template, Styling, Script,và để có thể viết đc component thì FE developer phải nắm vững HTML, CSS, JS. Tại sao phải cần component ? Nếu như ko có component Todo item, và clients thay đổi specs, không có tính năng edit item nữa, thì developer phải thực hiện xoá phần code liên quan đến việc edit 5 lần. Điều này thực sự rất tốn thời gian so với việc chia component Todo Item và sử dụng lại, chỉ cần thay đổi content của component Todo Item 1 lần là sẽ áp dụng cho tất cả items. Vì vậy bắt buộc phải chia component khi lập trình web ở bất cứ framework nào. Việc chia components giúp chúng ta có thể tái sử dụng, dễ dàng sửa đổi và mở rộng code. Code sẽ sạch sẽ và tường minh hơn rất nhiều khi components đc chia hợp lý. 2. Lifecycle Hooks - những sự kiện trong vòng đời của 1 component Mỗi component instance sẽ trải qua 1 loạt các sự kiện khi nó đang tạo ra. Đồng thời, nó cũng chạy các function được gọi là life cycle hooks, cho phép người dùng có cơ hội thêm code ở các giai đoạn cụ thể. Cũng giống như tất cả lifecycle khác, lifecycle hooks của 1 component bao gồm các sự kiện quan trọng diễn ra trong quá trình sống của component đó, lấy ví dụ, component được sinh ra (init), component setup data, compile template, mount instance đó vào DOM (mounted), và update DOM khi data thay đổi, và cuối cùng là component mất đi (unmounted). Mỗi Framework sẽ có cách tiếp cận lifecycle hooks khác nhau, nên FE developer cần phải nắm được Lifecycle Diagram của từng framework. Để dễ hiểu hơn, mình sẽ đưa ra 1 bài toán cụ thể, bài toán yêu cầu chỉ gọi API get về danh sách news khi vừa mở ra page News - page News được thiết kế là 1 component và API sẽ phải gọi khi nó init xong, dựa trên Lifecycle Diagram của từng framework chúng ta sẽ đặt code gọi API lần lượt ở trong các hooks ngOnInit (Angular), componentDidMount (Reactjs), mounted (Vuejs),…. 3. Data Binding - Ràng buộc dữ liệu Mỗi framework sẽ có 1 cơ chế data binding khác nhau, nhưng nhìn chung là chỉ cần nắm được syntax của những mục bên dưới. Text interpolation - show value của variables trên UI Angular, Vuejs: sử dụng "Mustache" syntax (double curly braces) <span>Message: {{ msg }}</span> React: sử dụng special syntax của JSX (curly braces) <span>Message: { msg }</span> Attribute Bindings - thao tác đến attribute của elements Để input value cho attribute thì mỗi framework đều có sử dụng 1 cách khác nhau, hãy xem ví dụ bên dưới: Angular - sử dụng [] trên attribute <a [href]="url">...</a> Vuejs - sử dụng : trên attribute <a :href="url">...</a> Reactjs - sử dụng curly braces {} trên variable <a href={url}>...</a> Class & Style Binding - thao tác đến class và inline style của elements ​ class và style là attributes đặc biệt của element, một số frameworks support cách binding với Object, Array, sẽ tạo ra code tường minh hơn. 4. Components interaction - Tương tác giữa các components Sự tương tác giữa các component có liên hệ với nhau là rất cần thiết trong modern frameworks. Các component lồng ghép nhau tạo nên component tree, và mỗi node trong tree sẽ là 1 component. node này có thể là parent của node kia, và cũng có thể là 1 child của 1 node khác. Mối quan hệ chủ yếu là parent - child. Nếu thực hiện tương tác giữa 2 node cách quá xa nhau có thể rơi vào case props drilling. Các cách để interact giữa parent & child mà frameworks thường hay sử dụng: Truyền data từ parent vào child: truyền value vào cho child sử dụng.Parent lắng nghe events từ child: tạo function và truyền vào cho child, child sẽ execute function và gửi kèm data ra cho parent khi một event xác định diễn ra.Parent truy cập trực tiếp đến child: parent có thể truy cập đến tất cả variable và function ở bên trong child, thậm chí là thay đổi value của variable, hoặc thực thi function của child. 5. Routing - Điều hướng Client-side routing là chìa khóa của SPA frameworks mà chúng ta thấy ngày nay. Rất dễ để implement nhưng cần nắm vững routing hierarchy.Đầu tiên hãy tìm hiểu về dynamic routing . Trở lại với ví dụ todos ở mục 1, trang list ra tất cả todos sẽ có route /todos, khi user nhấp vào 1 todo, họ sẽ được đưa đến một trang dành riêng cho todo đó (Todo Detail), route của trang này sẽ phải có dạng /todos/:id. id là 1 dynamic variable, dù id=1, id=2 cũng sẽ show ra trang Todo Detail. Tiếp theo, hãy tìm hiểu về cách để nested routing - trong 1 route sẽ có nhiều routes con phụ thuộc, nó cho phép thay đổi các fragment cụ thể của view dựa trên current route. Ví dụ: trên trang user profile, sẽ hiển thị nhiều tab (ví dụ: Profile, Account) để điều hướng qua user info. Bằng cách nhấp vào các tab này, URL trong trình duyệt sẽ thay đổi, nhưng thay vì thay thế toàn bộ trang, chỉ nội dung của tab được thay thế. Cuối cùng, hãy luôn lưu ý đến việc sử dụng lazy loading cho route, nó sẽ giúp cho webapp nhẹ hơn khi chỉ cần load những đoạn code liên quan đến route đang mở, thay vì load hết tất cả code ngay lần đầu tiên truy cập đến trang web. Theo diagram, có thể thấy, StockTable được render nhanh hơn với 1546ms của lazy loading so sánh với 2470ms của eager loading. 6. State Management - Phương thức quản lý các state của app Khi một ứng dụng phát triển, sự phức tạp của việc quản lý state cũng tăng lên theo cấp số nhân. Trong một ứng dụng lớn, nơi chúng ta có rất nhiều components, việc quản lý state của chúng là một vấn đề lớn. Công việc chính của tất cả libraries hoặc frameworks là lấy state của ứng dụng, xử lý và biến nó thành DOM nodes, đó là lý do tại sao việc sắp xếp, quản lý state theo mô hình hợp lý sẽ nâng cao được chất lượng của ứng dụng. Hãy tưởng tượng state management như một tầng cloud, bên dưới là component tree. Tất cả component trong tree có thể truy xuất lên cloud để lấy về những state mà nó mong muốn. ĐIều này giúp cho việc giao tiếp dữ liệu trở nên thuận tiện hơn rất nhiều, đặc biệt là trong trường hợp 2 components không có quan hệ cụ thể trong tree. Phần lớn các thư viện về state management được xây dựng dựa trên kiến trúc Flux. Cách hoạt động State được truyền vào viewActions được triggered từ user trên viewActions update state trong storeState thay đổi value và truyền lại vào view Kiến trúc Flux bao gồm 3 đối tượng: Action & Store & Dispatcher. Cách làm việc này kết hợp với cấu trúc của Actions, Dispatchers, Reducer, đã tạo ra một tiêu chuẩn sẽ được áp dụng cho các thư viện tiếp theo cho rất nhiều ứng dụng. Từ đó, chúng ta có Redux, đây có lẽ là thư viện nổi tiếng nhất. Tuy nhiên, ngày nay, tùy thuộc vào loại dự án và frameworks chúng ta đang sử dụng, chúng ta sẽ lựa chọn những thư viện quản lý state phù hợp nhất. Angular : NGRX : Ứng dụng Redux hướng tới Angular framework.ReactJS : Redux, thư viện nổi tiếng nhất về quản lý state khi code Reactjs.VueJS : Vuex, một thư viện giống Redux khi code VueJS. Vì vậy nếu nắm vững được ý tưởng của kiến trúc Flux, thì việc tiếp cận đến các libraries chuyên quản lý state rất dễ dàng. 7. Kết luận Lựa chọn framework vẫn là một chủ đề được bao quanh bởi các cuộc tranh luận. Không có đúng hay sai, chúng ta cần chọn những gì phù hợp nhất với dự án và con người trong team. Trong thực tế, có nhiều điểm khác biệt lớn giữa các frameworks, nhưng nhìn chung nắm bắt được các concepts trên sẽ giúp chúng ta làm chủ được công nghệ. Suy cho cùng, đó là mục tiêu của bài viết này, để mọi người học nhiều FrontEnd frameworks khác nhau ko còn là câu chuyện khó nữa! Author: Quan Do

                  18/04/2022

                  445

                  How-to

                  +1

                  • Software Development

                  18/04/2022

                  445

                  Những Concepts Cốt Lõi Để Trở Thành Bậc Thầy Của Mọi FrontEnd Frameworks

                  functional_error_handling_in_kotlin_with_arrow_kt_img_001-1

                  How-to

                  +0

                    Xử Lý Lỗi Theo Phong Cách Lập Trình Hàm Trong Kotlin Với Arrow-kt

                    Bài viết này sẽ giới thiệu một số cách để xử lý lỗi trong Kotlin theo phong cách lập trình hàm sử dụng thư viện Arrow-kt. Những ví dụ được đưa ra sẽ theo thứ tự từ đơn giản đến phức tạp nhưng mạnh mẽ hơn. Kotlin là một ngôn ngữ lập trình kiểu tĩnh, ban đầu được thiết kế để chạy trên máy ảo Java (JVM), sau này có thể biên dịch sang JavaScript và Native binaries sử dụng công nghệ LLVM. Kotlin có cú pháp hiện đại, ngắn gọn, an toàn và hỗ trợ cả lập trình hướng đối tượng (OOP) và lập trình hàm (FP). Arrow-kt (https://arrow-kt.io/) là một thư viện Typed Functional Programming trong Kotlin. Arrow cung cấp một ngôn ngữ chung của các interface và sự trừu tượng hóa trên các thư viện Kotlin. Nó bao gồm các kiểu dữ liệu phổ biến nhất như Option, Either, Validated, v.v … và các functional operator như traverse và computation blocks giúp cho người dùng viết các ứng dụng và thư viện pure FP dễ dàng hơn. Setup Trong file build.gradle.kts của root project, thêm mavenCentral vào danh sách: allprojects { repositories { mavenCentral() } } Thêm dependency vào file build.gradle.kts của project: val arrow_version = "1.0.1" dependencies { implementation("io.arrow-kt:arrow-core:$arrow_version") } Pure function và exceptions Pure function Trong lập trình hàm, pure function là những function có hai tính chất: Giá trị trả về chỉ phụ thuộc vào tham số truyền vào nó (tức là nếu cùng input thì cùng output).Không tạo ra các side effect. Side effect là những tác dụng xảy ra khi thực hiện một function mà không phải công dụng chính của nó. Ví dụ: ngoài việc trả về các giá trị, nó gây ra những tương tác thay đổi môi trường, thay đổi các biến toàn cục, thực hiện các hoạt động I/O như HTTP request, in dữ liệu ra console, đọc và ghi files Trong Kotlin, tất cả các function trả về Unit rất có thể tạo ra side effect. Đó là bởi vì giá trị trả về là Unit biểu thị "không có giá trị hữu ích được trả về", điều này ngụ ý rằng function không làm gì khác ngoài việc thực hiện các side effect. Một số ví dụ pure function trong Kotlin là những hàm toán học như sin, cos, max, … Lợi ích của pure functions: dễ dàng combine, dễ dàng test, dễ dàng debug, dễ dàng parallelize, … Vì thế trong lập trình hàm, chúng ta sẽ cố gắng sử dụng nhiều pure functions nhất có thể, và tách biệt các phần pure và impure. Exceptions Kotlin có thể throw và catch các Exception tương tự như ngôn ngữ Java, JavaScript, C++,… Sử dụngtry { } catch(e) { } finally { } là cách xử lý lỗi phổ biến trong các ngôn ngữ lập trình mệnh lệnh. Tuy nhiên việc throw và catch các Exception, chúng ta có thể thay đổi hành vi của function, khiến cho các function không còn pure nữa (catch Exception là một side effect). Ví dụ, một function catch hai Exception là ex1 và ex2 từ một function khác và tính toán kết quả, lúc đó kết quả đó sẽ phụ thuộc vào thứ tự thực thi của các câu lệnh, thậm chí có thể thay đổi giữa hai lần thực thi khác nhau của cùng một hệ thống. Partial function Ngoài ra, việc throw các Exception khiến cho các function trở thành một Partial function, tức là một function không hoàn toàn - không được xác định cho tất cả các giá trị input có thể có, bởi vì trong một số trường hợp, nó có thể không bao giờ trả về bất cứ thứ gì. Ví dụ, trong trường hợp một vòng lặp vô hạn hoặc nếu một Exception được throw. Ví dụ: findUserById ở ví dụ dưới là một partial function. @JvmInline value class UserId(val value: String) @JvmInline value class Username(val value: String) @JvmInline value class PostId(val value: String) data class User( val id: UserId, val username: Username, val postIds: List<PostId> ) class UserException(message: String?, cause: Throwable?) : Exception(message, cause) /** * @return an [User] if found or `null` otherwise. * @throws UserException if there is any error (eg. database error, connection error, ...) */ suspend fun findUserById(id: UserId): User? = TODO() Đề làm cho findUserById trở thành một total function, chúng ta thay vì throw UserException, chúng ta có thể return nó như một giá trị, thay return type của findUserById thành UserResult. sealed interface UserResult { data class Success(val user: User?) : UserResult data class Failure(val error: UserException) : UserResult } suspend fun findUserById(id: UserId): UserResult = TODO() Các vấn đề với Exceptions Exception có thể được xem như là những câu lệnh GOTO như trong C/C++, vì chúng làm gián đoạn luồng chương trình bằng cách quay lại nơi gọi nó. Các Exception không nhất quán, đặc biệt là khi trong lập trình Multithread, chúngta try...catch một function nhưng Exception được throw ở một Thread khác mà không thể catch nó được. Một vấn đề khác là việc lạm dụng catch Exception: catch nhiều hơn những gì cần thiết và cả những Exception từ hệ thống như VirtualMachineError, OutOfMemoryError, … try { doExceptionalStuff() //throws IllegalArgumentException } catch (e: Throwable) { // too broad, `Throwable` matches a set of fatal exceptions and errors // a user may be unable to recover from: /* VirtualMachineError OutOfMemoryError ThreadDeath LinkageError InterruptedException ControlThrowable NotImplementedError */ } Và cuối cùng, nhìn vào một signature của một function, chúng ta không thể biết được, nó sẽ throw ra Exception nào, ngoài việc đọc docs hay là đọc source code của nó, thay vào đó, chúng ta hay để signature của function đó biểu hiện rõ ràng những lỗi nào có thể xảy ra khi gọi function đó. Vì vậy, để xử lý lỗi, chúng ta cần một type có thể được compose với nhau, và biểu thị một kết quả hợp lệ hoặc một lỗi. Những type đó là Discriminated union/ tagged union, trong Kotlin đó được triển khai thông qua sealed class/sealed interface/enum class. Chúng ta sẽ cùng tìm hiểu kotlin.Result được cung cấp bởi Kotlin Sdtlib từ version 1.3 , và sau đó là arrow.core.Either đến từ thư viện Arrow-kt. Sử dụng kotlin.Result để xử lý lỗi Chúng ta có thể sử dụng Result<T> như là một type để biểu thị: hoặc là giá trị thành công với type là T, hoặc là là một lỗi xảy ra với một một Throwable. Nếu theo cách hiểu đơn giản, Result<T> = T | Throwable. Để tạo ra giá trị Result, ta có thể dụng các function có sẵn như Result.successResult.failurerunCatching (tương tự như try { } catch { }nhưng trả về Result). suspend fun findUserByIdFromDb(id: String): UserDb? = TODO() fun UserDb.toUser(): User = TODO() suspend fun findUserById(id: UserId): Result<User?> = runCatching { findUserByIdFromDb(id.value)?.toUser() } Chúng ta có thể kiểm tra Result là giá trị thành công hay không, thông qua hai property là isSuccess và isFailure. Để thực hiện các hành động ứng với mỗi trường hợp của Result thông qua function onSuccess và onFailure. val userResult: Result<User?> = findUserById(UserId("#id")) userResult.isSuccess userResult.isFailure userResult.onSuccess { u: User? -> println(u) } userResult.onFailure { e: Throwable -> println(e) } Để có thể lấy giá trị bên trong Result, chúng ta sử dụng các function getOr__. Sử dụng exceptionOrNull để truy cập giá trị Throwable bên trong nếu Result đại diện cho giá trị thất bại. Ngoài ra, còn có function fold có thể handle một trong hai case dễ dàng. val userResult: Result<User?> = findUserById(UserId("#id")) // Access value userResult.getOrNull() userResult.getOrThrow() userResult.getOrDefault(defaultValue) userResult.getOrElse { e: Throwable -> defaultValue(e) } // Access Throwable userResult.exceptionOrNull() fun handleUser(u: User?) {} fun handleError(e: Throwable) { when (e) { is UserException -> { // handle UserException } else -> { // handle other cases } } } userResult.fold( onSuccess = { handleUser(it) }, onFailure = { handleError(it) } ) Tuy nhiên, sức mạnh thực sự của Result nằm ở việc chain các hoạt động trên nó. Ví dụ: nếu bạn muốn truy cập một property của User: val userResult: Result<User?> = findUserById(UserId("#id")) val usernameNullableResult: Result<Username?> = userResult.map { it?.username } Chú ý rằng, nếu việc gọi lambda truyền vào function map throw Exception, thì Exception đó sẽ bị throw ra ngoài. Nếu muốn Exception đó được catch và chuyển thành giá trị Result, sử dụng mapCatching để vừa map vừa catching. val usernameResult: Result<Username> = userResult.map { checkNotNull(it?.username) { "user is null!" } } Một vấn đề đặt ra là làm sao để chain các Result mà phụ thuộc lẫn nhau // (UserId) -> Result<User?> suspend fun findUserById(id: UserId): Result<User?> = TODO() // User -> List<Post> suspend fun getPostsByUser(user: User): Result<List<Post>> = TODO() // List<Post> -> Result<Unit> suspend fun doSomethingWithPosts(posts: List<Post>): Result<Unit> = TODO() Chúng ta tạo một function flatMap (map và flatten). // Map and flatten inline fun <T, R> Result<T>.flatMap(transform: (T) -> Result<R>): Result<R> = mapCatching { transform(it).getOrThrow() } // or inline fun <T, R> Result<T>.flatMap(transform: (T) -> Result<R>): Result<R> = map(transform).flatten() inline fun <T> Result<Result<T>>.flatten(): Result<T> = getOrElse { Result.failure(it) } Bằng việc sử dụng flatMap, chúng ta có thể chain các Result với nhau val unitResult: Result<Unit> = findUserById(UserId("#id")) .flatMap { user: User? -> runCatching { checkNotNull(user) { "user is null!" } } } .flatMap { getPostsByUser(it) } .flatMap { doSomethingWithPosts(it) } Thư viện Arrow-kt cũng cung cấp block result { ... } để có thể handle việc chain các Result với nhau, tránh một số trường hợp sử dụng quá nhiều các nested flatMap. Trong block result { ... }, sử dụng function bind() để lấy giá trị T từ Result<T>. Nếu bind được gọi trên một Result đại diện một lỗi, thì phần code ở phía dưới nó trong block result { ... } sẽ bị bỏ qua (cơ chế short-circuits). import arrow.core.* val unitResult: Result<Unit> = result { /*this: ResultEffect*/ val userNullable: User? = findUserById(UserId("#id")).bind() val user: User = checkNotNull(userNullable) { "user is null!" } val posts: List<Post> = getPostsByUser(user).bind() doSomethingWithPosts(posts).bind() } Một số tình huống khác có thể yêu cầu các chiến lược xử lý lỗi phức tạp có thể bao gồm khôi phục hoặc báo cáo lỗi. Ví dụ, chúng ta fetch data từ remote server, nếu bị lỗi thì sẽ lấy data từ cache. Chúng ta có thể sử dụng 2 function recover và recoverCatching class MyData(...) fun getFromRemote(): MyData = TODO() fun getFromCache(): MyData = TODO() val result: Result<MyData> = runCatching { getFromRemote() } .recoverCatching { e: Throwable -> logger.error(e, "getFromRemote") getFromCache() } Sử dụng Result là một cách tiếp cận này tốt hơn, tuy nhiên vấn đề là lỗi luôn luôn là một Throwable, ta phải đọc docs hoặc đọc source code của nó. Một vấn đề nữa là runCatching khi kết hợp với suspend function, nó sẽ catch mọi Throwable, kể cả kotlinx.coroutines.CancellationException, CancellationException là một Exception đặc biệt, được coroutines sử dụng để đảm bảo cơ chế cooperative cancellation (xem issues 1814 Kotlin/kotlinx.coroutines). Một cách tiếp cận tốt hơn là sử dụng arrow.core.Either, khắc phục các nhược điểm của Result. Sử dụng arrow.core.Either để xử lý lỗi Chúng ta có thể sử dụng Either<L, R> như là một type để biểu thị: hoặc là giá trị Left(value: L) , hoặc là giá trị Right(value: R). Nếu theo cách hiểu đơn giản, Either<L, R> = L | R. public sealed class Either<out A, out B> { public data class Left<out A> constructor(val value: A) : Either<A, Nothing>() public data class Right<out B> constructor(val value: B) : Either<Nothing, B>() } Trong đó, Left thường đại diện cho các giá trị lỗi, giá trị không mong muốn, và Right thường đại diện cho các giá trị thành công, giá trị mong muốn. Nhìn chung Either<L, R> tương tự với Result<T>, Result<T> chỉ tập trung vào type của giá trị thành công mà không quan tâm đến type của giá trị lỗi, và chúng ta có thể xem Result<R> ~= Either<Throwable, R>. Either là right-biased, tức là các function như map, filter, flatMap, … sẽ theo nhánh Right, nhánh Left bị bỏ qua (được return trực tiếp mà không có hành động nào trên nó cả). Để tạo ra giá trị Either, ta có thể dụng các function có sẵn như Left constructor, ví dụ: val e: Either<Int, Nothing> = Left(1)Right constructor, ví dụ: val e: Either<Nothing, Int> = Right(1)left extension function, ví dụ val e: Either<Int, Nothing> = 1.left().right extension function, ví dụ val e: Either<Nothing, Int> = 1.right().Either.catch functions, catch các Exceptions nhưng nó sẽ bỏ qua các fatal Exceptionnhư kotlinx.coroutines.CancellationException, VirtualMachineError, OutOfMemoryError, …Và nhiều cách được cung cấp bởi arrow.core.Either.Companion. suspend fun findUserByIdFromDb(id: String): UserDb? = TODO() fun UserDb.toUser(): User = TODO() fun Throwable.toUserException(): UserException = TODO() suspend fun findUserById(id: UserId): Either<UserException, User?> = Either .catch { findUserByIdFromDb(id.value)?.toUser() } // Either<Throwable, User?> .mapLeft { it.toUserException() } // Either<UserException, User?> Chúng ta có thể kiểm tra Either là giá trị Left hay Right, thông qua hai function là isLeft() và isLeft(). Either cũng cung cấp hai function tap (tương tự onSucesscủa Result) và tapLeft (tương tự onFailure của Result). val result: Either<UserException, User?> = findUserById(UserId("#id")) result.isLeft() result.isRight() result.tap { u: User? -> println(u) } result.tapLeft { e: UserException -> println(e) } Tương tự như Result, chúng ta sử dụng các function getOrElse, orNull, getOrHandle để lấy giá trị mà Right chứa nếu nó là Right. Một số function hữu ích nữa là fold, bimap, mapError, filter, … val result: Either<UserException, User?> = findUserById(UserId("#id")) // Access value result.getOrElse { defaultValue } result.orNull() result.getOrHandle { e: UserException -> defaultValue(e) } fun handleUser(u: User?) {} fun handleError(e: UserException) { // handle UserException } result.fold( ifRight = { handleUser(it) }, ifLeft = { handleError(it) } ) Tương tự ví dụ khi sử dụng Result, chúng ta cũng muốn chain nhiều giá trị Either với nhau // (UserId) -> Either<UserException, User?> suspend fun findUserById(id: UserId): Either<UserException, User?> = TODO() // User -> Either<UserException, List<Post>> suspend fun getPostsByUser(user: User): Either<UserException, List<Post>> = TODO() // List<Post> -> Either<UserException, Unit> suspend fun doSomethingWithPosts(posts: List<Post>): Either<UserException, Unit> = TODO() Thư viện Arrow-kt đã cung cấp sẵn function flatMap và block either { ... } để có thể chain các Either với nhau dễ dàng. Trong either { ... } block, sử dụng function bind() để lấy giá trị R từ Either<L, R>. Nếu bind được gọi trên một Either chứa giá trị Left, thì phần code ở phía dưới nó trong block either { ... } sẽ bị bỏ qua (cơ chế short-circuits). import arrow.core.* class UserNotFoundException() : UserException("User is null", null) val result: Either<UserException, Unit> = findUserById(UserId("#id")) .flatMap { user: User? -> if (user == null) UserNotFoundException().left() else user.right() } .flatMap { getPostsByUser(it) } .flatMap { doSomethingWithPosts(it) } // or either block val result: Either<UserException, Unit> = either { /*this: EitherEffect*/ val userNullable: User? = findUserById(UserId("#id")).bind() val user: User = ensureNotNull(userNullable) { UserNotFoundException() } val posts: List<Post> = getPostsByUser(user).bind() doSomethingWithPosts(posts).bind() } Cuối cùng là cách khôi phục lỗi. Tương tự như recover và recoverCatching của Result, chúng ta có thể sử dụng hai function handleError và handleErrorWith (giống như flatMap nhưng theo nhánh Left). class MyData(...) suspend fun getFromRemote(): MyData = TODO() suspend fun getFromCache(): MyData = TODO() val result: Either<Throwable, MyData> = Either .catch { getFromRemote() } .handleErrorWith { e: Throwable -> Either.catch { logger.error(e, "getFromRemote") getFromCache() } } Kết luận Chúng ta đã cùng tìm hiểu Result và sau đó là Either, cả hai type giúp xử lý lỗi và làm giảm side effect. Either còn chỉ rõ về những lỗi có thể xảy ra mà chỉ cần nhìn vào signature của một function. Ngoài ra, Either hỗ trợ cho suspend function mà không làm mất đi cơ chế cancellation, và Arrow-kt cũng có module Fx (https://arrow-kt.io/docs/fx/) giúp cho việc sử dụng Kotlin Coroutines dễ dàng hơn, khi viết các chương trình async và concurrent. Hy vọng bạn thích bài viết này và hôm nay bạn đã học được điều gì đó hữu ích! Tài liệu tham khảo Arrow-kt - Either docsArrow-kt - Error handldingArrow-kt - Monad comprehensionsRock The JVM - Idiomatic Error Handling in Scala Author: st-hocnguyen

                    07/04/2022

                    433

                    How-to

                    +0

                      07/04/2022

                      433

                      Xử Lý Lỗi Theo Phong Cách Lập Trình Hàm Trong Kotlin Với Arrow-kt

                      design document

                      How-to

                      +0

                        Có cần tài liệu thiết kế (design document) trong phát triển phần mềm Agile?

                        Xin chào tất cả mọi người. Tôi là Ueki - một thành viên của SupremeTech Co.,Ltd. Với vai trò là một Phó Giám đốc tôi hỗ trợ cho các dự án phát triển về mặt quản lý với các role như Project Management Office (PMO) hay Resource Management Office (RMO). Sau khi đọc được một bài viết thú vị với chủ để mà tôi rất quan tâm là  lý do tại sao các programer không viết document , tôi đã có suy nghĩ đặt bút để viết nên bài viết này. Mục lục 1. Tại sao nhiều dự án vẫn làm việc được mà không cần đến tài liệu thiết kế? 2. Vai trò Product backlog (và những hạn chế) 3. Vai trò của Design documents 4. Bạn hiểu rõ tầm quan trọng của Design documents nhưng nó lại quá phiền phức 5. Ba mẹo để ứng dụng tốt cả Product backlog và Design documents 6. Kết thúc 1. Tại sao nhiều dự án vẫn làm việc được mà không cần đến tài liệu thiết kế? Trước khi đến Việt Nam, tôi từng là một system engineer tại một công ty SI ở Nhật Bản. Lúc đó chủ yếu các dự án phát triển theo mô hình waterfall, nên tuần tự công việc của chúng tôi sẽ là: tự viết design document, review, sau đó dựa trên design đó để tiến hành coding, tạo test cases, chạy test. Vì thế mà, tôi chưa từng nghĩ đến việc phát triển hệ thống mà không có design document. Khi chuyển công việc sang một công ty chuyên về WEB, tôi đã rất shock khi thấy một số project vẫn chạy bình thường mà không hề có design document. Chuyện xảy ra một thời gian trước đây khi tôi còn làm ở một công ty Offshore ở Việt Nam. Khi đó, tôi có tham gia vào một dự án từ Phase 2. Tôi có nhờ Project manager (PM) phụ trách Phase 1 chia sẻ cho tôi tài liệu về design document thì lại nhận được URL của một tool quản lý task có tên là Redmire, tool này được dự án sử dụng để quản lý Product Backlog. PM đó nói với tôi rằng tất cả yêu cầu đều được mô tả trong ticket Redmine, nên đó chính là design document. Lúc đó, khi tôi đặt ra câu hỏi “Nếu yêu cầu có thay đổi thì có update trong ticket đó không? “. Câu trả lời tôi nhận được là “Trong trường hợp đó, sẽ tạo ticket mới”. Nếu như vậy thì chẳng phải sẽ có trường hợp yêu cầu của 1 màn hình có thể bị trải dài ra nhiều ticket khác nhau, và ngược lại yêu cầu của nhiều màn hình có thể chỉ được gom lại trong một ticket hay sao? Như vậy thì những ticket Redmine đó không thể làm vai trò của một design document được. Bỏ qua nhiều câu hỏi trong đầu, cuối cùng tôi đã bỏ ra vài tuần để tạo lại từ đầu design document của Phase1, trước khi bắt đầu Phase2.  Người PM mà tôi vừa nhắc đến cũng là một thành viên thuộc team PMO của công ty, đến cả một người ở level này và có nhiều kinh nghiệm như thế mà cũng chấp thuận và làm theo cách này, quả thật lúc đó tôi đã rất shock. Thế nhưng, nếu như đã quen với mô hình phát triển Agile, họ chỉ cần nhận được tài liệu khái quát từ khách hàng, Product backlog hay whiteboard, thông qua việc thảo luận với khách hàng, họ sẽ không cần đến design document mà vẫn có thể tiến hành coding, do đó, dù ko nắm được tầm quan trọng của design document hay sự khác biệt giữa Product Backlog và design document thì họ vẫn có thể phát triển dự án được.  Ở bài blog tôi có nói đến ở phần đầu cũng đã viết “cho dù không có document cũng không có trở ngại gì cả”, nhưng đó lại là sự thật. Vậy nên, nếu không cần design document mà vẫn có thể phát triển được thì design document cũng trở nên không cần thiết nữa sao? Có thật sự không cần đến design document nếu đã có Product backlog không? Thực ra, Product backlog và design đều được mô tả bằng chung một từ là “specification” nhưng vai trò của nó lại khác nhau. Nói cách khác, không phải cái nào tốt hơn cái nào, mà là cả hai đều cần thiết cho các mục đích khác nhau.  2. Vai trò của Product backlog (và những hạn chế khi sử dụng nó như một tài liệu thiết kế) Ở SupremeTech, chúng tôi quản lý các Product backlog bằng các tool quản lý ticket như Backlog, Github issue, Redmine. Chúng tôi sẽ quản lý 1 product backlog bằng những tickets được PO tạo ra, khi cần thiết sẽ cùng thảo luận, đặt Q&A ở phần comment, sau đó sẽ bổ sung những nội dung được quyết định cuối cùng vào phần overview của ticket đó. Trong mô hình phát triển mà yêu cầu thường không được rõ ràng ở giai đoạn đầu như Agile, thì phương pháp này rất có hiệu quả và cho phép nhiều bên liên quan (Stakeholders) tham gia vào quá trình xây dựng yêu cầu để yêu cầu được tốt hơn. Những product backlog item (PBI) đã hoàn thành sẽ được close, nếu có yêu cầu thay đổi thì sẽ tạo một ticket mới để các kĩ sư có thể chỉ cần tập trung vào phần hiện tại mình làm. Vì có thể nhìn thấy được số lượng ticket, nó sẽ giúp bạn lên schedule dễ dàng hơn dựa theo estimate và cũng có thể thúc đẩy các engineer làm việc hiệu quả hơn thông qua các mục tiêu đã đề ra. Quản lý Product backlog bằng Github issue Mặt khác, nếu chỉ quản lý bằng  Product backlog, sẽ có những câu hỏi chỉ có thể trả lời bằng kí ức phát sinh như là “đâu là spec đúng hiện tại” hay “cái nào mới chính xác”. Ví dụ ở Product backlog có những thông tin như sau: 1. Muốn develop màn hình A bao gồm các function A-1, A-2, A-3 2. Log các yêu cầu của màn hình A ở ticket ① 3. Engineer tiến hành develop → Close ticket ① 4. Thay đổi spec ở function A-1 và A-2 ở màn hình A 5. Log các yêu cầu thay đổi của function A-1, A-2 ở ticket ② 6. Engineer tiến hành develop → Close ticket ② 7. Thay đổi spec ở function A-2 ở màn hình A 8. Log các yêu cầu thay đổi của function A-2 ở ticket ③ 9. Engineer tiến hành develop → Close ticket ③ Ở đây, nếu bạn muốn kiểm tra spec chính xác của màn hình A, bạn cần phải tìm tất cả các ticket ①②③  đã close và sắp xếp chúng theo thứ tự thời gian. (Trong ví dụ này, spec đúng của màn hình A bao gồm function A-1 được log ở ticket ②, function A-2 được log ở ticket ③ và function A-3 được log ở ticket ①). Các ticket đã close có thể được tìm thấy bằng cách search trên tool quản lý ticket, nhưng nếu search bị sót 1 thông tin gì đó hoặc kết hợp sai, thì spec sai sẽ bị nhầm thành spec đúng. Nếu bạn cố gắng xây dựng spec mới dựa theo cái đã bị nhầm trước đó, sự nhầm lẫn qua lại sẽ ngày một tăng lên. Product backlog không phải vạn năng Cũng có cách để tách ticket cho từng function A-1, A-2, A-3, nhưng ở ví dụ này nó chỉ là một function, và spec có thể thay đổi ngay cả chỉ với một image hay một button, vì vậy sẽ không thực tế nếu chia các yếu tố thành ticket được. Cũng có ý kiến ​​cho rằng "những gì được viết trong code mới là đúng", và nó có thể đúng trong trường hợp bây giờ, nhưng chưa chắc đã đúng hết như thế. Vì không có gì đảm bảo rằng không có bug xảy ra nên không thể cho răng nội dung code là spec đúng được. 3. Vai trò của design document Vậy tại sao chúng ta cần phải cần có một spec đúng? Bạn hoàn toàn có thể implement dựa trên nội dung ghi trong Product backlog, nhưng chỉ nên duy trì điều đó trong một thời gian ngắn. Ở mô hình phát triển Agile, chúng ta sẽ bắt đầu phát triển với một mô hình hệ thống nhỏ tối thiểu, thường trước hết chúng ta sẽ release MVP (Minimum Viable Product: Sản phẩm khả dụng tối thiểu), và liên tục cải thiện trong thời gian dài dựa theo feedback của người dùng. Trường hợp các member tham gia dự án ngay từ đầu, nắm rõ ngọn ngành và spec thì có thể duy trì dự án mà không gặp vấn đề gì với Product backlog, tuy nhiên nếu có member mới join vào, hoặc ngược lại, các member cũ rời khỏi dự án vì nhiều lý do, thì khó có thể tránh khỏi nhiều hiểu lầm xảy ra nếu dự án được tiếp tục duy trì lâu dài. Khi đó, cần phải có design document với những yêu cầu cơ bản chính xác và mới nhất ở thời điểm hiện tại để không phải chỉ truyền đạt với nhau bằng miệng. Trước hết, trí nhớ của con người không phải lúc nào cũng hoàn chỉnh (duy trì thông tin đầy đủ và nhất quán), nên điều quan trọng là phải có một nơi (tài liệu) lưu giữ thông tin chính xác (source of truth) thay vì dựa vào trí nhớ. Vì design là nội dung đã được thống nhất thông qua review của client và engineer, nên nếu có action nào khác với description trong product, thì có thể là bug hoặc đã bỏ sót thông tin. Tóm lại, Product backlog hữu ích trong vòng đời phát triển (life cycle develop) ngắn hạn, còn design document có thể được coi là công cụ cần thiết để lưu trữ lâu dài. Cần phân biệt giữa Product backlog và design 4. Bạn hiểu rõ tầm quan trọng của Design document nhưng nó lại quá phiền phức Tôi sẽ tạm dừng phần giải thích về vai trò của Product backlog hay design document ở đây. Các engineer thường hay nói "Tôi hiểu design document rất quan trọng, nhưng tôi không có thời gian để tạo chúng", hoặc "Nó không thú vị bằng viết code (tôi không có hứng thú)." Những người như vậy thường tránh viết tài liệu vì họ muốn tập trung coding trong một khoảng thời gian đã được đề ra, nhưng nếu cứ tránh thì họ sẽ không tiến bộ và sẽ tạo nên một vòng luẩn quẩn ngày càng muốn né tránh. Ở SupremeTech, chúng tôi phân chia và triển khai đầu công việc thành hai mảng là document và coding với hệ thống resource gồm có Business Analyst (BA) - người sẽ cùng với client và engineer triển khai yêu cầu thành Product backlog, design document, và Software Engineer (SE) - người sẽ phát triển phần mềm dựa trên những yêu cầu đó. Việc tạo design document thường tập trung chủ yếu vào phase 0 đến 1 trong thời gian đầu của project, và một khi design document được tạo xong, phần còn lại chỉ là update các phần cần thay đổi, vì vậy giả sử bên SE phải update thì rào cản tâm lý cũng sẽ giảm đi đáng kể, do phần tài liệu mà họ cần phải làm chỉ là phần update. Việc tạo design document ban đầu là một trong những nhiệm vụ của BA và thông qua quá trình này, họ có thể nắm được yêu cầu và hỗ trợ cho project với tư cách là spec holder. Mặc dù vậy, khi quy mô MVP lớn hoặc trong trường hợp tiến hành dự án đã được phát triển từ phía công ty khác nhưng lại không có design document thì gánh nặng cho BA sẽ rất lớn. Trong trường hợp đó, Japanese Communicator (JC) sẽ đảm nhiệm phần biên/phiên dịch để có tạo ra design. Trong career path của chúng tôi, những JC sau này đều sẽ có hướng phát triển thành BA nên điều này cũng vừa có ích cho việc đào tạo công việc BA cho JC để phát triển trong tương lại. Bằng cách phân chia công việc như thế này, việc tạo/ duy trì design document được thực hiện như yếu tố cần thiết để phát triển phần mềm, tương tự như coding của SE, hoặc việc phân chia task, lập kế hoạch và quản lý tiến độ của PM là không thể thiếu. 5.  Ba cách để ứng dụng tốt cả Product Backlog và Design document Trước đây khi còn là Senior BA tại công ty phát triển phần mềm Offshore tại Việt Nam, cũng đã từng điều hành dự án sử dụng cả Product backlog và Design. Nên tôi muốn giới thiệu cho mọi người một số mẹo mà cá nhân tôi thấy dễ thực hiện. 1. Update timing Product backlog được sử dụng để thiết lập spec trong life cycle develop ngắn hạn nên thường xuyên được update. Mặt khác, design document dùng để duy trì lâu dài không yêu cầu phải cập nhật realtime, nên tôi nghĩ nó có thể sắp xếp thời gian để update nó khi mà yêu cầu đã ổn định hơn, không còn thay đổi nhiều nữa. Cụ thể, thời điểm SE bắt đầu coding, hay thời điểm tiếp nhận yêu cầu từ client, yêu cầu sẽ được đưa lên Product backlog, sau đó chúng ta mới tiến hành update design document. Tất nhiên, điều này không áp dụng nếu project được phát triển dựa hoàn toàn trên design document. 2. Sử dụng tool Bạn nên sử dụng tool quản lý ticket để có thể quản lý Product backlog. Có rất nhiều tool khác nhau như Backlog, Github issue, Redmine,… nhưng bạn có thể lựa chọn tuỳ thích miễn là tool đó có thể assign function, set milestones, change status, change notifications. Github issues có thể sẽ hữu ích cho engineer khi họ còn có thể sử dụng Github để quản lý task và code version cùng 1 chỗ. Tôi thường thấy nhiều trường hợp sử dụng Spreadsheet để quản lý Product backlog, nhưng tôi nghĩ đây lại là một antipattern. Ở life cycle develop ngắn hạn hay được update thường xuyên, Spreadsheet lại không có function thông báo về các cập nhật, nên khả năng sẽ xảy ra nguy cơ không để ý và bỏ quên nội dung nếu có ai đó add/change/delete chúng. Hơn nữa, so với Product backlog, ta thường sử dụng Spreadsheet cho các design có tần suất update thấp. Các thay đổi sẽ bị lưu lại trên sheet lịch sử thay đổi. Cũng có ý kiến khắt khe cho rằng không nên sử dụng Spreadsheet cho bất cứ cái gì ngoại trừ cho bảng tính (excel), nhưng tôi nghĩ dùng công cụ gì cũng được miễn là nó được sử dụng một cách thích hợp với nhu cầu trên thực tế. 3. Có cần tách riêng giữa client và internal không  Tốt hơn là nên tách Product backlog thành một bên cho client (client và BA sử dụng) và một bên cho internal (Project members như BA, PM, SE sử dụng). Đầu tiên phải kể đến vấn đề ngôn ngữ. Việc chuẩn bị product backlog cần những  đổi phức tạp, hoặc mang tính khái quát cao về product sẽ như thế nào, nên nhiều trường hợp client muốn thảo luận bằng ngôn ngữ mẹ đẻ (tiếng Nhật hoặc tiếng Anh) càng nhiều càng tốt. Nhưng kĩ sư người Việt lại không sử dụng thành thạo tiếng Nhật hoặc tiếng Anh giao tiếp, nên Communicator sẽ phải dịch sang tiếng Việt hoặc tiếng Anh, và như thế nhiều ngôn ngữ sẽ bị trộn lẫn và đoạn hội thoại sẽ trở nên khó đọc. Tiếp theo là vấn đề về độ chính xác, chi tiết của thông tin. Việc spec thay đổi thường xảy ra trong quá trình thảo luận, nhưng có nguy cơ là PBI của client được bắt đầu triển khai sớm ngay cả khi yêu cầu đó vẫn đang trong giai đoạn thảo luân, dẫn đến phải làm lại. Ngoài ra, nếu nhiều yêu cầu được thảo luận trong một ticket hoặc ngược lại, các yêu cầu tương tự được thảo luận trong nhiều ticket, thì phải tách riêng/ tổng hợp nếu cần và sau đó truyền đạt lại cho kĩ sư, như thế sẽ tránh hiểu sai về nội dung công việc. Từ những điểm trên, chúng tôi đã áp dụng phương pháp tách từng tool và quản lý Product backlog cho client giao tiếp bằng tiếng Nhật và Product backlog cho internal giao tiếp bằng tiếng Anh hoặc tiếng Việt. Mặt khác, vì cần phải có được sự thống nhất của cả client và engineer sau khi tạo xong design document, nên sẽ tốt hơn nếu viết bằng tiếng Anh trên Spreadsheet chung để mọi người có thể cùng thấy. Nếu dịch những gì đã tạo từ tiếng Nhật sang tiếng Việt, bạn sẽ phải quản lý 2 phiên bản tiếng Nhật và tiếng Việt, và nếu có một bản được chỉnh sửa, nhưng bản kia lại bị sót, thì khả năng hiểu sai spec giữa client và engineer sẽ xảy ra. Dù được viết bằng tiếng Anh, design cũng chỉ đơn giản là mô tả các yêu cầu với nội dung giải thích dài thành một câu giải thích ngắn hơn, nên trừ khi client của bạn là người không thích tiếng Anh, thì nó vẫn có thể chấp nhận được. Luồng thực hiện khi tóm tắt Tips 1-3 Flow hoạt động này chỉ là phương pháp hay nhất từ ​​kinh nghiệm của riêng tôi nên không có nghĩa là sẽ áp dụng được trong mọi tình huống. Cơ bản, tôi nghĩ sẽ không sao khi lựa chọn work flow hay tool dựa trên đặc điểm của từng dự án, sở thích và kinh nghiệm của các bên liên quan (stakeholder), hoặc là quan điểm tôn giáo (^^). Nếu design documentation hiện tại của bạn không hữu dụng nhiều, bạn có thể lấy cách làm này để tham khảo. 6. Kết thúc Bài viết này dùng để truyền đạt vai trò của design document và cách tương tác cho những bạn không hiểu vì sao lại cần design document hoặc những bạn đang gặp vấn đề về cách vận dụng nó. Ngay cả ở công ty SupremeTech, tôi cũng muốn hỗ trợ và truyền đạt cho các member của chúng tôi có thể nhận thức rõ tính quan trọng của design document và những rủi ro khi không có nó, cũng như để phân bổ nguồn nhân lực cần thiết. ※ Bài viết này được phiên dịch từ bản tiếng Nhật được viết trên Enlyt Blog.

                        27/08/2021

                        898

                        How-to

                        +0

                          27/08/2021

                          898

                          Có cần tài liệu thiết kế (design document) trong phát triển phần mềm Agile?

                          Customize software background

                          Want to customize a software for your business?

                          Meet with us! Schedule a meeting with us!