Không có bất cứ điều gì đột biến cuối cùng thao túng nhà nước?
Đúng, nhưng nếu nó đứng sau một hàm thành viên của một lớp nhỏ là thực thể duy nhất trong toàn bộ hệ thống có thể thao túng trạng thái riêng tư của nó, thì trạng thái đó có phạm vi rất hẹp.
Bạn nên làm gì với trạng thái càng ít càng tốt?
Từ quan điểm của biến: càng ít dòng mã có thể truy cập nó càng tốt. Thu hẹp phạm vi của biến đến mức tối thiểu.
Từ quan điểm của dòng mã: càng ít biến số có thể truy cập được từ dòng mã đó càng tốt. Thu hẹp số lượng biến mà dòng mã có thể truy cập (thậm chí không quan trọng đến mức nó có truy cập được hay không, tất cả vấn đề là liệu nó có thể hay không ).
Biến toàn cầu là rất xấu bởi vì chúng có phạm vi tối đa. Ngay cả khi họ được truy cập từ 2 dòng mã trong một cơ sở mã, từ dòng POV của mã, một biến toàn cục luôn có thể truy cập được. Từ POV của biến, một biến toàn cục có liên kết ngoài có thể truy cập được đối với mọi dòng mã trong toàn bộ cơ sở mã (hoặc mọi dòng mã bao gồm tiêu đề nào). Mặc dù chỉ được truy cập thực sự bởi 2 dòng mã, nếu biến toàn cục hiển thị với 400.000 dòng mã, danh sách nghi phạm ngay lập tức của bạn khi bạn thấy nó được đặt thành trạng thái không hợp lệ thì sẽ có 400.000 mục nhập (có thể nhanh chóng giảm xuống 2 mục có công cụ, tuy nhiên, danh sách trước mắt sẽ có 400.000 nghi phạm và đó không phải là điểm khởi đầu đáng khích lệ).
Tương tự như vậy, ngay cả khi một biến toàn cục bắt đầu chỉ được sửa đổi bởi 2 dòng mã trong toàn bộ cơ sở mã, xu hướng đáng tiếc của các cơ sở mã hóa sẽ phát triển ngược lại sẽ có xu hướng tăng số lượng đó, đơn giản vì nó có thể tăng lên nhiều các nhà phát triển, điên cuồng đáp ứng thời hạn, xem biến toàn cầu này và nhận ra họ có thể dùng các phím tắt thông qua nó.
Trong một ngôn ngữ không tinh khiết như C ++, không phải quản lý nhà nước thực sự là những gì bạn đang làm sao?
Phần lớn, vâng, trừ khi bạn sử dụng C ++ theo cách rất kỳ lạ, bạn phải xử lý các cấu trúc dữ liệu bất biến tùy chỉnh và lập trình chức năng thuần túy - đó cũng thường là nguồn gốc của hầu hết các lỗi khi quản lý nhà nước trở nên phức tạp và phức tạp là thường là một chức năng của khả năng hiển thị / tiếp xúc của trạng thái đó.
Và những cách khác để đối phó với trạng thái càng ít càng tốt ngoài việc hạn chế tuổi thọ biến?
Tất cả những điều này nằm trong phạm vi giới hạn phạm vi của một biến, nhưng có nhiều cách để làm điều này:
- Tránh các biến toàn cầu thô như bệnh dịch hạch. Ngay cả một số hàm setter / getter toàn cầu câm làm thu hẹp khả năng hiển thị của biến đó và ít nhất cho phép một số cách duy trì bất biến (ví dụ: nếu biến toàn cục không bao giờ được phép là giá trị âm, thì setter có thể duy trì bất biến đó). Tất nhiên, ngay cả một thiết kế setter / getter trên đầu của biến toàn cục là thiết kế khá kém, quan điểm của tôi là nó vẫn tốt hơn.
- Làm cho lớp học của bạn nhỏ hơn khi có thể. Một lớp có hàng trăm hàm thành viên, 20 biến thành viên và 30.000 dòng mã thực hiện nó sẽ có các biến riêng tư "toàn cầu", vì tất cả các biến đó sẽ có thể truy cập được vào các hàm thành viên bao gồm 30k dòng mã. Bạn có thể nói "độ phức tạp trạng thái" trong trường hợp đó, trong khi chiết khấu các biến cục bộ trong mỗi hàm thành viên, là
30,000*20=600,000
. Nếu có 10 biến toàn cục có thể truy cập trên đó, thì độ phức tạp trạng thái có thể là như thế 30,000*(20+10)=900,000
. Một "độ phức tạp trạng thái" lành mạnh (loại số liệu được phát minh cá nhân của tôi) nên có trong hàng ngàn hoặc thấp hơn cho các lớp, không phải hàng chục nghìn và chắc chắn không phải hàng trăm nghìn. Đối với các chức năng miễn phí, hãy nói hàng trăm hoặc thấp hơn trước khi chúng tôi bắt đầu bị đau đầu nghiêm trọng trong bảo trì.
- Cũng giống như trên, không thực hiện một cái gì đó như một chức năng thành viên hoặc chức năng bạn bè mà có thể không phải là tháng mười một, không kết bạn chỉ sử dụng giao diện chung của lớp. Các hàm như vậy không thể truy cập các biến riêng của lớp và do đó giảm khả năng xảy ra lỗi bằng cách giảm phạm vi của các biến riêng đó.
- Tránh khai báo các biến từ lâu trước khi chúng thực sự cần thiết trong một hàm (nghĩa là tránh kiểu C kế thừa, khai báo tất cả các biến ở đầu hàm ngay cả khi chúng chỉ cần nhiều dòng bên dưới). Nếu bạn vẫn sử dụng phong cách này, ít nhất là phấn đấu cho các chức năng ngắn hơn.
Beyond Variabled: Tác dụng phụ
Rất nhiều hướng dẫn tôi liệt kê ở trên đang giải quyết quyền truy cập trực tiếp vào trạng thái thô, có thể thay đổi (biến). Tuy nhiên, trong một cơ sở mã đủ phức tạp, chỉ cần thu hẹp phạm vi của các biến thô sẽ không đủ để dễ dàng suy luận về tính chính xác.
Bạn có thể có một cấu trúc dữ liệu trung tâm, đằng sau một giao diện trừu tượng hoàn toàn RẮN, hoàn toàn có khả năng duy trì hoàn hảo các bất biến, và cuối cùng vẫn gặp rất nhiều đau buồn do sự phơi bày rộng rãi của trạng thái trung tâm này. Một ví dụ về trạng thái trung tâm không nhất thiết phải truy cập toàn cầu mà chỉ có thể truy cập rộng rãi là biểu đồ cảnh trung tâm của công cụ trò chơi hoặc cấu trúc dữ liệu lớp trung tâm của Photoshop.
Trong những trường hợp như vậy, ý tưởng về "trạng thái" vượt ra ngoài các biến thô và chỉ đến các cấu trúc dữ liệu và những thứ thuộc loại đó. Nó cũng giúp giảm phạm vi của chúng (giảm số lượng dòng có thể gọi các hàm gián tiếp biến đổi chúng).
Lưu ý cách tôi cố tình đánh dấu ngay cả giao diện là màu đỏ ở đây, vì từ cấp độ kiến trúc rộng, thu nhỏ, truy cập vào giao diện đó vẫn đang thay đổi trạng thái, mặc dù gián tiếp. Lớp có thể duy trì bất biến như là kết quả của giao diện, nhưng điều đó chỉ đi xa về khả năng suy luận về tính chính xác của chúng tôi.
Trong trường hợp này, cấu trúc dữ liệu trung tâm nằm phía sau một giao diện trừu tượng thậm chí có thể không truy cập được trên toàn cầu. Nó chỉ có thể được tiêm và sau đó được gián tiếp đột biến (thông qua các hàm thành viên) từ một khối các hàm trong cơ sở mã phức tạp của bạn.
Trong trường hợp như vậy, ngay cả khi cấu trúc dữ liệu duy trì hoàn hảo các bất biến của riêng nó, những điều kỳ lạ có thể xảy ra ở cấp độ rộng hơn (ví dụ: trình phát âm thanh có thể duy trì tất cả các loại bất biến như mức âm lượng không bao giờ vượt quá phạm vi 0% đến 100%, nhưng điều đó không bảo vệ nó khỏi người dùng nhấn nút phát và có một đoạn âm thanh ngẫu nhiên khác với đoạn mà anh ta tải gần đây nhất bắt đầu phát khi một sự kiện được kích hoạt khiến danh sách phát được chia sẻ lại theo cách hợp lệ nhưng vẫn không mong muốn, hành vi rối rắm từ góc độ người dùng rộng).
Cách để tự bảo vệ mình trong các tình huống phức tạp này là "thắt cổ chai" các vị trí trong cơ sở mã có thể gọi các chức năng gây ra tác dụng phụ bên ngoài ngay cả từ cách nhìn rộng hơn của hệ thống vượt ra ngoài trạng thái thô và ngoài giao diện.
Trông kỳ lạ như thế này, bạn có thể thấy rằng không có "trạng thái" nào (hiển thị màu đỏ và điều này không có nghĩa là "biến thô", nó chỉ có nghĩa là một "đối tượng" và thậm chí có thể đằng sau một giao diện trừu tượng) đang được truy cập bởi nhiều nơi . Mỗi chức năng đều có quyền truy cập vào trạng thái cục bộ mà trình cập nhật trung tâm cũng có thể truy cập và trạng thái trung tâm chỉ có thể truy cập vào trình cập nhật trung tâm (làm cho nó không còn là trung tâm mà là bản chất cục bộ).
Điều này chỉ dành cho các cơ sở mã thực sự phức tạp, giống như một trò chơi kéo dài 10 triệu dòng mã, nhưng nó có thể giúp rất nhiều trong việc suy luận về tính chính xác của phần mềm của bạn và thấy rằng các thay đổi của bạn mang lại kết quả có thể dự đoán được, khi bạn giới hạn / tắc nghẽn đáng kể số lượng của những nơi có thể đột biến các trạng thái quan trọng mà toàn bộ kiến trúc xoay quanh để hoạt động chính xác.
Ngoài các biến thô là tác dụng phụ bên ngoài và tác dụng phụ bên ngoài là nguồn gây ra lỗi ngay cả khi chúng bị giới hạn trong một số ít chức năng thành viên. Nếu một nhóm chức năng có thể gọi trực tiếp các nhóm chức năng đó, thì có một nhóm chức năng trong hệ thống có thể gián tiếp gây ra tác dụng phụ bên ngoài và điều đó làm tăng sự phức tạp. Nếu chỉ có một nơi trong cơ sở mã có quyền truy cập vào các chức năng thành viên đó và một con đường thực thi đó không được kích hoạt bởi các sự kiện lẻ tẻ ở khắp mọi nơi, mà thay vào đó được thực hiện theo kiểu rất dễ kiểm soát, có thể dự đoán được, thì nó sẽ giảm độ phức tạp.
Phức tạp nhà nước
Ngay cả sự phức tạp của nhà nước là một yếu tố khá quan trọng cần tính đến. Một cấu trúc đơn giản, có thể truy cập rộng rãi đằng sau một giao diện trừu tượng, không quá khó để gây rối.
Một cấu trúc dữ liệu đồ thị phức tạp đại diện cho biểu diễn logic cốt lõi của một kiến trúc phức tạp khá dễ gây rối và theo cách thậm chí không vi phạm các bất biến của đồ thị. Một biểu đồ phức tạp hơn nhiều lần so với một cấu trúc đơn giản và do đó, nó trở nên quan trọng hơn trong trường hợp như vậy để giảm độ phức tạp nhận thức của cơ sở mã để giảm số lượng vị trí có quyền truy cập vào cấu trúc biểu đồ đó đến mức tối thiểu tuyệt đối, và trong đó loại chiến lược "cập nhật trung tâm" chuyển sang mô hình kéo để tránh lẻ tẻ, việc đẩy trực tiếp vào cấu trúc dữ liệu đồ thị từ khắp nơi có thể thực sự được đền đáp.