[Design Patterns #2] Singleton Pattern

Nguồn: https://cppdeveloper.com/design-patterns/design-patterns-1-singleton-pattern/

Bài toán cần giải quyết

(Tình huống giả định)

—–

Tôi là chuyên gia về thiết kế phần mềm ở công ty XYZ và tôi đang phải xử lý một vấn đề liên quan đến performance – hiệu suất.

“Hệ thống của mình đang chạy chậm vãi chưởng anh ạ !” – Technical Leader của dự án nói với tôi.

“Anh đã check thử và để ý thấy rằng database object của các chú đang có kích thước rất lớn, tận gần 20MB.”

“Vâng.”

“Khi hệ thống đang chạy thì có khoảng bao nhiêu database object ?”

“Khoảng 200 anh ạ.”

“Đm, vãi, 200 nhân với 20MB, các chú không thấy vấn đề gì ở đây à ?”

“Dạ không ạ.”

“Các chú đang sử dụng quá nhiều tài nguyên hệ thống. Có cả trăm object với kích thước lớn (~20MB) được khởi tạo trong bộ nhớ RAM. Trong khi server chạy App chỉ có 4GB RAM, dùng full cả RAM thì nó chả chậm. Có thực sự cần nhiều database object như vậy không ?”

“Bla bla…”

“A nghĩ là dell cần đâu… Thôi được rồi, vấn đề này phải xử lý bằng Singleton Pattern.”

—–

Trong bài này chúng ta sẽ nói về vấn đề việc kiểm soát số lượng đối tượng trong chương trình để tối ưu hóa việc sử dụng tài nguyên hệ thống sử dụng Singleton Pattern. Với một class theo Singleton Pattern, chỉ có tối đa một đối tượng cụ thể của class đó được khởi tạo xuyên suốt chương trình.

Chỉ khởi tạo một đối tượng với Singleton Pattern

Quay trở lại với bài toán bên trên, các lập trình viên đang tạo ra hàng trăm Database objects khi chương trình chạy, trong khi đó kích thước của mỗi object rất lớn (lên đến gần 20MB). Chúng ta sẽ cùng nhau sử dụng Singleton Pattern để giải quyết vấn đề này.

Mục đích chính của Singleton Pattern là đảm bảo chỉ có thể tạo ra một object của một class cụ thể. Nếu chúng ta không sử dụng pattern này thì với mỗi toán tử new hoặc lệnh khai báo đối tượng như sau, chương trình sẽ tạo ra các object khác nhau của cùng một class.

Singleton Pattern sẽ đảm bảo chỉ có tối đa một object của class được tạo ra trong chương trình cho dù bạn cố gắng tạo đối tượng mới bao nhiêu lần đi nữa. Dó đó bạn nên sử dụng Singleton Pattern khi bạn muốn hạn chế việc sử dụng tài nguyên (thay vì tạo số lượng đối tượng lớn không giới hạn) hoặc bạn muốn có một object chứa dữ liệu chia sẻ cho cả hệ thống (ví dụ: registry, logging, caching,…).

Việc chỉ tạo một object cũng có ý nghĩa khá quan trọng khi bạn phát triển ứng dụng đa luồng (multithreading) và không muốn bị xung đột trong việc truy cập data khi có nhiều object của cùng một class cùng hoạt động. Với trường hợp làm việc với database objects và có nhiều thread, mỗi thread tạo ra database object riêng của nó, tất cả các objects này đều truy cập chung một data store bên dưới. Khi đó việc xảy ra lỗi do xung đột truy cập dữ liệu cùng lúc là hoàn toàn có thể xảy ra.

Demo Code

*** Tạo Singleton database class

Chúng ta sẽ bắt đầu với class có tên là Database → 

Tiếp tục, chúng ta thêm 2 methods là editRecord (dùng để edit record trong database) và getName (trả về tên của database) → 

Ok tạm ổn. Tuy nhiên vấn đề về việc khởi tại nhiều object của class Database vẫn chưa được giải quyết. Đoạn code sau sẽ tạo ra 3 Database objects trong hệ thống → 

Vậy làm thế nào để ngăn chặn việc tạo object mới với mỗi câu lệnh new (hoặc khai báo biến) như trên ?

Câu trả lời: hãy để contructor của Database private → 

Bây giờ thì không ai có thể tạo object của class Database ở bên ngoài class này một cách tùy tiện được nữa.

Chờ đã… What the fuck ?? Vậy làm thế dell nào tạo được object của class này để mà dùng đây ?

OK. Chúng ta cần tạo một static method có tên là getInstance() dùng để tạo object của class Database, method này sẽ call đến constructor của Database (vì method này là hàm của class nên nó được phép call đến hàm private). Ngoài ra hàm này cũng chịu trách nhiệm đảm bảo chỉ có duy nhất một object của class được tạo ra trong hệ thống → 

Ngoài việc thêm hàm getInstance() chúng ta cũng cần thêm một biến member static là mInstancePtr – là con trỏ sẽ trỏ đến object duy nhất của Database. Hàm getInstance() sẽ phải kiểm tra object đã tồn tại chưa, nếu chưa tồn tại thì tạo object mới và gán mInstancePtr trỏ vào object đó, sau đó trả về mInstancePtr. Nếu object đã tồn tại (mInstancePtr khác nullptr) thì trả về mInstancePtr luôn mà không tạo object mới.

Như vậy vấn đề vấn đề đã được giải quyết 99% (còn 1% liên quan đến đa luồng sẽ thảo luận sau), chỉ có duy nhất một object cúa class Database tại một thời điểm. Call hàm getInstance() sẽ lấy được object của Database, và tất cả object đó vẫn chỉ là một object duy nhất mà thôi.

*** Test Singleton Database class

Để test class Database, mình sẽ tạo hàm main như bên dưới → 

Chạy chương trình sẽ cho ra kết quả trên console như sau → 

Từ kết quả chúng ta có thể nhận thấy rằng 2 lần call hàm getInstance() đều trả về con trỏ của cùng một object.

Xem xét vấn đề đa luồng (multithreading) trong Singleton Pattern

Hãy cùng xem xét lại hàm getInstance() của class Database → 

Có một lỗ hổng tiềm ẩn nguy hiểm ở đây. Chúng ta muốn đảm bảo rằng chỉ có duy nhất 1 object của class Database có thể được tạo ra. Nhưng nếu chương trình có nhiều threads cùng chạy một lúc và cùng call đến hàm getInstance() tại cùng thời điểm, chúng ta có thể gặp rắc rối ở đây. Lỗ hổng ở đây nằm ở câu lệnh check null con trỏ mInstancePtr.

Giả sử có 2 threads cùng call đến hàm getInstance() một lúc và lúc đó chưa có object nào của class Database được tạo. Khi đó có thể xảy ra trường hợp câu lệnh “if (nullptr == mInstancePtr)” ở cả 2 threads đều “true”, và cả 2 threads đều tạo ra object mới.

Để ngăn chặn lỗi này chúng ta có 2 phương pháp:

  1. Sử dụng mutex để đồng bộ xử lý của các threads
  2. Tạo object tĩnh ngay từ lúc khởi chạy chương trình (trước khi vào hàm main)

*** Sử dụng mutex để đồng bộ xử lý của các threads

Từ C++11 chúng ta có thể sử dụng mutex trong thư viện chuẩn, file header là <mutex>.

Trước khi check null mInstancePtr và tạo object mới (nếu chưa tồn tại) ta cần call hàm lock() của mLocker (một biến member kiểu mutex của Database) và sau khi thực hiện xong thì call hàm unlock() → 

*** Tạo object tĩnh ngay từ lúc khởi chạy chương trình (trước khi vào hàm main)

Chạy chương trình này vẫn cho ra kết quả như lúc trước. Điểm khác biệt lớn nhất ở đây là object của Database được tạo ra ngay từ đầu chương trình chứ không phải tạo ở lần đầu tiên call hàm getInstance()

— Phạm Minh Tuấn (Shun) —

 

Ngành lập trình nhúng trên ô tô và cơ hội cho các lập trình viên Việt Nam

Nguồn bài viết: https://cppdeveloper.com/tech360/nganh-lap-trinh-nhung-tren-o-to-va-co-hoi-cho-cac-lap-trinh-vien-viet-nam/

Sơ lược về hệ thống nhúng trên ô tô (Automotive Embedded Systems)

Ngành công nghiệp ô tô hiện nay là nền kinh tế lớn thứ sáu trên thế giới, sản xuất hàng chục triệu xe mỗi năm và đóng góp quan trọng vào thu nhập của các chính phủ trên toàn thế giới. Và ngày nay thì công nghệ điện tử và phần mềm đang đóng góp rất lớn trong việc cải thiện về tính năng, hiệu suất, sự thoải mái và an toàn của xe ô tô. Kể từ năm 1990 thì lĩnh vực phần mềm nhúng (embedded sofware) vẫn đang tăng trưởng với tỉ lệ hàng năm là 10%.

Năm 2004, hệ thống điện tử nhúng của một chiếc xe Volkswagen Phaeton bao gồm hơn 10.000 thiết bị điện, 61 vi xử lý, 3 mạng CAN (controller area networks) hỗ trợ trao đổi dữ liệu giữa các vi xử lý. Trong khi đó Volvo S70 có 2 networks hỗ trợ giao tiếp giữa các vi xử lý điều khiển gương, điều khiển cửa xe và hệ thống điều khiển truyền động. Vị trí của các gương được điều khiển tự động theo cảm giác xe chạy và âm lượng của radio được điều chỉnh theo tốc độ xe được cung cấp bởi hệ thống chống bó cứng phanh (ABS). Vào năm 2006 thì giá thành của một hệ thống nhúng (bao gồm cả điện tử và phần mềm) chiếm khoảng 25% tổng giá thành của 1 chiếc xe (đối với dòng xe cao cấp là khoảng 35%).

Ngành công nghiệp ô tô đã phát triển nhanh chóng và sẽ phát triển nhanh hơn nữa dưới sự tác động của một số yếu tố như áp lực từ các quy định của luật pháp (liên quan đến khí thải, môi trường), áp lực từ phía khách hàng, áp lực về tiến bộ công nghệ (cả khía cạnh phần cứng và phần mềm). Đã có một sự thay đổi lớn trong việc phát triển các hệ thống điều khiển điện tử xuất phát từ vấn đề liên quan đến ô nhiễm không khí. Người dùng thì đòi hỏi xe có hiệu suất cao hơn (ở mức tiêu thụ nhiên liệu thấp hơn), thoải mái và an toàn hơn. Và chỉ có tiến bộ và đột phá về công nghệ mới có thể giải quyết và đáp ứng được các yêu cầu này.

Công nghệ điện tử đã có những bước tiến lớn và ngày nay, chất lượng của các thành phần điện tử bao gồm hiệu suất, độ bền và độ tin cậy đã cho phép chúng ta sử dụng chúng ngay cả đối với các hệ thống quan trọng. Đồng thời, chi phí giảm dần của công nghệ điện tử cho phép chúng được sử dụng để hỗ trợ bất kỳ chức năng nào trong xe hơi. Hơn nữa, trong thập kỷ qua, một số networks nhúng trong ô tô (automotive-embedded networks) như LIN, CAN, TTP / C, FlexRay đã được phát triển với ưu điểm chính là giúp giảm đáng kể chi phí về dây dẫn kết nối và tăng tính linh hoạt (ví dụ: tốc độ xe được đo bởi một con vi điều khiển và dữ liệu được truyền đến các vi điều khiển khác qua networks).

Một lý do công nghệ khác cho sự phát triển của các hệ thống nhúng ô tô là do các công nghệ này có thể làm được chức năng mà sẽ tốn kém hoặc thậm chí không khả thi nếu chỉ sử dụng công nghệ cơ khí hoặc thủy lực. Do đó, cho phép đáp ứng các yêu cầu của người dùng cuối về sự an toàn, thoải mái và cả chi phí. Các ví dụ điển hình là hệ thống chống bó cứng phanh (ABS – Anti-lock Braking System), chương trình cân bằng điện tử (ESP – Electronic Stability Program), hệ thống treo chủ động,… Tóm lại, nhờ những công nghệ này, khách hàng có thể mua một chiếc xe an toàn, hiệu quả và có thể được cá nhân hóa phù hợp với sở thích hơn.

Các Domains chính trong Automotive Embedded Systems

Các nhà sản xuất xe hơi đưa ra 5 Domains (tạm hiểu là các nhóm chức năng) chính cho các thiết bị điện tử nhúng trong xe hơi bao gồm: Power trainChassisBodyHMI và Telematics.

  • Power train domain liên quan đến chức năng điều khiển chuyển động của xe bao gồm các động cơ, hệ thống truyền động, tăng tốc, giảm tốc.
  • Chassis domain liên quan đến điều khiển lái (vị trí và hướng di chuyển của bánh), phanh.
  • Body domain bao gồm các thành phần không liên quan trực tiếp đến chuyển động của xe như: túi khí, cần gạt nước, đèn đóm, điều hòa, …
  • HMI domain bao gồm các thiết bị (màn hình hiển thị, nút bấm) dùng để trao đổi thông tin giữa hệ thống điện tử của xe và người dùng (lái xe và hành khách). HMI bao gồm nhiều hệ thống nhỏ như Head Unit (chứa hệ thống thông tin giải trí, nghe nhạc, xem video, dẫn đường, …), Instrument Cluster (hệ thống hiển thị thông tin cụm đồng hồ), HUD – Head Up Display (hệ thống hiển thị các thông tin như tốc độ, dẫn đường trên kính, thẳng mặt lái xe, giống kiểu trên máy bay ý anh em ạ)
  • Telematics domain là hệ thống trao đổi thông tin giữa xe với thế giới bên ngoài, có thể là giữa xe với xe, giữa xe với cơ sở hạ tầng và dịch vụ xung quanh.

Trong 5 domains ở trên thì hiện nay phần lớn anh em lập trình viên Việt Nam mới chỉ được làm phần HMI và Telematics. Trong đó chủ yếu là HMI, Telematics chiếm phần nhỏ. Lý do là vì 2 domains này không liên quan trực tiếp đến tính mạng, an toàn của người dùng (LOL).

Head Unit

Cluster

HUD – Head Up Display

Có lẽ chém vĩ mô về hệ thống nhúng trên ô tô như vậy thôi, giờ sẽ sang phần tiếp theo là tình hình công việc về Automotive Embedded Systems tại Việt Nam giờ ra sao nhé.

Tình hình công việc về Automotive Embedded Systems tại Việt Nam

Ở Việt Nam hiện nay, nói đến ô tô thì không thể không nhắc đến VINFAST, công ty đi đầu trong việc sản xuất ô tô mang thương hiệu Việt. Và tất nhiên VINFAST có tham vọng đưa người Việt làm chủ công nghệ ô tô của VINFAST trong đó bao gồm cả hệ thống nhúng trên ô tô. Tuy hiện tại chưa thể tự sản xuất nhưng VINFAST đã có những viện nghiên cứu về hệ thống nhúng trên ô tô với rất nhiều chuyên gia Tây lông cũng như những kỹ sư Việt Nam rất giỏi. Do đó có thể nói, với tiềm lực về kinh tế của mình, nói về công nghệ hệ thống nhúng trên ô tô, VINFAST có lẽ là mạnh nhất Việt Nam dù mới thành lập được 2 năm.

Trước khi sang VINFAST R&D và bây giờ chuyển sang Viện Công Nghệ Ô Tô của VINFAST thì mình làm lập trình Embedded ở FPT Software. Theo mình biết thì từ đầu những năm 2010 trở đi thì FSOFT đâu đó đã có những dự án làm về Automotive với một số khách hàng Nhật nhưng quy mô còn nhỏ, việc chủ yếu là Demo, nói chung là chủ yếu làm le ve, vừa học vừa làm. Năm 2012 đến 2014 thì FSOFT đã có được những dự án lớn và thử thách hơn, nhưng đến năm 2015 thì mảng công việc về nhúng trên ô tô mới thật sự bùng nổ với rất nhiều dự án lớn của các khách hàng Nhật, Hàn. Cho đến nay thì mảng công việc này tại FSOFT cũng vẫn đang rất hot và có nhiều dự án, FSOFT thậm chí còn thành lập một đơn vị riêng chuyên về Automotive đó là FGA – FPT Global Automotive.

Ngoài VINFAST, FSOFT thì ở Việt Nam mình biết có 2 công ty lớn khác cũng đang làm trong lĩnh vực Automotive. Đó là:

  • LG VS DCV – LG Vehicle Component Solutions Development Center Vietnam: Là một thành viên của Công ty TNHH LG Electronics Việt Nam Hải Phòng (LGEVH). Địa điểm tại tầng 34, 35 tòa nhà Keangnam – Hà Nội. Chuyên phát triển hệ thống thông tin giải trí trong ô tô (In-Vehicle Infotainment) như: hệ thống hiển thị thông tin cụm đồng hồ (Clusters), hệ thống nghe nhìn và dẫn đường (Audio Video Navigation), hệ thống trợ lái tiên tiến (Advanced Driver Assistant System), Telematics. Hiện đang làm các dự án của các công ty lớn như GM, BMW, Huyndai. Lương lậu ở đây KHÁ ngon so với mặt bằng chung.
  • Panasonic R&D Center Vietnam: Là công ty con của công ty Panasonic Việt Nam trực thuộc tổng công ty Panasonic Nhật Bản. Địa điểm: Tầng 17, Tháp Đông, Tòa nhà Lotte Center Hà Nội, 54 Liễu Giai, Cống Vị, Ba Đình, Hà Nội. Cũng làm một số các hệ thống nhúng trên ô tô theo yêu cầu từ công ty mẹ bên Nhật. Theo đánh giá của mình thì không mạnh mẽ bằng LG VS DCV. Mình từng đi phỏng vấn ở đây và passed nhưng thấy lương trả khá bèo, không ăn thua lắm.

Hiện nay ngành Automotive Embedded ở Việt Nam đang có rất nhiều cơ hội và cũng đang rất khát nhân lực bao gồm lực lượng Developer, Tester. Đối với các công ty outsourcing như FSOFT thì họ còn thiếu nhân lực BrSE (kỹ sư cầu nối) làm việc tại Nhật Bản, Hàn Quốc nữa (làm BrSE được trải nghiệm cuộc sống nước ngoài, lương cũng ngon hơn trong nước). Lương BrSE của FSOFT trong ngành Automotive này theo mình biết thì thường nằm trong khoảng 200~350.000 yên / tháng tùy năng lực và kinh nghiệm, tiền nhà và đi lại công ty hỗ trợ. Còn Hàn Quốc thì chưa đi bao giờ nên không biết.

Để làm về Automotive Embedded Systems thì cần kiến thức chuyên môn gì ?

*** Ngôn ngữ lập trình

Đầu tiên về ngôn ngữ lập trình thì chủ yếu dùng C/C++ để phát triển ứng dụng nhúng chạy trên các thiết bị nằm trên ô tô (Head Unit, Cluster, HUD). Ngoài ra thì còn sử dụng một số ngôn ngữ khác như C#, NodeJs, Python, … để phát triển tools hỗ trợ và tự động hóa quá trình phát triển và kiểm thử. Ví dụ như các tools để tự động generate code C/C++, tools giả lập tín hiệu CAN cho mục đích testing, tool update firmware,… nói chung là đủ các thể loại.

Chính vì vậy nắm vững kiến thức về C/C++ là yêu cầu tiên quyết và quan trọng nếu bạn muốn trở thành lập trình viên cho ngành này. Biết thêm các ngôn ngữ khác sẽ là điểm cộng và là lợi thế giúp bạn nhanh chóng tạo ra sự khác biệt so với các đồng nghiệp khác.

*** Hệ điều hành

Hệ điều hành chạy trên hệ thống nhúng của ô tô chia làm 2 loại chính là RTOS (Real Time OS) và Non-RTOS.

  • RTOS bao gồm các OS như Windows CE, QNX, INTEGRITY, iTRON, FreeRTOS.
  • Non-RTOS thì có Linux, Android (cho automotive, khác với Android trên smartphone).

RTOS thường có kích thước nhỏ và được dùng cho các thiết bị và ứng dụng yêu cầu khắt khe về thời gian đáp ứng.

Riêng với Linux thì có 2 platform khá nổi tiếng giúp đẩy nhanh quá trình phát triển ứng dụng trên ô tô dựa trên hệ điều hành Linux đó là AGL (Automotive Grade Linux) và GenIVI. Ở đây mình chỉ giới thiệu qua như vậy chứ không đề cập sâu, có thời gian sẽ viết bài chém riêng.

*** Framework

Có một số Framework khá nổi tiếng và thông dụng trong việc phát triển các ứng dụng HMI như Qt, Kanzi Studio, CGI Studio, MTA Studio, EB Guide. Trong đó ngoài Qt có bản free ra thì các frameworks còn lại đều phải mua commercial license mới có thể dùng được. Do đó bạn nào muốn theo ngành này thì mình khuyên các bạn học Qt trước cho dễ vì nó có bản free mà cộng đồng người dùng lớn, google search dễ.

*** Vi xử lý

Hiện nay có 2 hãng sản xuất vi xử lý (MCU – Micro Controller Unit) chuyên dùng cho Automotive đó là NXP và Renesas. Trong khi NXP có các dòng MCU như i.MX6, i.MX7, i.MX8 thì Renesas có RH850, RCar khá nổi tiếng và thông dụng dành cho xe hơi. Nếu có kinh nghiệm hoặc kiến thức về các dòng MCU này thì sẽ như hổ mọc thêm cánh khi làm Automotive Embedded Software.

*** Phần cứng và các chuẩn kết nối, giao tiếp

Với những lập trình viên làm về các software modules ở tầng thấp như BSP (Board Support Packages), HAL (Hardware Abstraction Layers), Device Drivers thì ngoài những kiến thức trên còn cần thêm các kiến thức chuyên sâu về phần cứng và các chuẩn kết nối, giao tiếp trong hệ thống nhúng. Cần phải hiểu về kiến trúc các MCU, giao tiếp GPIO – General Purpose Input Output (bao gồm Digital và Analog Input/Output), UART, SPI, I2C,… ngoài ra còn phải hiểu cách làm việc với các bộ nhớ ROM, Internal / External RAM, Internal / External Flash,… nói chung là rất nhiều thứ mà mình không thể kể hết ở đây.

Lời kết

Trên đây là một số thông tin chia sẻ từ kinh nghiệm và kiến thức của chính bản thân mình. Hy vọng nó có ích cho các bạn. Nếu cần mình giúp đỡ hay muốn hỏi thêm về chuyên môn có thể contact mình qua Facebook cá nhân hoặc post câu hỏi vào Group https://www.facebook.com/groups/916177308573002/, hoặc post câu hỏi lên https://codingguru.vn.

Tham khảo

  • Automotive Embedded Systems Handbook

— Phạm Minh Tuấn (Shun) —

Thanks author

 

 

Sửa lỗi install-package : Unable to find package ‘EntityFramework’ at source ”.

khi dùng visual cài đặt trên nuget gặp lỗi

install-package : Unable to find package ‘EntityFramework’ at source ”.

Để khắc phục lỗi, cách đơn giản nhất và xóa luôn file Nuget.config trong thư mục ‘C:Users[Ten_Nguoi_Dung]AppDataRoamingNuGet

Tắt visual và mở lại dự án.

Ví dụ cài Entity framework :Install-Package EntityFramework

Gỡ EF: Uninstall-Package EntityFramework -force

 

 

 

 

 

Đọc ghi file .CSV trong C#

//GHI FIle CSV

public void writeToItemSettingFile()
{

int quantity =99;

int PARA_1=82;

int PARA_2=92;

int PARA_3=490;

string path = @”C:FTPUploadItemSetting.csv”; //Khai báo đường dẫn chứa file
List<String> lines = new List<String>(); //Khai báo đối tượng kiểu string
lines.Add(“EM06000,” + quantity + “,1”);
lines.Add(“EM06001,” + PARA_1 + “,1”);
lines.Add(“EM06002,” + PARA_2 + “,1”);
lines.Add(“EM06003,” + PARA_3 + “,1”);

File.WriteAllText(path, “”); //Xóa trắng tất cả dữ liệu ở file cũ.

//File.WriteAllText(path, string.Empty); //dùng cách này cũng được

//Sử dụng đối tượng StreamWriter để ghi file
using (StreamWriter writer = new StreamWriter(path, false))
{
foreach (string line in lines)
writer.WriteLine(line);
}

}

 

//Ý tưởng Sửa dữ liệu 1 file CSV;

//Đọc từng dòng trong file CSV => tách dữ liệu từng dòng để tìm giá trị muốn thay thế=> add lại vào list<string>  => ghi file

//Trong ví dụ: Tìm đến hàng có giá trị EM05100 và thay cột bên cạnh thành giá trị =1

public void writeResult()
{
String path = @”C:FTPUploadResult2.csv”;
List<String> lines = new List<String>();

if (File.Exists(path))
{
using (StreamReader reader = new StreamReader(path))
{
String line;

while ((line = reader.ReadLine()) != null)
{
if (line.Contains(“,”))
{
String[] split = line.Split(‘,’);

if (split[0].Contains(“EM05100”))
{
split[1] = “1”;
line = String.Join(“,”, split);
}
}

lines.Add(line);
}
}

using (StreamWriter writer = new StreamWriter(path, false))
{
foreach (String line in lines)
writer.WriteLine(line);
}
}
}

 

 

 

 

 

 

 

 

 

Tiếng anh song ngữ: Scrum Product Backlog

Nguồn: https://longnguyen.site/scrum-product-backlog-636d03902259

Source: https://www.mountaingoatsoftware.com/agile/scrum/scrum-tools/product-backlog

Agile Product Backlog theo phương pháp Scrum là một danh sách các tính năng đã được sắp thứ tự ưu tiên, chứa các mô tả ngắn của các chức năng mong muốn của sản phẩm. Khi áp dụng phương pháp Scrum, chúng ta không cần bắt đầu dự án bằng cách document (tài liệu hóa) toàn bộ các yêu cầu về sản phẩm. Thông thường, một Scrum team và Product owner sẽ bắt đầu bằng việc viết những thứ họ nghĩ ra để sắp xếp thứ tự ưu tiên cho Product backlog. Product backlog luôn luôn nhiều hơn khối lượng cho sprint đầu tiên. Scrum Product backlog sau đó sẽ được phát triển và thay đổi liên tục sau khi team hiểu rõ hơn về sản phẩm và khách hàng của họ.

Product backlog sẽ được thay đổi sau khi hiểu người dùng hơn

Một Scrum product backlog thường có các loại item như sau:

  • Feature (các tính năng)
  • Bug hay Defect (lỗi)
  • Technical work (các công việc kỹ thuật)
  • Knowledge asquisition (các kiến thức thu lượm được)

Phương pháp nổi trội cho Scrum team khi mô tả về các tính năng trong scrum product backlog là thể hiện nó dưới dạng các user story (câu chuyện người dùng). Đó là các câu mô tả ngắn, đơn giản về các tính năng mong muốn dưới góc nhìn của người dùng. Ví dụ: “với tư cách là người mua hàng, tôi có thể xem lại các món hàng trong giỏ hàng trước khi thanh toán để biết được mình đã chọn các món hàng nào”.

Scrum product backlog

Không có sự khác nhau khi mô tả lỗi và tính năng (mỗi lỗi mô tả một cái gì đó khác với điều người dùng muốn) nên bug cũng được đặt vào Scrum product backlog.

Các hoạt động kỹ thuật và các kiến thức thu thập được cũng nằm trong backlog. Ví dụ về các công việc kỹ thuật: “Cập nhật toàn bộ máy tính của dev lên Windows 7”. Ví dụ về kiến thức thu thập được: một item trong backlog mô tả về quá trình nghiên cứu các thư viện Javascript khác nhau và sau đó đưa ra quyết định chọn cái nào.

Ví dụ về một Product Backlog thực tế (cột ngoài cùng bên trái) của team TripX

Kinh nghiệm của mình: chọn Trello làm công cụ cho Backlog là tuyệt vời nhất.

Product owner đưa ra Scrum product backlog đã được sắp thứ tự ưu tiên trong một buổi sprint planning meeting và mô tả các top item cho team. Cả team sẽ xác định xem item nào họ có thể hoàn thành trong sprint sắp tới. Các item được chọn sẽ được chuyển từ product backlog sang sprint backlog. Theo đó, team sẽ chuyển mỗi item trong product backlog thành một hoặc nhiều task (việc phải làm) trong sprint backlog để từ đó họ sẽ phân chia công việc hiệu quả hơn trong một sprint.

Theo lý thuyết, team sẽ bắt đầu tại các item trên cùng của một product backlog đã sắp xếp ưu tiên và sẽ gạch ngang 1 đường tại item cuối của các item ưu tiên nhất mà họ cảm thấy có thể hoàn thành. Thực tế, rất dễ thấy một team chọn 5 item ưu tiên nhất (ví dụ thế) và sau đó là 2 item thấp hơn liên quan đến 5 item đó.

Để hiểu rõ hơn, các bạn có thể xem ví dụ về một product backlog tại đây(không dịch).

 

ENGLISH

The agile product backlog in Scrum is a prioritized features list, containing short descriptions of all functionality desired in the product. When applying Scrum, it’s not necessary to start a project with a lengthy, upfront effort to document all requirements. Typically, a Scrum team and its product owner begin by writing down everything they can think of for agile backlog prioritization. This agile product backlog is almost always more than enough for a first sprint. The Scrum product backlog is then allowed to grow and change as more is learned about the product and its customers.

A typical Scrum backlog comprises the following different types of items:

  1. Features
  2. Bugs
  3. Technical work
  4. Knowledge acquisition

By far, the predominant way for a Scrum team to express features on the agile product backlog is in the form of user stories, which are short, simple descriptions of the desired functionality told from perspective of the user. An example would be, “As a shopper, I can review the items in my shopping cart before checking out so that I can see what I’ve already selected.”

Because there’s really no difference between a bug and a new feature—each describes something different that a user wants—bugs are also put on the Scrum product backlog.

Technical work and knowledge acquisition activities also belong on the agile backlog. An example of technical work would be, “Upgrade all developers’ workstations to Windows 7.” An example of knowledge acquisition could be a Scrum backlog item about researching various JavaScript libraries and making a selection.

The product owner shows up at the sprint planning meeting with the prioritized agile product backlog and describes the top items to the team. The team then determines which items they can complete during the coming sprint. The team then moves items from the product backlog to the sprint backlog. In doing so, they expand each Scrum product backlog item into one or more sprint backlog tasks so they can more effectively share work during the sprint.

Conceptually, the team starts at the top of the prioritized Scrum backlog and draws a line after the lowest of the high-priority items they feel they can complete. In practice, it’s not unusual to see a team select, for example, the top five items and then two items from lower on the list that are associated with the initial five.

For more, check out this product backlog example.

Scrum Foundations Video Series

 

 

 

Sửa lỗi trong C++ Exception from HRESULT: 0x8CE00001 when opening Visual Studio 2010-2017 Designer

Lỗi xảy ra khi tạo project CLR  trong c++:

File → New → Project… → Visual C++ → CLR → Windows Forms Application

Cách sửa:

tools -> options -> textEditor -> C++ -> Advanced -> “Disable DataBase”

Lúc này DisableDataBase == false. Ta đổi sang true rồi đổi sang False. Mở lại visual là được.

back to false (when DisableDataBase == true the HRESULT error appears), than restarting VisualStudio.

 

ps: Lỗi tù vãi lồn

 

 

 

 

Định dạng màu cho Placeholder trong html

Định dạng màu cho Placeholder trong html

 

Style CSS

<style>
::placeholder {
color: #f2eaea;
opacity: 1; /* Firefox */
}

:-ms-input-placeholder { /* Internet Explorer 10-11 */
color: #f2eaea;
}

::-ms-input-placeholder { /* Microsoft Edge */
color: #f2eaea;
}
</style>

Textbox trong ASP.net

<asp:TextBox ID=”txtDateExpiry” runat=”server” Width=”200px”
PlaceHolder=”MM/DD/YYYY”
Font-Bold=”True” Font-Size=”16pt”>

 

 

 

Sử dụng thư viện EPPlus.dll và FlexCel.dll

thư viện EPPlus.dll và FlexCel.dll đều là 2 thư viện free* để đọc và ghi file Excel rất hiệu quả mà không cần cài Excel(có thể)

So sánh

1.EPPlus: rất phù hợp khi xuất Excel vào mẫu(template) có sẵn, có thể xuất ra tất cả các vị trí chỉ bằng việc chỉ ra bạn muốn xuất dữ liệu vào Cell nào. Thư viện này cự kì linh hoạt. Nhưng việc dò từng cell khá mất thời gian.

Sử dụng: Import file EPPlus.dll vào project

using OfficeOpenXml;

string pathFileTemplate=”Đường dẫn chứa file Mẫu”;

FileInfo fileInfo = new FileInfo(pathFileTemplate);
using (ExcelPackage p = new ExcelPackage(fileInfo, true))
{
ExcelWorksheet ws = p.Workbook.Worksheets[1];

ws.Cells[“E4”].Value = ProductionNo;

string file = pathFileOut; // đường dẫn file sẽ xuât ra.
//string file = outputdir + “\GC.xlsx”;
File.WriteAllBytes(file, bin);

}

 

2.FlexCel.dll

Cho phép đặt các Parameter trên  excel. Có nghĩa là, bạn muốn xuất dữ liệu trên file Excel ở vị trí nào thì đặt parameter ở vị trí đấy. Cho phép xuất vào file Excel: Variable và Datatable

Ví dụ

using (FlexCelReport flex = new FlexCelReport())
{

string ItemCode=”somthing”;

string LotNo=”Something”;

flex.SetValue(“ItemCode”, ItemCode);

flex.SetValue(“LotNo”, LotNo);

datatable dtDocGC02_2;

flex.AddTable(“dtDocGC02_2”, dtDocGC02_2);

}

Cái này phải code ít hơn thư viện Epplus, phù hợp khi xuất hóa đơn đơn giản nhưng không phù hợp khi cần xuất dữ liệu kiểu có nhiều bảng nằm song song.

H1. Với cái này OK

fixed-band

H2. Với hình 2, không thể dùng Flexcel vì sẽ bị vỡ khung, vỡ dòng, Không thể kiểm soát được.

Captureffff

 

Khi nào rảnh mình sẽ có bài viết sâu hơn về 2 thư viên này.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Datatable _ Copy column từ bảng đến bảng khác

1.Sử dụng DataView để add bảng vào sau đó Select các cột cần lấy vào bảng. 

DataView viewDoc2 = new DataView(dtDocGC02);
DataTable select2 = viewDoc2.ToTable(“Selected”, false, “DocumentName”, “DocumentVer”);
DataView viewDoc3 = new DataView(dtMaterialGC02);
DataTable select3 = viewDoc3.ToTable(“Selected”, false, “MaterialCode”, “MaterialName”, “MaterialLotNo”, “Quantity”, “QuantityUnit”);

2. Để gộp 2 bảng vào làm 1 bảng, Gọi Hàm gồm 2 bảng

DataTable dtDocGC02_2 = Common.joinTable(select2, select3);

hàm gộp 2 bảng
/// <summary>
/// Gộp 2 bảng làm 1 bảng
/// </summary>
/// <param name=”dt1″></param>
/// <param name=”coldt1″>Số lượng của cột trong bảng 1</param>
/// <param name=”dt2″></param>
/// <param name=”coldt2″>số lượng cột của bảng 2</param>
/// <returns></returns>
/// <summary>
/// Gộp 2 bảng làm 1 bảng
/// </summary>
/// <param name=”dt1″></param>
/// <param name=”coldt1″>Số lượng của cột trong bảng 1</param>
/// <param name=”dt2″></param>
/// <param name=”coldt2″>số lượng cột của bảng 2</param>
/// <returns></returns>
public static DataTable joinTable(DataTable dt1, DataTable dt2)
{
int coldt1 = dt1.Columns.Count;
int coldt2 = dt2.Columns.Count;
DataTable dt = new DataTable();

foreach (DataColumn dataColumn in dt1.Columns)
{
dt.Columns.Add(dataColumn.ColumnName);
}

for (int i = 0; i < dt1.Rows.Count; i++)
{
DataRow dr = dt.NewRow();
for (int ii = 0; ii < coldt1; ii++)
{

string a = dt1.Rows[i][ii].ToString();
dr[ii] = dt1.Rows[i][ii].ToString();
}

dt.Rows.Add(dr);
}
int nextCol = coldt1 + coldt2;
foreach (DataColumn dataColumn in dt2.Columns)
{
dt.Columns.Add(dataColumn.ColumnName);
}

//Nếu chưa có dòng mới vì số dòng của bảng 2 > số dòng bảng 1 thì thêm dòng mới
if (coldt1 < coldt2)
{
for (int i = 0; i < dt2.Rows.Count; i++)
{

for (int ii = coldt1; ii < nextCol; ii++)
{
dt.Rows[i][ii] = dt2.Rows[i][ii – coldt1].ToString();
string a = dt2.Rows[i][ii – coldt1].ToString();

}

}
}
else
{
for (int i = 0; i < dt2.Rows.Count; i++)
{
if (i >= dt1.Rows.Count)
{
DataRow dr = dt.NewRow();

for (int ii = coldt1; ii < nextCol; ii++)
{
//dt.Rows[i][ii] = dt2.Rows[i][ii – coldt1].ToString();
//string a = dt2.Rows[i][ii – coldt1].ToString();
dr[ii] = dt2.Rows[i][ii – coldt1].ToString();
}
dt.Rows.Add(dr);

}
else
{
for (int ii = coldt1; ii < nextCol; ii++)
{
dt.Rows[i][ii] = dt2.Rows[i][ii – coldt1].ToString();
string a = dt2.Rows[i][ii – coldt1].ToString();

}
}
}
}
return dt;
}

//Kiểm tra  cột đã có trong bảng không, nếu không có thì mới dùng làm tên cột
public static bool checkColumnName(DataTable dt, string colName)
{
foreach (DataColumn dataColumn in dt.Columns)
{
if (dataColumn.ColumnName==colName)
{
return true;
}
}
return false;
}

 

 

 

 

Hàm gộp 2 datatable là 1 datatable

Không tìm được hàm tương ứng nên viết 1 hàm để gộp 2 datatable là 1 datatable.

Các ví dụ tìm kiếm trên mạng thì phải inner join theo 1 điều kiện nào đó. Nhưng 2 bảng này không có thuộc tính chung nên không inner join được.

Mình muốn cộng 2 bảng với nhau: Cộng các cột để ra bảng mới

/// <summary>
/// Gộp 2 bảng làm 1 bảng
/// </summary>
/// <param name=”dt1″></param>
/// <param name=”coldt1″>Số lượng của cột trong bảng 1</param>
/// <param name=”dt2″></param>
/// <param name=”coldt2″>số lượng cột của bảng 2</param>
/// <returns></returns>
public DataTable joinTable(DataTable dt1,int coldt1, DataTable dt2,int coldt2)
{
DataTable dt = new DataTable();

foreach (DataColumn dataColumn in dt1.Columns)
{
dt.Columns.Add(dataColumn.ColumnName);
}

for (int i = 0; i < dt1.Rows.Count; i++)
{
DataRow dr = dt.NewRow();
for (int ii = 0; ii < coldt1; ii++)
{

string a = dt1.Rows[i][ii].ToString();
dr[ii] = dt1.Rows[i][ii].ToString();
}

dt.Rows.Add(dr);
}
int nextCol = coldt1 + coldt2;
foreach (DataColumn dataColumn in dt2.Columns)
{
dt.Columns.Add(dataColumn.ColumnName);
}

//Nếu chưa có dòng mới vì số dòng của bảng 2 > số dòng bảng 1 thì thêm dòng mới
if (coldt1 < coldt2)
{
for (int i = 0; i < dt2.Rows.Count; i++)
{

for (int ii = coldt1; ii < nextCol; ii++)
{
dt.Rows[i][ii] = dt2.Rows[i][ii – coldt1].ToString();
string a = dt2.Rows[i][ii – coldt1].ToString();

}

}
}
else
{
for (int i = 0; i < dt2.Rows.Count; i++)
{
if (i>=dt1.Rows.Count)
{
DataRow dr = dt.NewRow();

for (int ii = coldt1; ii < nextCol; ii++)
{
//dt.Rows[i][ii] = dt2.Rows[i][ii – coldt1].ToString();
//string a = dt2.Rows[i][ii – coldt1].ToString();
dr[ii] = dt2.Rows[i][ii-coldt1].ToString();
}
dt.Rows.Add(dr);

}
else
{
for (int ii = coldt1; ii < nextCol; ii++)
{
dt.Rows[i][ii] = dt2.Rows[i][ii – coldt1].ToString();
string a = dt2.Rows[i][ii – coldt1].ToString();

}
}

}
}
return dt;
}