Làm thế nào để tách mã và dữ liệu trở thành một thông lệ?


29

Xin vui lòng đọc câu hỏi cẩn thận: nó hỏi làm thế nào , không phải tại sao .

Gần đây tôi đã bắt gặp câu trả lời này , trong đó gợi ý sử dụng cơ sở dữ liệu để lưu trữ dữ liệu bất biến:

Nghe có vẻ như nhiều con số ma thuật mà bạn mô tả - đặc biệt nếu chúng phụ thuộc một phần - thực sự là dữ liệu, không phải mã. [...] Nó có thể có nghĩa là một cơ sở dữ liệu kiểu SQL hoặc có thể chỉ đơn giản là một tệp văn bản được định dạng.

Dường như với tôi rằng nếu bạn có dữ liệu là một phần của những gì chương trình của bạn làm, thì điều cần làm là đưa nó vào chương trình . Ví dụ, nếu chức năng của chương trình của bạn là đếm nguyên âm, có gì sai khi có vowels = "aeiou"trong đó? Xét cho cùng, hầu hết các ngôn ngữ đều có cấu trúc dữ liệu được thiết kế để sử dụng chính xác. Tại sao bạn phải phân tách dữ liệu bằng cách đặt nó vào "tệp văn bản có định dạng", như được đề xuất ở trên? Tại sao không làm cho tệp văn bản đó được định dạng bằng ngôn ngữ lập trình bạn chọn? Bây giờ nó là một cơ sở dữ liệu? Hay là mã?

Tôi chắc chắn một số người sẽ nghĩ rằng đây là một câu hỏi ngớ ngẩn, nhưng tôi hoàn toàn nghiêm túc hỏi nó. Tôi cảm thấy như "mã và dữ liệu riêng biệt" đang nổi lên một cách văn hóa như một sự thật hiển nhiên nào đó, cùng với những điều hiển nhiên khác như "đừng đặt tên biến của bạn" và "đừng tránh sử dụng khoảng trắng chỉ vì ngôn ngữ của bạn xem xét nó không đáng kể ".

Lấy ví dụ, bài viết này: Vấn đề tách dữ liệu khỏi mã rối . Vấn đề ? Có vấn đề gì vậy? Nếu Puppet là ngôn ngữ để mô tả cơ sở hạ tầng của tôi, tại sao nó cũng không thể mô tả rằng máy chủ tên là 8.8.8.8? Dường như với tôi rằng vấn đề không phải là mã và dữ liệu được trộn lẫn, 1 nhưng điều đó Múa rối thiếu đủ giàu cấu trúc dữ liệu và cách để giao diện để những thứ khác.

Tôi thấy sự thay đổi này đáng lo ngại. Lập trình hướng đối tượng cho biết "chúng tôi muốn các cấu trúc dữ liệu phong phú tùy ý" và do đó, các cấu trúc dữ liệu được ban cho sức mạnh của mã. Kết quả là bạn được đóng gói và trừu tượng hóa. Ngay cả cơ sở dữ liệu SQL cũng có các thủ tục lưu trữ. Khi bạn sắp xếp dữ liệu vào YAML hoặc tệp văn bản hoặc cơ sở dữ liệu câm như thể bạn đang loại bỏ một khối u khỏi mã, bạn sẽ mất tất cả.

Bất cứ ai cũng có thể giải thích cách thực hành tách dữ liệu này khỏi mã được thực hiện và nó sẽ đi đến đâu? Bất cứ ai cũng có thể trích dẫn các ấn phẩm bằng ánh sáng, hoặc cung cấp một số dữ liệu có liên quan chứng minh "mã riêng biệt khỏi dữ liệu" như một điều răn mới nổi và minh họa nguồn gốc của nó?

1: nếu người ta thậm chí có thể tạo ra sự khác biệt như vậy. Tôi đang nhìn bạn, lập trình viên Lisp.


5
Vui lòng chôn tất cả các html & css bằng ngôn ngữ bạn chọn.
JeffO

3
Tôi nghĩ điều mà tác giả của trích dẫn có nghĩa là những con số ma thuật không thực sự bất biến.
Pieter B

4
Không có gì sai với các nguyên âm mã hóa cứng. Nếu ứng dụng của bạn sẽ chỉ được sử dụng để đếm các nguyên âm bằng tiếng Anh.
Michael Paulukonis

3
Một lý do kỹ thuật lớn để phân tách mã và dữ liệu là không phải biên dịch lại mã khi dữ liệu thay đổi. Do đó, tôi đặt câu hỏi liệu nó có áp dụng cho cùng mức độ với các ngôn ngữ scripting hay không.
dùng16764

1
@MichaelPaulukonis: Và đưa nó vào cơ sở dữ liệu là một giải pháp giả mạo. Những thay đổi cần thiết cho tiếng Hà Lan? Không (thậm chí không thay đổi DB). Thay đổi cần thiết cho tiếng Pháp / tiếng Đức? Ít nhất là hỗ trợ ISO-8859-1. (Hơn DB). Thay đổi cần thiết cho Hy Lạp / Nga? Hỗ trợ Unicode (hơn DB). Trên thực tế, tôi không thể nghĩ ra bất kỳ ngôn ngữ nào mà DB đó có ích gì.
MSalters

Câu trả lời:


22

Có nhiều lý do tốt để tách dữ liệu khỏi mã và một số lý do không nên. Sau đây đến với tâm trí.

Tính kịp thời. Khi nào giá trị dữ liệu được biết đến? Có phải tại thời điểm mã được viết, khi nó được biên dịch, liên kết, phát hành, cấp phép, cấu hình, bắt đầu thực thi hoặc trong khi chạy. Ví dụ: số ngày trong một tuần (7) được biết sớm, nhưng tỷ giá USD / AUD sẽ được biết khá muộn.

