Chuỗi mã hóa sẽ không bao giờ thay đổi


39

Vì vậy, trong nỗ lực viết chương trình chia động từ (theo thuật toán, không thông qua bộ dữ liệu) cho tiếng Pháp, tôi đã gặp một vấn đề nhỏ.

Thuật toán chia động từ thực sự khá đơn giản đối với các trường hợp động từ 17 hoặc hơn, và chạy trên một mẫu cụ thể cho từng trường hợp; do đó, hậu tố liên hợp cho 17 lớp này là tĩnh và sẽ (rất có thể) sẽ không thay đổi bất kỳ lúc nào. Ví dụ:

// Verbs #1 : (model: "chanter")
    terminations = {
        ind_imp: ["ais", "ais", "ait", "ions", "iez", "aient"],
        ind_pre: ["e", "es", "e", "ons", "ez", "ent"],
        ind_fut: ["erai", "eras", "era", "erons", "erez", "eront"],
        participle: ["é", "ant"]
    };

Đây là các hậu tố thay thế cho lớp động từ phổ biến nhất trong tiếng Pháp.

Có các lớp động từ khác (irregenses), mà sự chia động từ của nó cũng rất có thể sẽ tĩnh trong thế kỷ tới hoặc hai. Vì chúng không đều, nên các liên hợp hoàn chỉnh của chúng phải được bao gồm tĩnh, bởi vì chúng không thể được liên hợp một cách đáng tin cậy từ một mẫu (cũng chỉ có [theo số lượng của tôi] 32 quy định). Ví dụ:

// "être":
    forms = {
        ind_imp: ["étais", "étais", "était", "étions", "étiez", "étaient"],
        ind_pre: ["suis", "es", "est", "sommes", "êtes", "sont"],
        ind_fut: ["serai", "seras", "sera", "serons", "serez", "seront"],
        participle: ["été", "étant"]
    };

Tôi có thể đặt tất cả những thứ này vào XML hoặc thậm chí JSON và giải tuần tự hóa nó khi nó cần được sử dụng, nhưng liệu có một điểm? Các chuỗi này là một phần của ngôn ngữ tự nhiên, không thay đổi, nhưng với tốc độ chậm.

Mối quan tâm của tôi là bằng cách thực hiện mọi thứ theo cách "đúng" và giải trừ một số nguồn dữ liệu, tôi không chỉ phức tạp hóa vấn đề không cần phức tạp, mà tôi còn hoàn toàn theo dõi được toàn bộ mục tiêu của cách tiếp cận thuật toán: không sử dụng nguồn dữ liệu! Trong C #, tôi chỉ có thể tạo một lớp bên dưới namespace Verb.Conjugation(ví dụ class Irregular) để chứa các chuỗi này theo kiểu liệt kê hoặc một cái gì đó, thay vì nhồi chúng vào XML và tạo một class IrregularVerbDeserializer.

Vì vậy, câu hỏi: nó có phù hợp với các chuỗi mã cứng rất khó thay đổi trong suốt vòng đời của một ứng dụng không? Tất nhiên tôi không thể đảm bảo 100% rằng họ sẽ không thay đổi, nhưng rủi ro so với chi phí gần như không đáng kể trong mắt tôi - mã hóa cứng là ý tưởng tốt hơn ở đây.

Chỉnh sửa : Bản sao được đề xuất hỏi cách lưu trữ một số lượng lớn các chuỗi tĩnh , trong khi câu hỏi của tôi là khi nào tôi nên mã hóa các chuỗi tĩnh này .


26
Bạn có muốn sử dụng phần mềm này cho một ngôn ngữ khác ngoài tiếng Pháp trong tương lai không?

10
Cách tiếp cận thuật toán hay không, rõ ràng là bạn chỉ cần mã hóa các chuỗi 32 * 20 này (và nhiều hơn nữa khi bạn thêm nhiều ngôn ngữ), và câu hỏi thực sự duy nhất là đặt chúng ở đâu. Tôi sẽ chọn bất cứ nơi nào cảm thấy thuận tiện nhất với bạn, có vẻ như đó là mã trong thời điểm hiện tại. Bạn luôn có thể xáo trộn chúng xung quanh sau này.
Ixrec

