2 điểm bởi GN⁺ 1 ngày trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Dự án rất dễ rẽ theo hai hướng: bắt tay vào làm và hoàn thành ngay, hoặc để phần tìm hiểu và thiết kế phình to rồi đánh mất vấn đề ban đầu; trong thực tế, cứ làm thử thường lại tiến xa hơn
  • Chiếc kệ bếp được hoàn thành trong một cuối tuần, nhưng việc tìm hiểu workflow diff có cấu trúc cùng các ý tưởng ngôn ngữ·CAD đã kéo dài từ lâu, dù qua vô số nghiên cứu và prototype, vẫn chưa dẫn tới một kết quả trực tiếp giải quyết động cơ ban đầu
  • Khi làm tính năng tìm kiếm fuzzy path cho Emacs, các tính năng phụ của một thư viện tốt lại sinh ra yêu cầu mới khiến thiết kế phình to; cuối cùng toàn bộ phần code cho tính năng anchor không cần thiết đã bị bỏ đi, và bài học YAGNI lại được khẳng định
  • Trong diff code, so sánh theo từng dòng không nắm bắt tốt cấu trúc cấp cao như hàm hay kiểu dữ liệu; ngay cả công cụ dựa trên treesitter cũng có thể hiển thị dài dòng các phần xóa và thêm nếu việc ghép thực thể bị lệch, khiến khó đọc hơn
  • Hướng đi cần thiết là trước tiên tạo ra một công cụ phạm vi tối thiểu phù hợp với việc review đầu ra LLM theo từng lượt, bắt đầu bằng trích xuất thực thể cho Rust và ghép nối đơn giản để nhanh chóng xem được tổng quan thay đổi ở cấp cao

Suy nghĩ quá mức và mở rộng phạm vi

  • Dự án rất dễ chia thành hai hướng: làm ngay rồi xong, hoặc đào sâu các ví dụ đi trước đến mức phạm vi nở ra và rốt cuộc lại không giải quyết được vấn đề ban đầu
  • Chiếc kệ bếp làm trong dịp cuối tuần được hoàn thiện bằng cách vừa uống cà phê vừa chốt thiết kế, chỉnh sửa móc treo in 3D vài lần, rồi dùng vật liệu và sơn còn thừa để xong ngay trong cuối tuần
    • CAD cho móc treo Ikea bin được công khai trên OnShape CAD
    • Vật liệu được tái sử dụng từ phần dư của bàn làm việc, còn các góc được mài thủ công bằng palm sander
  • Với chiếc kệ này, tiêu chí thành công chính không phải là tạo ra món đồ hoàn hảo vừa khít cho nhà bếp, mà là tận hưởng việc làm mộc cùng bạn bè, nhờ đó cũng bớt cần phải cân nhắc quá mức các tiêu chí chi tiết
  • Ngược lại, trong quá trình tìm công cụ diff có cấu trúc, vì chưa hài lòng với kết quả của difftastic, tác giả đã dành 4 tiếng để tìm hiểu các công cụ và workflow liên quan, nhưng cuối cùng lại quay về tiêu chí ban đầu là một workflow diff tốt hơn để dùng trong Emacs
  • Các mối quan tâm lâu năm như giao diện prototyping phần cứng, một ngôn ngữ trộn Clojure và Rust, hay một ngôn ngữ cho CAD đã ngốn hàng trăm giờ nghiên cứu nền và làm prototype nhỏ, nhưng vẫn chưa tạo ra được sản phẩm nào trực tiếp giải quyết động cơ ban đầu
  • Trong các dự án ngôn ngữ và CAD, tiêu chí thành công trở nên mơ hồ: liệu có phải thay thế Rust hay Clojure, chỉ xử lý một phần vấn đề, chỉ cần là sân chơi để học, thay thế CAD thương mại, hay phải hữu ích cho người khác nữa hay không
  • Việc xem xét những câu hỏi này là có giá trị, nhưng tác giả cho rằng thay vì chỉ xem xét thật nhiều thứ, tốt hơn là thực sự làm ra nhiều thứ hơn
  • Kể cả nếu nhìn lại và thấy kết quả rõ ràng là chưa tốt, thì về tổng thể, cứ làm thử vẫn giúp tiến xa hơn