Kết cấu. Đây có phải là một thời gian dữ liệu được đặt theo một xem xét duy nhất, hoặc nó có thể được kế thừa hoặc là một phần của một bộ sưu tập lớn hơn của các mục không? Các ngôn ngữ như YAML và JSON cho phép kết hợp giá trị từ nhiều nguồn. Có lẽ một số thứ ban đầu có vẻ bất biến được truy cập tốt hơn như các thuộc tính trong trình quản lý cấu hình.

Địa phương. Nếu tất cả các mục dữ liệu được lưu trữ ở một số nơi hạn chế, việc quản lý chúng sẽ dễ dàng hơn nhiều, đặc biệt nếu một số mục có thể cần phải thay đổi thành giá trị mới (không thay đổi). Chỉnh sửa mã nguồn chỉ để thay đổi giá trị dữ liệu dẫn đến nguy cơ thay đổi và lỗi vô ý.

Tách biệt mối quan tâm. Làm cho các thuật toán hoạt động chính xác được tách biệt tốt nhất với việc xem xét sử dụng giá trị dữ liệu nào. Dữ liệu là cần thiết để kiểm tra các thuật toán, không phải là một phần của chúng. Xem thêm http://c2.com/cgi/wiki?ZeroOneInfinityRule .

Trả lời câu hỏi của bạn đây không phải là một điều mới. Các nguyên tắc cốt lõi đã không thay đổi trong hơn 30 năm và đã được viết về nhiều lần trong thời gian đó. Tôi có thể nhớ lại không có ấn phẩm lớn về chủ đề này vì nó thường không được coi là gây tranh cãi, chỉ là một cái gì đó để giải thích cho người mới. Có thêm một chút ở đây: http://c2.com/cgi/wiki?SeparationOfDataAndCode .

Kinh nghiệm cá nhân của tôi là tầm quan trọng của sự tách biệt này trong một phần mềm cụ thể trở nên lớn hơn theo thời gian chứ không phải ít hơn. Các giá trị được mã hóa cứng được chuyển vào các tệp tiêu đề, các giá trị được biên dịch được chuyển vào các tệp cấu hình, các giá trị đơn giản trở thành một phần của cấu trúc phân cấp và được quản lý.

Theo xu hướng, tôi chưa thấy bất kỳ thay đổi lớn nào trong thái độ của các lập trình viên chuyên nghiệp (hơn 10 năm), nhưng ngành công nghiệp này ngày càng đầy những người trẻ và nhiều điều tôi nghĩ đã biết và quyết định tiếp tục bị thách thức và sáng tạo, đôi khi không còn mới hiểu biết nhưng đôi khi ra khỏi vô minh.


2
Bạn có thể mở rộng về lịch sử và xu hướng của thực hành này? Nếu mọi người đưa ra những cân nhắc này, tôi sẽ không đặt câu hỏi. Tiền đề của câu hỏi là mọi người không cẩn thận xem xét dữ liệu của họ nên đi đâu (các hằng số được biên dịch, cơ sở dữ liệu bên ngoài, YAML ...) mà họ chỉ nghĩ rằng "MÃ VÀ DỮ LIỆU BỊ XÓA! HULK SMASH!" Tại sao hoặc khi nào điều này trở thành một điều?
Phil Frost

Đó không phải là một phần kinh nghiệm của tôi, vì vậy tôi không thể nói với bạn. Tôi đã thêm một vài ký sinh vào câu trả lời của tôi.
david.pfx

Tôi nghĩ rằng "dòng người trẻ" là một lời giải thích hợp lệ, nhưng tôi không chấp nhận vì tôi muốn nghe từ một số những người trẻ này để xem họ có ý tưởng ở đâu. Rõ ràng họ có phần "mã và dữ liệu riêng biệt", nhưng tôi không nghĩ họ có phần còn lại. Họ đã đọc nó trong một bài viết trên blog? Một quyển sách? Ở đâu và khi nào?
Phil Frost

Bạn sẽ luôn nhận được "_____ BAD! HULK SMASH!" - điều đó không có nghĩa là nó đúng. Thông thường loại điều này (ví dụ: "'GOTO' BAD! HULK SMASH!") Được dạy cho người mới bắt đầu, mà không dạy họ tại sao, hoặc ngoại lệ là gì.
AMADANON Inc.

Localitycũng hoạt động ngược lại: Chúng tôi đã kết thúc với một loại hệ thống plugin do yêu cầu tùy chỉnh cho các khách hàng khác nhau, và qua nhiều năm thử nghiệm và lỗi đã học được để loại bỏ các hằng số của họ (thậm chí cả bảng, bằng cách liệt kê các danh sách) của cơ sở dữ liệu và trong mã. Cả hai vì sử dụng nó ở bất cứ đâu ngoài "plugin" đó đều không chính xác và vì các thay đổi được tự động phiên bản khi có thay đổi.
Izkata

8

Dữ liệu quy mô tốt hơn nhiều, và có thể được truy vấn và sửa đổi dễ dàng hơn nhiều, khi nó được tách ra khỏi mã. Ngay cả khi dữ liệu của bạn có bản chất là mã hóa - ví dụ: dữ liệu của bạn đại diện cho các quy tắc hoặc lệnh - nếu bạn có thể lưu trữ đại diện cho mã đó dưới dạng dữ liệu có cấu trúc, bạn có thể tận hưởng các lợi ích của việc lưu trữ riêng:

quyền