1
@ChrisCirefice Nghe có vẻ khá tối ưu với tôi. Đi cho nó.
Ixrec

2
@Gusdor Tôi không nghĩ bạn đọc rõ ràng - Tôi đã nói rằng các kiểu chia động từ có thể sẽ không bao giờ thay đổi, hoặc thay đổi thường xuyên đến mức cứ sau 100 năm lại biên dịch lại sẽ ổn. Tất nhiên mã sẽ thay đổi, nhưng một khi các chuỗi ở đó tôi muốn chúng như thế nào, trừ khi tôi tái cấu trúc chúng sẽ tĩnh trong 100 năm tới.
Chris Cirefice

1
+1. Chưa kể rằng trong 60 - 100 năm, chi phí sẽ không tồn tại hoặc đã được thay thế bằng một phiên bản tốt hơn hoàn toàn.
HarryCBurn

Câu trả lời:


56

nó có phù hợp với các chuỗi mã cứng rất khó thay đổi trong suốt vòng đời của một ứng dụng không? Tất nhiên tôi không thể đảm bảo 100% rằng họ sẽ không thay đổi, nhưng rủi ro so với chi phí gần như không đáng kể trong mắt tôi - mã hóa là ý tưởng tốt hơn ở đây

Có vẻ như tôi đã trả lời câu hỏi của riêng bạn.

Một trong những thách thức lớn nhất mà chúng tôi gặp phải là tách biệt những thứ có khả năng thay đổi khỏi những thứ không thay đổi. Một số người thất bại và đổ tất cả mọi thứ họ có thể vào một tập tin cấu hình. Những người khác đi đến cực đoan khác và yêu cầu biên dịch lại ngay cả những thay đổi rõ ràng nhất.

Tôi sẽ đi theo cách tiếp cận dễ nhất để thực hiện cho đến khi tôi tìm thấy một lý do thuyết phục để làm cho nó phức tạp hơn.


Cảm ơn Dan, đó là những gì tôi nghĩ. Viết một lược đồ XML cho việc này, có một tệp khác để theo dõi và phải viết một giao diện để khử lưu lượng dữ liệu có vẻ như quá mức khi xem xét không có nhiều chuỗi và vì đó là ngôn ngữ tự nhiên, không có khả năng thay đổi mạnh mẽ trong 100 năm tới. May mắn thay, ngày nay trong các ngôn ngữ lập trình, chúng ta có những cách ưa thích để trừu tượng dữ liệu thô này đằng sau một giao diện đẹp mắt, ví dụ như French.Verb.Irregular.Etresẽ chứa dữ liệu từ câu hỏi của tôi. Tôi nghĩ rằng nó hoạt động ổn;)
Chris Cirefice

3
+1 Ở đây từ trại Ruby, tôi sẽ bắt đầu công cụ mã hóa cứng và chuyển nó sang cấu hình khi cần thiết. Đừng quá sớm kỹ sư dự án của bạn bằng cách làm cho mọi thứ có thể cấu hình. Nó chỉ làm bạn chậm lại.
Overbryd

2
Lưu ý: một số nhóm có định nghĩa khác về "mã hóa cứng", vì vậy hãy lưu ý rằng thuật ngữ đó có nghĩa là nhiều thứ. Có một mô hình chống được công nhận tốt trong đó bạn cứng các giá trị mã vào các câu lệnh của hàm, thay vì tạo các cấu trúc dữ liệu như bạn có ( if (num == 0xFFD8)). Ví dụ đó sẽ trở thành một cái gì đó giống như if (num == JPEG_MAGIC_NUMBER)trong hầu hết các trường hợp vì lý do dễ đọc. Tôi chỉ nêu ra vì từ "mã hóa cứng" thường mọc tóc trên cổ của mọi người (như của tôi) vì ý nghĩa thay thế của từ này.
Cort Ammon