Định luật bảo toàn của mở rộng phạm vi

  • Thời gian để cứ thế làm cũng có giới hạn và cần sự cân bằng; trải nghiệm để LLM agent viết rất nhiều code rồi cuối cùng phải bỏ hết đã khiến tác giả lại nhớ tới YAGNI
  • Tác giả muốn tạo một tính năng tìm kiếm fuzzy path trên toàn bộ filesystem theo kiểu Finda để dùng trong Emacs, và vì từng tự viết thủ công tính năng tương tự trước đây nên nghĩ rằng nếu giám sát LLM thì có thể xong trong vài tiếng
  • Ban đầu, trong cuộc trao đổi để lên kế hoạch, tác giả được gợi ý Nucleo, và vì nó được thiết kế tốt, tài liệu tốt nên đã chọn để có các tính năng smart caseUnicode normalization
    • Ví dụ, truy vấn foo sẽ khớp cả Foo lẫn foo, còn Foo thì không khớp foo
    • Việc xử lý cafecafé cũng được giải quyết trong cùng ngữ cảnh
  • Vấn đề không nằm ở bản thân thư viện tốt đó, mà ở chỗ Nucleo còn hỗ trợ tính năng anchor
  • Với một corpus chỉ gồm đường dẫn file, anchor ở đầu dòng có vẻ không hữu ích, nên tác giả định diễn giải nó thành anchor theo path segment
    • Ví dụ, ^foo sẽ khớp /root/foobar/ nhưng không khớp /root/barfoo/
  • Để xử lý hiệu quả, chỉ mục phải lưu biên của các segment và cần có khả năng kiểm tra truy vấn nhanh trên từng segment
  • Sau đó lại còn phải xử lý các anchor query có chứa dấu slash như ^foo/bar, và chỉ kiểm tra theo từng segment thì khó khớp đúng các đường dẫn như /root/foo/bar/baz/
  • Tác giả đã tốn thêm vài tiếng cho thiết kế này, trao đổi ý tưởng với LLM, viết code bọc quanh các kiểu của Nucleo, rồi vì code trở nên quá cồng kềnh và không vừa ý nên cuối cùng lại tự viết lại một wrapper nhỏ hơn
  • Sau khi nghỉ một chút, tác giả không nhớ nổi lần nào mình thực sự cần tính năng anchor trong Finda, và nhận ra rằng với corpus đường dẫn, chỉ cần thêm / ở đầu hoặc cuối truy vấn là đã thay thế được phần lớn vai trò của anchor
    • Ngoại lệ chỉ còn anchor cho phần cuối tên file
  • Cuối cùng toàn bộ code liên quan đến anchor bị xóa bỏ, và tác giả cũng không chắc liệu kết quả đó có còn tốt hơn so với việc tự viết từ đầu mà không trao đổi với LLM hay người khác hay không
  • Có vẻ như càng tăng tốc lập trình thì cũng tồn tại một kiểu định luật bảo toàn khiến tính năng không cần thiết, rabbit holeđường vòng tăng theo tương ứng

Diff có cấu trúc

  • Trong code, diff thường có nghĩa là bản tóm tắt thay đổi theo từng dòng giữa hai phiên bản của một file, và ở dạng unified view thì phần thêm và xóa được đánh dấu bằng +, -
  • Cùng một diff cũng có thể được render dưới dạng so sánh hai cột, và khi thay đổi phức tạp hơn thì dạng này có thể dễ đọc hơn
  • Vấn đề của diff theo dòng là nó không nhận biết được cấu trúc cấp cao như hàm hay kiểu dữ liệu; nếu dấu ngoặc nhọn tình cờ vẫn khớp thì thậm chí các phần thuộc về những hàm khác nhau cũng có thể bị lược bớt trong hiển thị
  • difftastic cố giảm vấn đề này bằng cách dùng concrete syntax tree do treesitter cung cấp, nhưng việc ghép thực thể giữa các phiên bản không phải lúc nào cũng hoạt động tốt
  • Trong bản diff trực tiếp khiến tác giả chú ý, struct PendingClick không được ghép tương ứng giữa hai bên, nên ở bên trái nó hiện là bị xóa còn bên phải lại hiện là được thêm vào
  • Tác giả không đào sâu lý do ghép thất bại, nhưng cho rằng dù toàn bộ diff có dài hơn thì việc nhìn PendingClickRequestPendingClick tương ứng ở hai bên vẫn tốt hơn

