Giới Thiệu
Trong thế giới phát triển phần mềm, việc quản lý mã nguồn và tối ưu hóa quy trình làm việc là rất quan trọng. Một trong những công cụ giúp tôi cải thiện quy trình làm việc của mình là một công cụ CLI (Command Line Interface) có tên là RepositoryContextPackager. Bài viết này sẽ đi sâu vào cách tôi phát triển công cụ này, những thách thức mà tôi gặp phải và những lợi ích mà nó mang lại.
Mục Đích của Công Cụ CLI
RepositoryContextPackager được thiết kế để gói gọn dữ liệu dựa trên các hướng dẫn và gửi dữ liệu định dạng đúng cho các mô hình ngôn ngữ lớn (LLMs) nhằm giải quyết các vấn đề lập trình một cách dễ dàng. Trong quá trình làm việc với ChatGPT để giải quyết các vấn đề lập trình, tôi thường phải sao chép và dán từng tệp một, điều này khiến tôi cảm thấy rất mệt mỏi. Công cụ này cho phép chúng tôi cung cấp dữ liệu cụ thể liên quan đến các phụ thuộc và cấu trúc dự án, giúp LLM hiểu rõ hơn về dự án của chúng tôi và hướng dẫn chúng tôi một cách chính xác. Kết quả là, chúng tôi có thể tập trung vào những phần chính và phát triển dự án của mình mà không bị choáng ngợp bởi thông tin không cần thiết.
Giải Pháp của Tôi
Công cụ này được phát triển bằng C++ và thực hiện một lệnh duy nhất để phân tích dự án của bạn và tạo ra một tài liệu ngữ cảnh toàn diện bao gồm đường dẫn địa phương, lịch sử git, cây thư mục, và tất cả các tệp nguồn cùng với các thống kê tổng quát. Ngoài ra, bạn có thể tùy chỉnh để loại trừ hoặc bao gồm các tệp hoặc thư mục cụ thể theo nhu cầu của mình. Điều này loại bỏ việc chọn tệp thủ công và giúp duy trì ngữ cảnh của dự án khi yêu cầu giúp đỡ từ các LLM.
Lợi Ích của Công Cụ CLI Đối Với Kiến Thức Của Tôi
Khi tôi bắt đầu phát triển công cụ này, tôi không ngờ rằng tôi có thể thu được những kiến thức mạnh mẽ như vậy. Tôi đã có thêm nhiều kinh nghiệm trong việc đọc và ghi tệp, sử dụng các thư viện và tính năng C++17. Đặc biệt, khi tôi muốn biểu diễn cấu trúc cây, tôi nhận ra rằng tôi cần sử dụng đệ quy để duyệt sâu vào các tệp và thư mục. Tôi đã học được về std::filesystem, giúp tôi tìm kiếm tệp và thư mục một cách đệ quy. Đây là lần đầu tiên tôi thiết lập dự án của mình với CMake và tìm hiểu cách tích hợp các dự án mã nguồn mở khác vào mã của mình. Công cụ này đã cải thiện kỹ năng của tôi liên quan đến các trường hợp biên, xử lý lỗi và suy nghĩ về thiết kế trước khi viết mã.
Thách Thức Đầu Tiên Của Tôi
Thách thức đầu tiên của tôi là cách lấy thông tin git. Điều đầu tiên tôi nghĩ đến là sử dụng các lệnh git và phân tích đầu ra của chúng, nhưng nếu git không được cài đặt trên hệ thống của người dùng thì sao? Vì vậy, tôi đã sao chép libgit2 và đóng gói nó qua vcpkg, công cụ mà tôi lần đầu tiên sử dụng, và tôi đã phải ra khỏi vùng thoải mái của mình vì phải sử dụng các công cụ khác nhau và tích hợp một dự án khác vào dự án của mình. Trong quá trình lấy thông tin về gitInfo, tôi đã xem xét lại kiến thức của mình về mã C và con trỏ, mặc dù tôi đang viết bằng C++. Tôi cũng phát hiện ra cách mà GIT lưu trữ các định danh commit. Dưới đây là đoạn mã:
cpp
char sha[GIT_OID_HEXSZ + 1];
git_oid_tostr(sha, sizeof(sha), oid);
info.m_commit = sha;
Bạn có biết những chuỗi dài gồm các ký tự và số mà bạn thấy khi thực hiện một commit không? Như Commit: 'một chuỗi các ký tự hệ thập lục phân'? Tôi luôn nghĩ rằng Git chỉ tạo ra một ID ngẫu nhiên cho mỗi commit nhưng tôi đã hoàn toàn sai. Khi chúng ta thực hiện một commit, Git sẽ lấy tất cả nội dung - các tệp của chúng ta, ai là người thực hiện, ngày tháng và chạy hàm băm SHA-1 để sản xuất dữ liệu nhị phân. Vì lý do đó, dữ liệu này sẽ được chuyển đổi thành chuỗi.
Thách Thức Thứ Hai
Phần lớn thời gian khi bắt đầu xây dựng các dự án, chúng ta không nghĩ đến các hành động trong tương lai và một trong những sai lầm của tôi là quá phụ thuộc vào std::cout. Đến một thời điểm, tôi cần ghi dữ liệu vào tệp. Thay vì viết lại mọi thứ, tôi đã học rằng tôi có thể chuyển hướng đầu ra.
cpp
void writeFileStructure(std::ostream& o, const std::filesystem::path& path) {
o << "Cấu trúc\n\n";
std::streambuf* original_out = std::cout.rdbuf();
std::ostringstream caughtOut;
std::cout.rdbuf(caughtOut.rdbuf());
fsTravel::travelDirTree(path, 0);
std::cout.rdbuf(original_out);
o << caughtOut.str() << "\n\n";
}
Các Khía Cạnh Ngôn Ngữ
Trong dự án của mình, tôi nhận ra rằng std::array tốt hơn với một số dữ liệu cụ thể vì nó được biết đến tại thời gian biên dịch và tôi đã sử dụng nó với constexpr. Nhưng một vấn đề phát sinh mà tôi chưa bao giờ thấy trước đây. Bạn có thấy lỗi ở đâu không?
cpp
constexpr std::array<std::string, 8> ignoredDirs{
".vs", "build", "out", ".git", ".github", ".gitignore", ".gitmodules", ".gitattributes"
};
Vấn đề ở đây là std::string liên quan đến việc cấp phát bộ nhớ động mà constexpr không cho phép. Do đó, tốt hơn là sử dụng std::string_view, một kiểu chỉ để xem chuỗi mà không thay đổi, và có thể được tạo ra tại thời gian biên dịch.
Những Tài Nguyên Hữu Ích Tôi Đã Khám Phá
Các Thực Hành Tốt Nhất
- Luôn kiểm tra kỹ lưỡng các lỗi khi làm việc với tệp và I/O.
- Sử dụng
std::string_viewkhi có thể để tránh việc cấp phát bộ nhớ không cần thiết.
Những Cạm Bẫy Thường Gặp
- Quá phụ thuộc vào
std::coutcó thể dẫn đến việc khó khăn trong việc ghi dữ liệu vào tệp. - Không kiểm tra xem git có được cài đặt hay không có thể gây ra lỗi trong việc thu thập dữ liệu.
Mẹo Tối Ưu Hiệu Suất
- Sử dụng
std::filesystemđể duyệt tệp và thư mục thay vì sử dụng các phương pháp cũ hơn. - Cải thiện khả năng mở rộng bằng cách sử dụng
constexprvàstd::arraykhi có thể.
Khắc Phục Sự Cố
- Nếu bạn gặp lỗi khi sử dụng
std::stringvớiconstexpr, hãy chuyển sangstd::string_view.
Kết Luận
Công cụ CLI mà tôi phát triển không chỉ giúp tôi tiết kiệm thời gian mà còn giúp tôi nâng cao kỹ năng lập trình của mình. Từ việc học về C++17 đến việc cải thiện quy trình làm việc, tôi đã thu được rất nhiều kiến thức quý giá. Nếu bạn cũng đang tìm kiếm cách tối ưu hóa quy trình lập trình của mình, hãy thử phát triển một công cụ CLI tương tự nhé! Hãy chia sẻ ý kiến của bạn hoặc bất kỳ câu hỏi nào trong phần bình luận bên dưới.
Câu Hỏi Thường Gặp
Công cụ CLI có thể sử dụng cho ngôn ngữ nào?
Công cụ CLI này được phát triển bằng C++ nhưng bạn có thể áp dụng các khái niệm tương tự cho các ngôn ngữ khác như Python hoặc Java.
Tôi có thể mở rộng công cụ này không?
Có, bạn có thể thêm các tính năng mới như hỗ trợ cho các loại tệp khác hoặc cải thiện khả năng xử lý lỗi.