@CortAmmon JPEG có rất nhiều số ma thuật. Chắc chắn phải JPEG_START_OF_IMAGE_MARKERkhông?
dùng253751

@immibis Sự lựa chọn của bạn về đặt tên liên tục có lẽ tốt hơn của tôi.
Cort Ammon

25

Bạn đang suy luận ở phạm vi sai.

Bạn đã không mã hóa chỉ các động từ riêng lẻ. Bạn đã mã hóa ngôn ngữ và các quy tắc của nó . Đến lượt mình, điều này có nghĩa là ứng dụng của bạn không thể được sử dụng cho bất kỳ ngôn ngữ nào khác và không thể được mở rộng với các quy tắc khác.

Nếu đây là ý định của bạn (tức là chỉ sử dụng nó cho tiếng Pháp), thì đây là cách tiếp cận phù hợp, vì YAGNI. Nhưng bạn thừa nhận rằng bạn cũng muốn sử dụng nó cho các ngôn ngữ khác, điều đó có nghĩa là rất sớm, bạn sẽ phải chuyển tất cả phần được mã hóa cứng sang các tệp cấu hình. Câu hỏi còn lại là:

  • Bạn, với một sự chắc chắn gần 100%, trong tương lai gần, sẽ mở rộng ứng dụng sang các ngôn ngữ khác? Nếu vậy, bạn nên xuất các thứ sang các tệp JSON hoặc XML (cho các từ, các phần của từ, v.v.) và các ngôn ngữ động (cho các quy tắc) ngay bây giờ thay vì buộc bạn phải viết lại phần chính của ứng dụng.

  • Hoặc chỉ có một xác suất nhỏ rằng ứng dụng sẽ được mở rộng ở đâu đó trong tương lai, trong trường hợp đó YAGNI chỉ ra rằng cách tiếp cận đơn giản nhất (cách bạn đang sử dụng ngay bây giờ) là tốt hơn?

Để minh họa, hãy kiểm tra chính tả của Microsoft Word. Có bao nhiêu điều bạn nghĩ là mã hóa cứng?

Nếu bạn đang phát triển một bộ xử lý văn bản, bạn có thể bắt đầu bằng một công cụ đánh vần đơn giản với các quy tắc được mã hóa cứng và thậm chí các từ được mã hóa cứng : if word == "musik": suggestSpelling("music");. Nhanh chóng, bạn sẽ bắt đầu di chuyển các từ, sau đó quy tắc bên ngoài mã của bạn. Nếu không thì:

  • Mỗi lần bạn phải thêm một từ, bạn phải biên dịch lại.
  • Nếu bạn đã học một quy tắc mới, bạn phải thay đổi mã nguồn một lần nữa.
  • Và quan trọng hơn, không có cách nào bạn có thể điều chỉnh động cơ sang tiếng Đức hoặc tiếng Nhật mà không cần viết số lượng mã khổng lồ.

Như bạn đã nhấn mạnh chính mình:

Rất ít quy tắc từ tiếng Pháp có thể được áp dụng cho tiếng Nhật.

Ngay khi bạn mã hóa các quy tắc cho một ngôn ngữ, mọi ngôn ngữ khác sẽ yêu cầu ngày càng nhiều mã, đặc biệt là với sự phức tạp của ngôn ngữ tự nhiên.

Một chủ đề khác là cách bạn thể hiện các quy tắc khác nhau đó, nếu không thông qua mã. Cuối cùng, bạn có thể thấy rằng một ngôn ngữ lập trình công cụ tốt nhất cho điều đó. Trong trường hợp đó, nếu bạn cần mở rộng công cụ mà không biên dịch lại, ngôn ngữ động có thể là một lựa chọn tốt.