Công cụ diff có cấu trúc và tài liệu tham khảo

  • Công cụ semantic diff hoàn thiện và được trau chuốt cẩn thận nhất, theo tác giả, là semanticdiff.com
    • Đây là sản phẩm của một công ty nhỏ ở Đức, có plugin VSCode miễn phí và web app để hiển thị GitHub PR diff
    • Tuy vậy, họ không cung cấp thư viện code có thể dùng làm nền cho workflow mà tác giả mong muốn
    • Bài semanticdiff vs. difftastic chứa nhiều chi tiết hữu ích, bao gồm cả việc difftastic thậm chí không hiển thị được thay đổi thụt lề có ý nghĩa trong Python
    • Một trong các tác giả cho biết trong bình luận HN rằng họ đã rời bỏ hướng dùng treesitter cho xử lý ngữ nghĩa; do keyword phụ thuộc ngữ cảnh và hành vi của lexer, việc parse có thể thất bại, khiến công cụ thậm chí dừng lại khi async được dùng làm tên tham số
  • diffsitter là công cụ dựa trên treesitter và có kèm MCP server
    • Số GitHub star khá nhiều nhưng tài liệu dường như không thật sự tốt, và tác giả khó tìm được tài liệu giải thích cách nó hoạt động
    • Wiki của difftastic viết rằng nó thực hiện longest-common-subsequence trên các leaf của cây
  • gumtree là công cụ xuất phát từ nền tảng nghiên cứu, học thuật từ năm 2014
    • Nó cần Java nên không phù hợp với nhu cầu cá nhân là một công cụ có thể dùng nhanh trong Emacs
  • mergiraf là một merge-driver dựa trên treesitter, viết bằng Rust
    • architecture overview được trình bày rất tốt, và nội bộ sử dụng thuật toán Gumtree
    • Tài liệu và hình minh họa tạo cảm giác đây là một dự án được viết rất cẩn thận
    • Tác giả của semanticdiff.com viết trong bình luận HN rằng GumTree cho kết quả nhanh, nhưng ngay cả khi áp dụng nhiều cải tiến từ các bài báo tiếp theo thì vẫn khá thường xuyên trả về các phép ghép tệ, nên cuối cùng họ chuyển sang cách tiếp cận dựa trên dijkstra để tối thiểu hóa chi phí ánh xạ
  • weave là một merge-driver khác dựa trên treesitter, cũng viết bằng Rust
    • Landing page hào nhoáng, nhiều GitHub star, có MCP server... khiến ấn tượng tổng thể hơi có phần phô trương
    • Tác giả đã xem qua crate trích xuất thực thể sem
    • Phần code diff cốt lõi khá ổn nhưng hơi dài dòng, và phần ghép thực thể dùng thuật toán greedy
    • Mô hình dữ liệu không phát hiện được việc di chuyển bên trong file, trong khi kiểu thay đổi này có thể rất quan trọng
    • Nó cũng chứa khá nhiều phân tích tác động dựa trên heuristic, thứ có vẻ cần tích hợp ngôn ngữ chặt chẽ hơn mới đáng tin
      • Khi chạy sem diff --verbose HEAD~4, tác giả còn gặp đầu ra lỗi đánh dấu cả những dòng thực tế không hề thay đổi là đã thay đổi
    • Có quá nhiều tính năng giả định hữu ích nhưng mới ở mức khoảng 80%, nên không hợp để dùng làm nền tảng; tuy vậy tác giả vẫn đánh giá cao việc nhóm này làm được đến mức đó chỉ trong 3 tháng
  • diffast tính tree edit-distance của AST dựa trên một thuật toán từ bài báo học thuật năm 2008
    • Nó hỗ trợ Python, Java, Verilog, Fortran, C/C++ thông qua parser chuyên biệt
    • example AST differences gallery được tổ chức rất tốt
    • Nó có thể xuất thông tin dưới dạng tuple để dùng trong datalog
  • autochrome là công cụ diff chỉ dành cho Clojure và dùng dynamic programming
    • Phần giải thích trực quan và walkthrough ví dụ rất tốt
  • Bài Designing a Tree Diff Algorithm Using Dynamic Programming and A* của Tristan Hume là tài liệu rất đáng tham khảo về thiết kế thuật toán tree diff