Nếu dữ liệu được mã hóa cứng, bạn sẽ cần chỉnh sửa tệp nguồn để chỉnh sửa dữ liệu đó. Điều đó có nghĩa là:

  • Chỉ nhà phát triển mới có thể chỉnh sửa dữ liệu. Điều này là xấu - nhập dữ liệu không phải là một cái gì đó đòi hỏi kỹ năng và kiến ​​thức của nhà phát triển.

  • Người không phát triển có thể chỉnh sửa tệp nguồn. Điều này là xấu - họ có thể làm hỏng tập tin nguồn mà không hề biết!

  • Dữ liệu được mã hóa cứng thành các tệp nguồn riêng biệt và những người không phải là nhà phát triển chỉ có quyền truy cập vào các tệp đó. Nhưng điều này không thực sự được tính - bây giờ dữ liệu được tách ra khỏi mã và được lưu trữ trong các tệp của chính nó ...

chỉnh sửa

Vì vậy, về việc ai có thể chỉnh sửa dữ liệu, tốt nhất nên lưu trữ riêng. Làm thế nào về cách họ sẽ chỉnh sửa dữ liệu? Nếu bạn có nhiều dữ liệu, việc gõ bằng tay sẽ rất tẻ nhạt và dễ bị lỗi. Có một số UI cho điều này là tốt hơn nhiều! Ngay cả khi bạn vẫn phải nhập tất cả mọi thứ, bạn sẽ không phải nhập bảng nồi hơi của định dạng, do đó, sẽ ít có cơ hội bạn làm hỏng định dạng và vặn toàn bộ tệp!

Nếu dữ liệu được mã hóa cứng, việc tạo UI đó sẽ có nghĩa là một công cụ tự động sẽ chỉnh sửa các tệp nguồn viết tay của bạn. Hãy để nó chìm vào - một công cụ tự động sẽ mở các tệp nguồn của bạn, cố gắng tìm vị trí của dữ liệu và sửa đổi mã đó. Brrr ... Microsoft đã giới thiệu các lớp một phần cho C # chỉ để tránh những điều đó ...

Nếu dữ liệu là riêng biệt, công cụ tự động của bạn sẽ chỉ phải chỉnh sửa các tệp dữ liệu. Tôi muốn tin rằng các chương trình máy tính chỉnh sửa các tệp dữ liệu ngày nay không phải là hiếm ...

nhân rộng

Mã và quy mô dữ liệu rất khác nhau. Khi mã của bạn phát triển, bạn muốn tách nó thành nhiều lớp và phương thức hơn (hoặc cấu trúc dữ liệu và hàm), nhưng dữ liệu của bạn - bất kể nó tăng bao nhiêu - bạn muốn giữ ở một nơi. Ngay cả khi bạn phải tách nó thành nhiều tệp, bạn vẫn muốn kết hợp các tệp đó lại với nhau bằng cách nào đó, vì vậy việc truy cập dữ liệu đó từ mã sẽ dễ dàng hơn.

Vì vậy, hãy tưởng tượng rằng bạn có hàng ngàn dòng dữ liệu trong một tệp nguồn. Trình biên dịch / trình thông dịch phải đi qua tất cả dữ liệu đó mỗi khi nó đọc tệp và phân tích nó với trình phân tích và trình phân tích cú pháp đắt tiền - ngay cả khi bạn sẽ không truy cập dữ liệu đó trong lần chạy chương trình cụ thể này. Ngoài ra, khi bạn chỉnh sửa mã thực tế trong tệp đó, bạn phải đi xung quanh dữ liệu, điều này làm cồng kềnh toàn bộ quá trình. Ngoài ra, các tệp dữ liệu có thể được lập chỉ mục. Dữ liệu mã hóa cứng? Không nhiều lắm...

đang tìm kiếm

Bạn có hàng tấn dữ liệu - đó là điều tự nhiên bạn sẽ muốn tìm kiếm thông qua nó.

  • Nếu bạn lưu trữ nó trong cơ sở dữ liệu - bạn có thể sử dụng ngôn ngữ truy vấn cơ sở dữ liệu.

  • Nếu bạn lưu trữ nó trong một tệp XML - bạn có thể sử dụng XPath.

  • Nếu bạn lưu trữ nó trong JSON / YAML - bạn có thể tải nó bằng REPL của ngôn ngữ kịch bản yêu thích của bạn và tìm kiếm nó.

  • Ngay cả khi bạn lưu trữ nó trong tệp văn bản cũ, vì nó có cấu trúc, chương trình của bạn có thể nhận ra bạn có thể sử dụng grep / sed / awk để tìm kiếm nó.

Mặc dù đúng là bạn cũng có thể grep / sed / awk thông qua dữ liệu được mã hóa cứng trong tệp nguồn, nhưng nó cũng không hoạt động, vì truy vấn của bạn có thể khớp với các dòng khác, không liên quan hoặc bỏ lỡ các dòng được viết khác vì cú pháp biểu diễn dữ liệu của ngôn ngữ lập trình cho phép nó.

Có các công cụ để tìm kiếm thông qua mã, nhưng chúng tốt cho việc tìm kiếm khai báo, không phải dữ liệu được mã hóa cứng.

Điều đó đang được nói ...

Điều rất quan trọng để phân biệt giữa dữ liệu và mã. Chỉ vì một cái gì đó được viết dưới dạng mã không có nghĩa là nó không thể là dữ liệu. Và chỉ vì một cái gì đó được viết với biểu diễn dữ liệu không có nghĩa là trên thực tế, đó không phải là mã.

Tôi đã có một lớp học khi chúng tôi có các quy tắc rất nghiêm ngặt về "số ma thuật" - chúng tôi không thể có bất kỳ số nào trong mã của mình. Điều đó có nghĩa là chúng tôi phải làm những việc như:

#define THE_NUMBER_ZERO 0
//....
for(int i=THE_NUMBER_ZERO;i<cout;++i){
//....

đó là hoàn toàn vô lý! Vâng, 0về mặt kỹ thuật là "dữ liệu", nhưng nó chỉ là một phần của mã như phần còn lại của forvòng lặp! Vì vậy, mặc dù chúng ta có thể biểu diễn nó dưới dạng dữ liệu và tách nó ra khỏi mã, điều đó không có nghĩa là chúng ta nên làm . Không phải vì chúng tôi muốn để lại dữ liệu bên trong mã, mà bởi vì đó không thực sự là dữ liệu - không nhiều hơn phần còn lại của mã, cũng được biên dịch thành mã và số không ...


7

Tôi nghĩ rằng có một số nhầm lẫn đang xảy ra. Bạn đang trộn hai thứ lại với nhau: "Tách mã và dữ liệu" và "diễn tả hành vi của chương trình dưới dạng dữ liệu".

Trong trường hợp của bạn, bạn thực sự lo lắng về cái thứ hai và trộn cái thứ nhất vào nó. Khi bạn thể hiện hành vi của chương trình dưới dạng dữ liệu, việc mở rộng sẽ dễ dàng hơn. Trong ví dụ của bạn với vowels = "aeiou", sau đó thêm nguyên âm mới cũng đơn giản như thêm một ký tự. Nếu bạn có dữ liệu này ở bên ngoài, bạn có thể thay đổi hành vi này mà không phải biên dịch lại chương trình.

Và khi bạn nghĩ về nó, OOP là sự mở rộng của suy nghĩ này. Liên kết dữ liệu và hành vi với nhau sẽ cho phép bạn thay đổi hành vi của chương trình dựa trên dữ liệu của chương trình.


2
Nguyên nhân tự nhiên, danh sách các nguyên âm sẽ thay đổi.
cHao

13
@cHao Ngay khi i18n bước vào, nó là.
Phục hồi Monica

2
i18n có thể phá vỡ đầu của bạn - xem một số ví dụ đồi trụy trong Java trong javaspecialists.eu/archive/Issue209.html
Rory Hunter

2
@Angew: Tuy nhiên, ngay sau khi i18n bước vào, dù sao bạn cũng bị lừa . Bạn cần mã cho việc này; giải pháp ngây thơ không có khả năng xử lý mọi trường hợp ngay cả bằng tiếng Anh. (Hãy quên đi ïtrong một giây; talk let về yw!) Moving danh sách ra một cơ sở dữ liệu sẽ không khắc phục điều đó, và thực sự là có hại - đó là sự phức tạp đó sẽ vô giá trị nếu được thực hiện sai, nhưng bạn sẽ không thậm chí biết "sai" là gì trừ khi bạn thiết kế cho i18n từ đầu. Tại thời điểm đó, bạn đã nhận ra rằng một danh sách các nguyên âm sẽ không bị cắt đi.
cHao

1
@BenLee: Thật ra tôi sẽ không ngạc nhiên chút nào. Tôi hiện đang làm việc để thay đổi một số mã như chúng ta nói. Nhưng gia công tất cả mọi thứ cho cơ sở dữ liệu là bói toán của một loại khác. Nếu bạn chưa biết liệu có cần phải sửa đổi hay không - và quan trọng hơn, nếu bạn chưa biết cần phải sửa đổi như thế nào - thì IMO tốt hơn là đợi cho đến khi bạn cần sự linh hoạt đó trước khi thêm nó .
cHao

5

Ví dụ: nếu chức năng của chương trình của bạn là đếm nguyên âm, thì có gì sai khi có nguyên âm = "aeiou" trong đó?

Lưu trữ cấu hình bên ngoài cho phép bạn có một phiên bản mã dự kiến ​​sẽ hoạt động với nhiều cấu hình, thay thế là duy trì nhiều phiên bản phần mềm chỉ khác nhau về cấu hình.

Bạn đề cập đến nguyên âm = "aeiou", nếu đôi khi tôi muốn "y", tôi có phải xây dựng lại toàn bộ chương trình không? Bây giờ tôi có thể nâng cấp phiên bản dễ dàng khi tôi đã sửa đổi mã không? Nếu có lỗi, tôi đã gây ra lỗi hay chương trình bị hỏng?

Nếu điều này nằm trong chương trình của bạn, điều đó có nghĩa là chương trình của bạn không mong muốn người dùng thay đổi định nghĩa nguyên âm mà không quét mã để xem các tác dụng phụ có thể xảy ra. Nếu định nghĩa được lưu trữ bên ngoài, nó ngụ ý rằng chương trình không được phá vỡ đối với bất kỳ giá trị hợp lý nào được đặt trong cấu hình.

Khi bạn sắp xếp dữ liệu vào YAML hoặc tệp văn bản hoặc cơ sở dữ liệu câm như thể bạn đang loại bỏ một khối u khỏi mã

Một số người xem nó ngược lại, nghĩa là bạn đang loại bỏ khối u mã khỏi dữ liệu quý giá của mình, xem: Trích dẫn của Torvalds về lập trình viên giỏi


4
Trích dẫn Torvalds đề cập đến cấu trúc dữ liệu, không phải dữ liệu.
dùng949300

OP tuyên bố: "Lập trình hướng đối tượng cho biết" chúng tôi muốn các cấu trúc dữ liệu phong phú tùy ý "và do đó, các cấu trúc dữ liệu được ban cho sức mạnh của mã."
FMJaguar

1
Nếu bạn thực hiện một thay đổi cơ bản cho định nghĩa về nguyên âm là gì, bạn sẽ cần phải chạy lại tất cả các bài kiểm tra tự động. Các hệ thống hiếm khi có khả năng chạy lại các kiểm tra khi tệp cấu hình thay đổi trên hệ thống được triển khai. Vì vậy, định nghĩa như vậy cần phải được xây dựng vào hệ thống; có lẽ là hai bộ mã hóa cứng với tùy chọn cấu hình để chọn giữa chúng.
soru

+1 cho trích dẫn của Torvalds. Tôi đồng ý với tình cảm này: trong ví dụ về con rối, tôi nghĩ vấn đề là con rối không có cấu trúc dữ liệu tốt để thể hiện thông tin mà mọi người muốn đưa vào. Thay vì sửa các cấu trúc dữ liệu, các nhà phát triển bù nhìn đã khẳng định rằng "dữ liệu trong mã" là vấn đề (tại sao? Đó là câu hỏi!) Và đã phát triển hiera , điều mà tôi thấy ít hơn là di chuyển vấn đề sang một nơi khác, và thêm vào đó là không thể để liên kết hành vi với dữ liệu.
Phil Frost

2

Tôi đã tham gia một dự án mà người dẫn đầu khăng khăng đưa dữ liệu tham khảo vào các bảng nhỏ và tôi nghĩ điều đó thật ngớ ngẩn. Nhưng vì chúng tôi đã thiết lập cơ sở hạ tầng và kết nối bền bỉ, nên cuối cùng chi phí khá thấp so với các hoạt động kiên trì khác mà chúng tôi đang thực hiện.

Bây giờ, tôi vẫn nghĩ rằng đó là một quyết định ngớ ngẩn và nếu chúng tôi không có cơ sở hạ tầng trong tay, tôi sẽ không làm điều đó.

Nhưng một số lý lẽ ủng hộ tôi thấy là:

  • Nếu bạn có tư duy cơ sở dữ liệu, thì việc đưa dữ liệu tham chiếu vào cơ sở dữ liệu SQL cho phép bạn tham gia vào đó để báo cáo.
  • Nếu bạn có tiện ích quản trị hoặc truy cập vào cơ sở dữ liệu, thì bạn có thể điều chỉnh các giá trị khi chạy. (Mặc dù điều đó có thể được chơi với lửa.)

Ngoài ra, đôi khi chính sách cản trở việc thực hành mã hóa. Ví dụ: tôi đã làm việc tại một số cửa hàng trong đó việc đẩy tệp .xml là A-OK, trong khi chạm vào một dòng trong mã yêu cầu chu trình hồi quy đầy đủ và có thể là kiểm tra tải. Vì vậy, có một nhóm tôi đã tham gia nơi các tệp .xml của tôi cho dự án cực kỳ phong phú (và có thể -heh- có thể chứa một số mã).

Tôi luôn tự hỏi mình có được hưởng lợi từ việc đẩy dữ liệu ra khỏi mã vào kho lưu trữ dữ liệu ngoài hay không, ngay cả khi đó chỉ là một tệp văn bản, nhưng tôi đã làm việc với những người chỉ xem nó như là lần đầu tiên của họ thúc đẩy.


3
Nhận xét tốt về các quy trình của cửa hàng, trong đó chỉnh sửa XML là "ok" nhưng chỉnh sửa cùng một thứ trong mã là một rắc rối lớn.
dùng949300

làm việc trong một cửa hàng nơi mọi thứ đều nằm trong cơ sở dữ liệu có thể, xuống các văn bản trên màn hình. Ngoài mã giao diện người dùng, điều duy nhất không có trong cơ sở dữ liệu là vị trí cơ sở dữ liệu và thông tin đăng nhập ...
jwenting

3
nó luôn luôn nghe có vẻ ngớ ngẩn cho đến một ngày, một người nào đó hỏi "chúng ta có thể cấu hình lại điều này cho người dùng X đang yêu cầu nó không", và sau đó nó dường như không quá ngớ ngẩn. Khách hàng chết tiệt :)
gbjbaanb