1
Tất nhiên, không phải mọi thứ đều được mã hóa cứng ở đó: P vì vậy tôi đoán nó thực sự đi xuống để xác định giao diện của tôi trông như thế nào để tôi có thể áp dụng nó cho nhiều ngôn ngữ. Vấn đề là tôi chưa biết tất cả các ngôn ngữ đủ tốt, vì vậy điều đó thực sự không thể. Tôi nghĩ rằng một điều mà có lẽ bạn đang thiếu là các mẫu chia động từ (đây là tất cả những gì tôi đang nói) rất tĩnh trong một ngôn ngữ, và nó thực sự là một trường hợp cụ thể. Có khoảng 17 mẫu chia động từ trong tiếng Pháp cho động từ. Nó sẽ không kéo dài bất cứ lúc nào sớm ...
Chris Cirefice

4
Tôi không đồng ý - Tôi không nghĩ việc di chuyển bất cứ thứ gì ra khỏi mã trước khi nó tự nhiên thông qua tái cấu trúc là điều hợp lý. Bắt đầu với một ngôn ngữ, thêm ngôn ngữ khác - tại một số điểm, việc triển khai IL LanguageRule sẽ chia sẻ đủ mã mà hiệu quả hơn khi có một triển khai duy nhất được tham số hóa bằng XML (hoặc tệp khác). Nhưng ngay cả sau đó bạn có thể kết thúc với tiếng Nhật có cấu trúc hoàn toàn khác. Bắt đầu bằng cách đẩy giao diện của bạn thành XML (hoặc tương tự) chỉ cầu xin có những thay đổi trong giao diện hơn là việc thực hiện.
ptyx

2
Lưu ý: nếu bạn muốn thêm nhiều ngôn ngữ, điều đó không có nghĩa là chuyển ngôn ngữ sang tệp cấu hình! Bạn cũng có thể có một LanguageProcessorlớp với nhiều lớp con. (Thực tế, "tệp cấu hình" thực sự là một lớp)
user253751

2
@MainMa: Tại sao bạn coi đó là một vấn đề cần biên dịch lại khi thêm một từ? Bạn phải biên dịch lại khi thực hiện bất kỳ thay đổi nào khác đối với mã và danh sách các từ có lẽ là một phần của mã ít có khả năng thay đổi theo thời gian.
JacquesB

3
Tôi nghi ngờ rằng tính linh hoạt của việc có thể mã hóa các quy tắc ngữ pháp rất cụ thể của từng ngôn ngữ trong một lớp con sẽ thuận tiện hơn so với khả năng tải các quy tắc tương tự bằng cách nào đó từ tệp cấu hình (vì về cơ bản bạn đang viết ngôn ngữ lập trình riêng để giải thích các cấu hình).
David K

15

Các chuỗi nên được trích xuất thành tệp cấu hình hoặc cơ sở dữ liệu khi các giá trị có thể thay đổi độc lập với logic chương trình.

Ví dụ:

  • Trích xuất văn bản UI vào các tệp tài nguyên. Điều này cho phép một người không lập trình viên chỉnh sửa và đọc bằng chứng các văn bản và nó cho phép thêm các ngôn ngữ mới bằng cách thêm các tệp tài nguyên cục bộ mới.

  • Trích xuất chuỗi kết nối, url đến các dịch vụ bên ngoài, vv để tập tin cấu hình. Điều này cho phép bạn sử dụng các cấu hình khác nhau trong các môi trường khác nhau và để thay đổi cấu hình nhanh chóng vì chúng có thể cần thay đổi vì lý do bên ngoài ứng dụng của bạn.

  • Một trình kiểm tra chính tả có từ điển các từ để kiểm tra. Bạn có thể thêm từ mới và ngôn ngữ mà không cần sửa đổi logic chương trình.

Nhưng cũng có một chi phí phức tạp với việc trích xuất cấu hình, và nó không phải lúc nào cũng có ý nghĩa.

Chuỗi có thể được mã hóa cứng khi chuỗi thực tế không thể thay đổi mà không thay đổi logic chương trình.