Workflow mong muốn và kế hoạch phạm vi tối thiểu

  • Use case chính là review đầu ra LLM theo từng lượt, và tác giả không để agent tự do tạo hơn 10.000 dòng code trong một lần
  • Tác giả giao cho agent các tác vụ có phạm vi rõ ràng, vài phút sau quay lại xem tổng quan toàn bộ thay đổi, rồi muốn có thể sửa trực tiếp trong Emacs, bỏ hết để làm lại, hoặc tự viết lại từ đầu
  • Workflow mong muốn là trước tiên xem tổng quan cấp cao về kiểu dữ liệu, hàm, phương thức nào đã được thêm, xóa hay thay đổi
  • Trên nền đó, cần có khả năng nhanh chóng mở rộng ra text diff cho từng thực thể, để việc đi từ tóm tắt sang diff chi tiết diễn ra tự nhiên
  • Đồng thời cũng cần có thể sửa ngay tại chỗ mà không phải chuyển sang nơi khác; tác giả muốn chỉnh sửa inline chứ không phải đổi từ màn hình diff sang màn hình file
  • Đích hướng tới là đưa workflow review thay đổi và staging của Magit từ cấp file·dòng lên cấp thực thể
  • Phù hợp với bài học mới được nhắc lại lần này về phạm vi tối thiểu, tác giả dự định trước tiên sẽ tự gấp rút làm một framework trích xuất thực thể dựa trên treesitter chỉ cho Rust
  • Việc ghép nối trước mắt sẽ bắt đầu bằng cách greedy đơn giản, còn diff sẽ được render trên dòng lệnh
  • Nếu chừng đó đã cho kết quả tốt hơn difftastic ở commit cụ thể kia, thì sau đó mới nối nó vào một workflow Emacs có tính tương tác hơn như Magit
    • Nếu có thể, tác giả cũng để ngỏ khả năng tái sử dụng chính Magit
    • Hỗ trợ ngôn ngữ mới sẽ chỉ được thêm khi thực sự cần
    • Về sau cũng có thể thử ghép nối toàn cục dựa trên chấm điểm thay cho greedy đơn giản
  • Nếu đủ hài lòng, tác giả có thể công khai nó, nhưng mục tiêu không phải là gom GitHub star hay HN karma; nó cũng có thể mãi chỉ là một công cụ riêng tư lặng lẽ dùng một mình
  • Tác giả khép lại bằng ý rằng đôi khi người ta chỉ đơn giản cần một cái kệ, qua đó gắn lại bài học làm đúng thứ cần thiết thay vì mở rộng quá đà