2
... và nếu ngày đó là "không bao giờ", thì đó là một thời gian dài cảm thấy ngớ ngẩn
Rob

2

Hãy để tôi hỏi bạn một câu hỏi hoàn toàn nghiêm túc: Theo quan điểm của bạn, sự khác biệt giữa "dữ liệu" và "mã" là gì?

Khi tôi nghe từ "dữ liệu", tôi nghĩ "trạng thái". Dữ liệu, theo định nghĩa, là thứ mà chính ứng dụng được thiết kế để quản lý, và do đó, chính là thứ mà ứng dụng không bao giờ có thể biết về thời gian biên dịch. Không thể mã hóa dữ liệu cứng, vì ngay khi bạn mã hóa cứng, nó sẽ trở thành hành vi - không phải dữ liệu.

Loại dữ liệu khác nhau tùy theo ứng dụng; một hệ thống hóa đơn thương mại có thể lưu trữ thông tin khách hàng và đặt hàng trong cơ sở dữ liệu SQL và chương trình đồ họa vector có thể lưu trữ dữ liệu hình học và siêu dữ liệu trong tệp nhị phân. Trong cả hai trường hợp này và mọi thứ ở giữa, có một sự tách biệt rõ ràng và không thể phá vỡ giữa mã và dữ liệu. Dữ liệu thuộc về người dùng , không phải lập trình viên, vì vậy nó không bao giờ có thể được mã hóa cứng.

Những gì bạn dường như đang nói đến là, sử dụng mô tả chính xác nhất về mặt kỹ thuật có sẵn cho từ vựng hiện tại của tôi: thông tin chi phối hành vi chương trình không được viết bằng ngôn ngữ lập trình chính được sử dụng để phát triển phần lớn ứng dụng.