Ví dụ:

  • Một trình biên dịch cho một ngôn ngữ lập trình. Các từ khóa không được trích xuất thành một cấu hình, vì mỗi từ khóa có ngữ nghĩa cụ thể phải được hỗ trợ bởi mã trong trình biên dịch. Thêm một từ khóa mới sẽ luôn yêu cầu thay đổi mã, vì vậy không có giá trị trong việc trích xuất các chuỗi vào một tệp cấu hình.
  • Thực hiện một giao thức: Ví dụ. một máy khách HTTP sẽ có các chuỗi được mã hóa cứng như "GET", "kiểu nội dung", v.v ... Ở đây, chuỗi là một phần của đặc tả của giao thức, vì vậy chúng là các phần của mã ít có khả năng thay đổi nhất.

Trong trường hợp của bạn, tôi nghĩ rõ ràng rằng các từ là một phần tích hợp của logic chương trình (vì bạn đang xây dựng một liên hợp với các quy tắc cụ thể cho các từ cụ thể) và trích xuất các từ này vào một tệp bên ngoài không có giá trị.

Nếu bạn thêm một ngôn ngữ mới, bạn sẽ cần thêm mã mới, vì mỗi ngôn ngữ có logic liên hợp cụ thể.


Một số người đã gợi ý rằng bạn có thể thêm một số loại công cụ quy tắc cho phép bạn chỉ định quy tắc chia động từ cho các ngôn ngữ tùy ý, do đó, các ngôn ngữ mới có thể được thêm hoàn toàn bằng cấu hình. Hãy suy nghĩ thật kỹ trước khi bạn đi vào con đường đó, bởi vì ngôn ngữ của con người rất kỳ lạ, vì vậy bạn cần công cụ quy tắc rất biểu cảm. Về cơ bản, bạn sẽ phát minh ra một ngôn ngữ lập trình mới (DSL liên hợp) để mang lại lợi ích đáng ngờ. Nhưng bạn đã có một ngôn ngữ lập trình theo ý của bạn, có thể làm bất cứ điều gì bạn cần. Trong mọi trường hợp, YAGNI.


1
Trên thực tế, trong một bình luận cho MainMa, tôi đã đề cập rằng việc viết DSL cho việc này sẽ là vô nghĩa vì rất ít ngôn ngữ tự nhiên đủ tương tự để khiến nó đáng để nỗ lực. Có thể tiếng Pháp / tiếng Tây Ban Nha / tiếng Ý sẽ đủ gần , nhưng không thực sự xứng đáng với nỗ lực bổ sung khi xem xét rằng số lượng quy tắc rất tĩnh trong bất kỳ ngôn ngữ nào. Những điểm khác mà bạn đề cập về sự phức tạp là những lo lắng chính xác của tôi và tôi nghĩ bạn đã hiểu một cách tuyệt vời những gì tôi đã hỏi trong câu hỏi của tôi và đã đưa ra một câu trả lời tuyệt vời với các ví dụ, vì vậy +1!
Chris Cirefice

5

Tôi đồng ý 100% với câu trả lời của Dan Pichelman, nhưng tôi muốn thêm một điều nữa. Câu hỏi bạn nên tự hỏi mình ở đây là "ai sẽ duy trì / mở rộng / sửa danh sách từ?". Nếu luôn luôn là người duy trì các quy tắc của một ngôn ngữ cụ thể (nhà phát triển cụ thể, tôi đoán là bạn), thì không có lý do gì để sử dụng tệp cấu hình bên ngoài nếu điều này làm cho mọi thứ phức tạp hơn - bạn sẽ không nhận được bất kỳ lợi ích nào từ điều này. Từ quan điểm này, sẽ hợp lý khi mã hóa các danh sách từ đó ngay cả khi bạn phải thay đổi chúng theo thời gian, miễn là đủ để cung cấp một danh sách mới như là một phần của phiên bản mới.

(Mặt khác, nếu có một cơ hội nhỏ, người khác phải có thể duy trì danh sách trong tương lai hoặc nếu bạn cần thay đổi danh sách từ mà không triển khai phiên bản mới của ứng dụng, thì hãy sử dụng một tệp riêng.)