1 bình luận

 
Ý kiến trên Hacker News
  • Tôi nghĩ bài này cho thấy rất rõ khó khăn lớn nhất của nghiên cứu PhD
    Khi chọn một chủ đề thú vị và đọc càng nhiều công trình liên quan càng tốt, bạn dễ nhận ra đã có rất nhiều người làm điều mình định làm, và từ đó scope creep rất dễ trở nên nghiêm trọng
    Sau khi đã tiêu hết năng lượng và sự hào hứng ban đầu, bạn phải gượng ép đẩy nốt 20~30% còn lại để kéo nó tới trạng thái có thể xuất bản

    • Ngày 1 thì bắt đầu với ý tưởng áp dụng chất xúc tác công nghiệp hiện có vào một mục đích mới để giảm chi phí sản xuất tiền chất cho thuốc thiết yếu
      Đến ngày 400 thì gần như giải thích xong thuyết vạn vật và đang định chế tạo một thiết bị thí nghiệm quỹ đạo tại điểm Lagrange để phát hiện hạt phổ quát trung gian cho mọi lực trong vũ trụ đã biết
    • Cảm giác đó thật sự quá chân thực
      Tôi muốn biết phải làm gì để giảm bớt chuyện này
    • Tôi nghĩ phần lớn nghiên cứu sinh tiến sĩ đều trải qua điều này, vì mục đích của PhD rốt cuộc là chứng minh rằng bạn có thể làm normal science
      Trên thực tế, nó gần giống kiểu nâng khả năng quan sát của một hệ thống từ 1% lên 1.001%, và là một cánh cổng để bước vào con đường học thuật
      Vì vậy tôi hiếm khi thấy luận án nào thực sự thú vị, cực kỳ mới mẻ, hoặc có thể áp dụng trực tiếp vào khoa học
    • Hơn nữa còn phải chịu đựng chuyện này trong trạng thái ngày càng nặng nề vì hối hận đã bắt đầu PhD ngay từ đầu
    • Bắt đầu bằng cách cố đọc toàn bộ công trình trước đó rõ ràng là một cách tiếp cận sai
      Thực tế tôi gần như không thấy ai nghiên cứu như vậy; thông thường đọc khoảng hai ba bài rồi xây tiếp từ đó mới là hợp lý
      Việc rà sâu tài liệu nghiên cứu nên làm sau khi đã có chút kết quả và bắt đầu viết lại thì tốt hơn
  • Tôi cứ nghĩ mãi về câu nói rằng chỉ cần tốt hơn là đủ
    Những cải tiến nhỏ cũng sẽ tích lũy theo thời gian, và vì ngay từ đầu chẳng có gì là hoàn toàn mới, nên ngồi đó cố vắt ra một thiết kế hoàn hảo lại dễ phản tác dụng
    Câu “chướng ngại vật chính là con đường” cũng rất hợp ở đây

    • Câu đừng để sự hoàn hảo trở thành kẻ thù của thứ đủ tốt thật sự rất đúng
      Một đồng nghiệp từng làm cùng tôi, khi phê bình thay đổi trong code, nếu cảm thấy mình đang bắt lỗi quá vụn vặt thì sẽ nói “vẫn tốt hơn trước”
      Nhờ vậy, anh ấy vừa chỉ ra được điểm cần cải thiện, vừa đồng thời cho phép mọi người tiếp tục tiến lên dù vẫn còn vài lỗi nhỏ, và tôi rất ủng hộ thái độ này
    • Suy cho cùng thì đây là chủ nghĩa hoàn hảo
      Trước đây tôi chỉ nghĩ chủ nghĩa hoàn hảo là cố gắng đạt thành tích quá cao một cách quá sức, nhưng việc không chấp nhận thứ gì không hoàn hảo rồi bỏ cuộc mà chẳng tiến triển gì cũng có thể là hoàn hảo chủ nghĩa
      Sự trì hoãn với những việc lớn cũng thường có cùng một gốc rễ
  • Tôi thích điều CEO của Rec Room từng nói
    Các team lúc nào cũng ước dự án ngắn hơn, chứ hiếm khi nói rằng lẽ ra nên dời phát hành thêm, làm nó phức tạp hơn và trau chuốt hơn nữa
    Dù không đúng 100% trong mọi trường hợp, nhưng nếu đã phải mắc sai lầm thì tôi nghĩ làm nhỏ và phát hành sớm vẫn tốt hơn là làm quá lớn rồi lãng phí thời gian

  • Con người vốn dễ nảy ra những ý tưởng giống nhau, nên nếu cứ hoàn thành dự án mà không biết trước thì cuối cùng nó cũng dễ trở thành một dạng tái phát minh nào đó
    Ngược lại, nếu nghiên cứu trước, bạn có thể nhận ra rằng một phần nào đó chỉ là lặp lại thứ đã tồn tại và bị mất hứng
    Dù vậy, việc tự mình làm tới cùng để học hỏi vẫn có thể là điều quan trọng nhất
    Tất nhiên, nếu bạn phải tạo ra một đóng góp học thuật mới hoặc kiếm tiền từ một dự án mang tính độc nhất thì sẽ khó hơn, nhưng ngay cả trong những lĩnh vực đó người ta cũng bất ngờ khoan dung với việc chỉ cần bẻ hướng nhẹ từ cái có sẵn

  • Tôi đang gặp đúng tình huống này với side project của mình
    Lĩnh vực là Information Retrieval nên tôi còn ít kinh nghiệm, và đương nhiên có rất nhiều prior art để học hoặc tích hợp
    Vì vậy sau khi đọc bài này, tôi thấy nghiêng hơn về hướng cứ làm cái của mình trước, chỉ nhìn vào các ví dụ có sẵn khi bị bí hoặc cần ý tưởng
    Mặt khác, nếu xem phim tài liệu Clojure ra gần đây thì Rich Hickey dường như lại đào rất sâu vào prior art, bài báo và các ngôn ngữ khác trong thời gian dài rồi mới bắt tay vào làm
    Nhưng bản thân ông ấy trước đó cũng đã tạo ra các ngôn ngữ khác rồi, nên bức tranh lớn vẫn là bắt đầu từ việc tự làm để học
    Có lẽ không nên chỉ suy nghĩ quá lâu; cứ làm trước, tích lũy bài học từ thực tế, va vào tường rồi lúc đó mới cần nghiên cứu sâu hơn

  • Việc đặt deadline đã giải quyết phần lớn vấn đề scope creep cho tôi
    Theo cảm nhận của tôi, những dự án có hạn chót cứng như game jam hay cuộc thi lập trình thì dễ hoàn thành hơn, còn những dự án mở vô thời hạn thì khó đi đến đích hơn nhiều
    Tôi thấy điều này cũng giống như việc chuẩn C++ được phát hành mỗi 3 năm thay vì chờ cho đến khi mọi tính năng mong muốn đều sẵn sàng
    https://news.ycombinator.com/item?id=20428703

  • Bài viết khá thú vị, nhưng tôi thấy suy nghĩ của tác giả có phần lan man, tản mát

    • Ở đây cốt lõi rốt cuộc vẫn là scope creep
    • Đây không phải là một bài blog đào sâu sắc bén vào một chủ đề cụ thể, mà gần hơn với một bản cập nhật newsletter gửi cho những người theo dõi tác giả
  • Với một người nói rằng mình bị scope creep áp đảo, tác giả lại có vẻ là kiểu làm được cực nhiều việc, đến mức cuối bài còn gắn cả đống link về đủ loại chủ đề
    Cuối cùng có vẻ đây là kiểu người thực sự thích học và thử nhiều thứ, và chính quá trình sa vào rabbit hole mới là thứ kích thích đầu óc họ một cách thú vị

  • Với tư cách là người làm một mình, có một nhận ra đã giúp tôi rất nhiều
    Phần lớn những thứ trông như abstraction bắt buộc thật ra chỉ là scope creep đổi tên
    Sau khi cứ gắn flag cho từng tính năng mới và thấy một pattern trong code của mình, tôi đặt ra một quy tắc
    Đó là không phát hành tính năng nào nếu không có test cho hành vi khi flag-off
    Từ đó tôi bắt đầu nhìn flag không phải như lối thoát mà là một phần của sản phẩm, và ba tính năng nằm trong backlog đã tự nhiên biến mất khi tôi bắt đầu nghĩ như vậy

  • Đúng là lên kế hoạch quá mức và scope creep là vấn đề, nhưng ngược lại cũng cần cảnh giác với việc nghiêng quá xa sang phía phát triển ngẫu hứng
    Một số dự án thành công nhất của tôi thực ra lại là những trường hợp tôi đã lên kế hoạch và rà soát trước hầu hết tính năng bằng cách mô hình hóa dữ liệu trước khi tạo ra phần mềm chạy được
    Ở giai đoạn đó thường rất khó biết cái gì là quá tay, và nếu bỏ đi những tính năng mà tôi hoặc người dùng có thể muốn thì sau này sẽ tốn rất nhiều thời gian để thiết kế lại phần lõi của code
    Ngược lại, nếu đoán sai theo hướng kia thì dự án lại phình ra quá lớn và ta gọi đó là scope creep
    Cuối cùng thì phán đoán này phụ thuộc vào việc bạn hiểu domain đến mức nào
    Nếu bạn biết ít hơn mình tưởng thì sẽ phải làm lại rất nhiều, còn nếu bạn biết nhiều hơn mình tưởng thì thực ra đã có thể đi lớn hơn nhưng lại lãng phí thời gian với baby step
    Dù đi hướng nào cũng vẫn để lại tiếc nuối, nên rốt cuộc tôi thấy đây là một vấn đề phán đoán rất lớn

    • Cách lý tưởng, theo tôi, là dành đủ thời gian ở giai đoạn phân tích để nạp đúng ngữ cảnh vào đầu, nhưng khi bắt tay vào làm thì sẵn sàng bỏ những giải pháp over-engineered và triển khai ngay theo hướng thuận tay nhất
      Không nên mắc ngụy biện chi phí chìm, và việc bỏ vài giờ nghiên cứu một chủ đề cỡ PhD không có nghĩa là bạn nhất định phải dùng nó trong dự án
      Nếu nó không thực sự khớp với vấn đề hiện tại thì nên mạnh dạn bỏ đi
    • Đừng quá lo mình sẽ sai, cứ làm thử trước rồi nếu cần thì điều chỉnh sau