Ngay cả định nghĩa này, ít mơ hồ hơn đáng kể so với chỉ từ "dữ liệu", có một vài vấn đề. Ví dụ, điều gì sẽ xảy ra nếu các phần quan trọng của chương trình được viết bằng các ngôn ngữ khác nhau? Cá nhân tôi đã làm việc trên một số dự án khoảng 50% C # và 50% JavaScript. Mã JavaScript có phải là "dữ liệu" không? Hầu hết mọi người sẽ nói không. Còn HTML thì sao, đó là "dữ liệu"? Hầu hết mọi người vẫn sẽ nói không.

Còn CSS thì sao? Đó là dữ liệu hay mã? Nếu chúng ta nghĩ rằng mã là thứ gì đó kiểm soát hành vi của chương trình, thì CSS không thực sự là mã, bởi vì nó chỉ (tốt, chủ yếu) ảnh hưởng đến ngoại hình chứ không phải hành vi. Nhưng nó cũng không thực sự là dữ liệu; Người dùng không sở hữu nó, ứng dụng thậm chí không thực sự sở hữu nó. Nó tương đương với mã cho một nhà thiết kế UI. Đó là mã- giống như , nhưng không hoàn toàn là mã.

Tôi có thể gọi CSS là một loại cấu hình, nhưng một định nghĩa thực tế hơn là nó chỉ đơn giản là mã trong một ngôn ngữ dành riêng cho tên miền . Đó là những gì XML, YAML và "tệp định dạng" khác của bạn thường đại diện. Và lý do chúng tôi sử dụng một ngôn ngữ dành riêng cho tên miền là vì nói chung, nó đồng thời ngắn gọn và biểu cảm hơn trong miền cụ thể của nó hơn là mã hóa thông tin tương tự trong ngôn ngữ lập trình đa năng như C hoặc C # hoặc Java.

Bạn có nhận ra định dạng sau?

{
    name: 'Jane Doe',
    age: 27,
    interests: ['cats', 'shoes']
}

Tôi chắc chắn rằng hầu hết mọi người làm; đó là JSON . Và đây là điều thú vị về JSON: Trong JavaScript, nó rõ ràng là mã và trong mọi ngôn ngữ khác, nó rõ ràng dữ liệu được định dạng . Hầu như mọi ngôn ngữ lập trình chính thống đều có ít nhất một thư viện để "phân tích cú pháp" JSON.

Nếu chúng ta sử dụng chính cú pháp tương tự bên trong một hàm trong tệp JavaScript, thì nó không thể là gì khác ngoài mã. Tuy nhiên, nếu chúng ta lấy JSON đó, chuyển nó vào một .jsontệp và phân tích nó trong một ứng dụng Java, đột nhiên nó là "dữ liệu". Điều đó thực sự có ý nghĩa?

Tôi lập luận rằng "dữ liệu" hoặc "cấu hình" hoặc "mã" là cố hữu với những gì được mô tả, không phải là cách nó được mô tả.

Nếu chương trình của bạn cần một từ điển 1 triệu từ để tạo một cụm mật khẩu ngẫu nhiên, bạn có muốn viết mã như thế này không:

var words = new List<string>();
words.Add("aa");
words.Add("aah");
words.Add("ahhed");
// snip 172836 more lines
words.Add("zyzzyva");
words.Add("zyzzyvas");

Hoặc bạn sẽ chuyển tất cả những từ đó vào một tệp văn bản được phân cách bằng dòng và bảo chương trình của bạn đọc từ đó? Sẽ không có vấn đề gì nếu danh sách từ không bao giờ thay đổi, đó không phải là câu hỏi về việc bạn mã hóa cứng hay mã hóa mềm (mà nhiều người coi là một mô hình chống khi áp dụng không phù hợp), đó đơn giản chỉ là một câu hỏi về định dạng nào là hiệu quả nhất và làm cho nó dễ dàng nhất để mô tả "công cụ", bất kể "công cụ" là gì. Nó khá là không liên quan cho dù bạn gọi nó là mã hay dữ liệu; đó là thông tin mà chương trình của bạn yêu cầu để chạy và định dạng tệp phẳng là cách thuận tiện nhất để quản lý và duy trì chương trình.

Giả sử bạn tuân theo các thực tiễn phù hợp, dù sao tất cả những thứ này sẽ đi vào kiểm soát nguồn, vì vậy bạn cũng có thể gọi nó là mã, chỉ là mã theo một định dạng khác và có lẽ rất tối giản. Hoặc bạn có thể gọi nó là cấu hình, nhưng điều duy nhất thực sự phân biệt mã với cấu hình là liệu bạn có ghi lại nó hay không và cho người dùng cuối biết cách thay đổi nó. Có lẽ bạn có thể phát minh ra một số đối số không có thật về cấu hình được diễn giải vào lúc khởi động hoặc thời gian chạy chứ không phải lúc biên dịch, nhưng sau đó bạn sẽ bắt đầu mô tả một số ngôn ngữ được gõ động và gần như chắc chắn bất cứ thứ gì có công cụ kịch bản được nhúng bên trong nó (ví dụ hầu hết các trò chơi). Mã và cấu hình là bất cứ điều gì bạn quyết định gắn nhãn chúng là, không hơn, không kém.