Đây là một điểm tốt - tuy nhiên, tôi rất có khả năng tôi sẽ là người duy nhất thực sự duy trì mã, ít nhất là trong vài năm tới. Điểm hay của việc này là mặc dù các chuỗi sẽ được mã hóa cứng, nhưng đó là một chuỗi các quy tắc / quy tắc rất nhỏ không thể thay đổi bất cứ lúc nào sớm (vì đó là ngôn ngữ tự nhiên, không phát triển quá nhiều trong năm -năm). Điều đó nói rằng, các quy tắc chia động từ, chuỗi chấm dứt động từ, v.v ... rất có thể sẽ giống nhau cho cả cuộc đời của chúng ta :)
Chris Cirefice

1
@ChrisCirefice ": chính xác là quan điểm của tôi.
Doc Brown

2

Ngay cả khi mã hóa cứng có vẻ tốt ở đây và tốt hơn là tải động các tệp cấu hình, tôi vẫn khuyên bạn nên tách riêng dữ liệu của mình (từ điển động từ) khỏi thuật toán . Bạn có thể biên dịch chúng ngay vào ứng dụng của bạn trong quá trình xây dựng.

Điều này sẽ giúp bạn tiết kiệm rất nhiều sự hấp dẫn với việc duy trì danh sách. Trong VCS của bạn, bạn có thể dễ dàng xác định liệu một cam kết đã thay đổi thuật toán hay chỉ sửa một lỗi liên hợp. Ngoài ra, danh sách có thể cần phải được thêm vào trong tương lai cho các trường hợp bạn không xem xét. Đặc biệt, số lượng 32 động từ bất quy tắc bạn đếm không có vẻ chính xác. Trong khi những thứ đó dường như bao gồm những cái thường được sử dụng, tôi đã tìm thấy các tài liệu tham khảo đến 133 hoặc thậm chí 350 trong số chúng.


Bergi, tôi đã có kế hoạch tách dữ liệu khỏi thuật toán. Những gì bạn lưu ý về các quy định của Pháp - định nghĩa của bất thường bị hiểu nhầm là tốt nhất. Ý tôi là khi tôi nói không đều là những động từ không thể 'tính toán', hoặc được kết hợp từ dạng nguyên bản của chúng. Các động từ bất quy tắc hoàn toàn không có mẫu đặc biệt nào, và do đó cần phải có các cách chia động từ được liệt kê rõ ràng (theo French.Verb.Conjugation.Iruity` chẳng hạn). Về mặt kỹ thuật, các động từ -ir là 'không đều', nhưng chúng thực sự có một kiểu chia động từ cố định :)
Chris Cirefice

0

Phần quan trọng là tách mối quan tâm. Làm thế nào bạn đạt được điều đó là ít liên quan. tức là Java vẫn ổn

Không phụ thuộc vào cách các quy tắc được thể hiện, bạn có cần thêm ngôn ngữ thay đổi quy tắc: bạn phải chỉnh sửa bao nhiêu mã và tệp?

Một cách lý tưởng, việc thêm một ngôn ngữ mới là có thể bằng cách thêm tệp 'english.xml' hoặc một 'EnglishRules mới thực hiện đối tượng IL LanguageRules'. Tệp văn bản (JSON / XML) cung cấp cho bạn một lợi thế nếu bạn muốn thay đổi nó bên ngoài vòng đời xây dựng của mình, nhưng yêu cầu một ngữ pháp phức tạp, phân tích cú pháp và sẽ khó gỡ lỗi hơn. Một tệp mã (Java) cho phép bạn thể hiện các quy tắc phức tạp theo cách đơn giản hơn, nhưng yêu cầu xây dựng lại.

Tôi sẽ bắt đầu với một API Java đơn giản đằng sau một giao diện bất khả tri ngôn ngữ sạch - vì bạn cần điều đó trong cả hai trường hợp. Bạn luôn có thể thêm việc triển khai giao diện đó được hỗ trợ bởi một tệp XML sau nếu bạn muốn, nhưng tôi không thấy cần phải giải quyết vấn đề đó ngay lập tức (hoặc bao giờ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.