Bây giờ, có một nguy hiểm cho externalizing thông tin đó không phải là thực sự an toàn để sửa đổi (xem liên kết "mềm mã hóa" ở trên). Nếu bạn bên ngoài mảng nguyên âm của mình trong một tệp cấu hình và ghi lại nó dưới dạng tệp cấu hình cho người dùng cuối của bạn, thì bạn đang cung cấp cho họ một cách gần như hoàn hảo để phá vỡ ứng dụng của bạn, ví dụ như bằng cách đặt "q" làm nguyên âm. Nhưng đó không phải là vấn đề cơ bản với "phân tách mã và dữ liệu", nó đơn giản là ý nghĩa thiết kế tồi.

Những gì tôi nói với các nhà phát triển cơ sở là họ phải luôn luôn đặt bên ngoài các cài đặt mà họ mong muốn thay đổi theo từng môi trường. Điều đó bao gồm những thứ như chuỗi kết nối, tên người dùng, khóa API, đường dẫn thư mục, v.v. Chúng thể giống nhau trên hộp dev của bạn và trong sản xuất, nhưng có lẽ là không, và các sysadins sẽ quyết định cách chúng muốn nó trông như thế nào trong sản xuất, chứ không phải dev. Vì vậy, bạn cần một cách để áp dụng một nhóm cài đặt trên một số máy và các cài đặt khác được áp dụng trên các máy khác - ergo, tệp cấu hình bên ngoài (hoặc cài đặt trong cơ sở dữ liệu, v.v.)

Nhưng tôi nhấn mạnh rằng chỉ đơn giản là đưa một số "dữ liệu" vào một "tệp" không giống như việc đưa nó vào cấu hình. Đặt một từ điển các từ vào một tệp văn bản không có nghĩa là bạn muốn người dùng (hoặc CNTT) thay đổi nó, đó chỉ là một cách giúp các nhà phát triển dễ hiểu hơn những gì đang xảy ra và, nếu cần, hãy làm thỉnh thoảng thay đổi. Tương tự như vậy, việc đưa thông tin tương tự vào bảng cơ sở dữ liệu không nhất thiết được tính là ngoại ứng hóa hành vi, nếu bảng chỉ đọc và / hoặc DBA được hướng dẫn không bao giờ bắt vít với nó. Cấu hình ngụ ý rằng dữ liệu có thể thay đổi, nhưng trong thực tế được xác định bởi quy trình và trách nhiệm thay vì lựa chọn định dạng.

Vì vậy, để tóm tắt:

  • "Mã" không phải là một thuật ngữ được định nghĩa cứng nhắc. Nếu bạn mở rộng định nghĩa của mình để bao gồm các ngôn ngữ dành riêng cho tên miền và bất kỳ ngôn ngữ nào khác ảnh hưởng đến hành vi, rất nhiều ma sát rõ ràng này sẽ biến mất và tất cả sẽ có ý nghĩa. Bạn có thể có "mã" DSL không được biên dịch trong một tệp phẳng.

  • "Dữ liệu" ngụ ý thông tin thuộc sở hữu của người dùng hoặc ít nhất là một người nào đó không phải là nhà phát triển và thường không có sẵn tại thời điểm thiết kế. Nó không thể được mã hóa cứng ngay cả khi bạn muốn làm như vậy. Ngoại trừ có thể có mã tự sửa đổi , việc phân tách giữa mã và dữ liệu là vấn đề định nghĩa, không phải là sở thích cá nhân.

  • "Mã hóa mềm" có thể là một thực tiễn khủng khiếp khi được áp dụng quá mức, nhưng không phải mọi trường hợp ngoại hóa nhất thiết phải cấu thành mã hóa mềm, và nhiều trường hợp lưu trữ thông tin trong "tệp phẳng" không nhất thiết là một nỗ lực bên ngoài.

  • Cấu hình là một loại đặc biệt của phần mềm mã hóa đó cần thiết vì sự hiểu biết rằng các ứng dụng có thể cần phải chạy trong môi trường khác nhau. Việc triển khai một tệp cấu hình riêng cùng với ứng dụng là công việc ít hơn nhiều (và ít nguy hiểm hơn) so với việc triển khai một phiên bản mã khác nhau cho mọi môi trường. Vì vậy, một số loại mã hóa mềm thực sự hữu ích.


1

Tôi đề nghị đọc bài viết kinh điển này của Oren Eini (còn gọi là Ayende Rahien)

http://ayende.com/blog/3545/eneac-change-by-hard-coding-everything-the-smart-way

Điểm nổi bật của riêng tôi từ nó là tập trung vào sự đơn giản và dễ đọc. Điều này có thể có nghĩa là những thứ không có khả năng được cấu hình lại tốt nhất là được mã hóa cứng (có thể đọc được). Điều này cho phép bạn sử dụng cú pháp đầy đủ của ngôn ngữ lập trình để thể hiện các tham số, cũng như đạt được các hiệu ứng phụ có lợi như hoàn thành mã và lỗi trình biên dịch khi sử dụng sai.

Bằng cách này, bạn có khả năng tránh sự phức tạp của phân tích cú pháp / phiên dịch ("nhưng người khác phân tích cú pháp YAML / JSON của tôi" - ánh xạ văn bản được phân tích cú pháp vào các lệnh gọi API cụ thể có thể là một hình thức diễn giải) và tránh sự phức tạp của một bước khác giữa "dữ liệu" "Và công dụng của nó.

Một số trường hợp cho vay để được thể hiện bằng dữ liệu ngay cả trong một kịch bản như thế này: ví dụ: chỉ định hàng ngàn điểm trong không gian 3D có thể phù hợp hơn cho tệp văn bản so với mã, mặc dù trong một số ngôn ngữ, bao gồm C sử dụng trình khởi tạo cấu trúc, mã có thể thích hợp ngay cả cho điều đó.


1

Ok, giả sử bạn muốn viết một số loại chương trình c ++ để giải trí. Bạn biết chính xác những gì nó phải làm và những gì nó sẽ không bao giờ cần phải làm. Bây giờ lấy bất kỳ cuốn sách về "thiết kế phần mềm hiện đại". Đây là quy tắc của trò chơi: Đối với mọi lớp trong dự án của bạn và mọi trường hợp thậm chí rất nhỏ, bạn phải thực hiện từng mô hình ưa thích mà bạn tìm thấy được mô tả trong cuốn sách đó để biến mã của bạn thành "thiết kế sạch". Chà, "tiêm phụ thuộc" sẽ đủ cho nhiều người, tôi đoán vậy. (Đó là c ++, không phải java!) Lập trình được dạy từ quan điểm lý thuyết ngày càng nhiều. Nó không đủ để bạn hoàn thành công việc, bạn phải viết mã có thể bảo trì, đánh lừa chứng minh ... tất cả đều ổn và đúng. Vấn đề bắt đầu khi ppl. ngừng suy nghĩ về lý do thực tế, các mẫu thiết kế đã được phát minh và trở thành giáo điều.

Hãy để tôi ngăn bạn viết công cụ đếm thư bằng cách sử dụng một nguyên tắc chỉ định đơn giản duy nhất: Khi bạn viết mã thực hiện một công việc nhất định trên dữ liệu đầu vào của một loại nhất định, hãy đảm bảo rằng nó có thể thực hiện tác vụ đó cho bất kỳ đầu vào cụ thể nào dữ liệu của loại đó. - Khi bạn muốn viết một công cụ đếm chữ cái, rõ ràng có ý nghĩa khi viết nó theo cách để nó không chỉ có thể đếm nguyên âm, mà còn "bất kỳ chữ cái nào". - Vì bạn có thể không biết văn bản mà bạn đang phân tích cú pháp thực sự là gì, bạn cũng có thể chọn một mã hóa rất chung (UTF-16) và bao gồm hầu hết (tất cả?) Ngôn ngữ viết và ký hiệu của chúng.

Cho đến thời điểm đó, chúng ta có một hàm với hai đối số (kho văn bản và các chữ cái sẽ được tính). Chúng tôi chỉ quan tâm để tìm một "loại" hoặc "lớp" hợp lý chung, các chữ cái cũng thuộc về: chúng tôi chắc chắn có thể làm tốt hơn các ký hiệu ASCII!

Nhập một con quỷ có "tổng quát hóa và tái sử dụng" -dogma: - Tại sao không tính bất kỳ biểu tượng nào của bất kỳ lớp nào trong luồng đầu vào của lớp đó? (trừu tượng từ các chữ cái đến chuỗi bit có độ dài tùy ý nhưng hữu hạn vì đó là tổng quát nhất bạn có thể nhận được với máy tính ...) - Đợi đã, ngay cả khi đó chúng ta vẫn đang đếm số tự nhiên. Tuy nhiên, việc đếm có thể được khái quát hóa dưới dạng ánh xạ từ tập hợp đếm được sang chính nó đáp ứng các tiên đề ... [bạn hiểu ý tưởng]

Bây giờ ví dụ đó có thể là ngớ ngẩn, nhưng nếu bạn xem xét các nhiệm vụ thiết kế phức tạp hơn một công cụ đếm, bạn có thể tìm thấy tất cả cơ hội để giới thiệu trừu tượng bổ sung cần thiết theo một số mẫu thiết kế bạn tìm thấy trong sách của mình.

Sự thay đổi của "dữ liệu" và "mã" có thể sẽ là tầm thường (đối số hàm) hoặc bạn sẽ thấy mình coi bất biến là biến ("dữ liệu").

Nếu có bất kỳ sự nhầm lẫn nào thì có khả năng là "giao diện" và "dịch vụ" và tất cả các chi tiết cụ thể của lớp (ví dụ: các loại) đột nhiên là "dữ liệu", đó là các phụ thuộc được đưa vào từ bên ngoài. Tôi cảm thấy rằng các khóa học tin học được giảng dạy tại trường đại học đã trở nên giống như các bài giảng về triết học và có ít thời gian hơn cho các dự án thực tế để sinh viên có thể có kinh nghiệm về cách làm cho phần mềm hoạt động. Nếu bạn có bao giờ tự hỏi tại sao bạn bắt buộc phải sử dụng một mô hình cực kỳ phức tạp thay vì một giải pháp rõ ràng, thì sự phát triển này là (có khả năng) làm thế nào yêu cầu đó được "tạo ra" ...

Đối với vấn đề cụ thể của bạn: Nếu bạn có thể 1.) hãy viết một chương trình với tối đa mã hóa cứng cho trường hợp cụ thể của bạn và sau đó 2.) khái quát hóa từ mã đó theo cách đơn giản bằng cách ví dụ. giới thiệu nhiều đối số hàm và sử dụng các "mẫu tầm thường" khác, bạn có thể chắc chắn rằng mình đang tách mã và dữ liệu, theo cách rõ ràng, giống như nó đã được thực hiện kể từ khi lập trình hàm được phát minh. (bạn bỏ qua 1. và làm 2. ngay lập tức ...)

Bất cứ điều gì không rõ ràng ở đây đều có thể là trường hợp "bế tắc lý thuyết": Giống như viết một giao diện tham chiếu đến một giao diện và một giao diện khác ... và cuối cùng, bạn có một tệp xml nhỏ gọn để định cấu hình tất cả các giao diện này và các phụ thuộc được đưa vào lộn xộn giao diện lớp của bạn.

Hãy hy vọng, trình phân tích cú pháp xml mà bạn yêu cầu không cần xml-config để hoạt động ...

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.