Phát minh lại thiết kế hệ thống cho Scala


35

Nhiều, rất nhiều, những lần trước, tôi đã học thạc sĩ về Kỹ thuật phần mềm hướng đối tượng. Tôi bao quát mọi thứ: bắt đầu dự án, yêu cầu, phân tích, thiết kế, kiến ​​trúc, phát triển, v.v. Cuốn sách CNTT yêu thích của tôi mọi thời đại là Phát triển phần mềm hướng đối tượng, Phương pháp tiếp cận dựa trên kinh nghiệm (IBM-1996). Một cuốn sách được tạo ra bởi một nhóm các chuyên gia thực sự của thời đại của họ. Nó mô tả một cách tiếp cận tập trung vào sản phẩm công việc đối với các phương pháp phân tích, thiết kế và phát triển hướng đối tượng.

Tôi đã thiết kế và phát triển và rất hạnh phúc và ở đầu trò chơi của mình, nhưng tôi bắt đầu cảm thấy hơi lạc hậu: Phong trào Agile trở thành mốt của thời đại và đổi tên thành một số cách tiếp cận lặp đi lặp lại và gia tăng nổi tiếng với những từ mới. Đột nhiên các nhà phát triển thiếu kinh nghiệm bắt đầu cau mày khi tôi nói "yêu cầu" hoặc "kiến trúc" như thể những thứ này được thay thế bằng ma thuật.

Thiết kế và phát triển mất đi điều đó thật thú vị và tôi sắp rời bỏ toàn bộ ngành CNTT phía sau mình.

Sau đó tôi phát hiện ra Scala. Ôi, như mưa mềm trên con đường bụi bặm. Mọi thứ trở nên rõ ràng, không khí trở nên ngọt ngào trở lại và ánh sáng nhỏ bé trong ổ cứng của tôi sẽ lóe lên trong màn đêm, vui vẻ giữ tôi lại trong thế giới khám phá của tôi.

Tôi thích thiết kế hệ thống. Tôi là một kiến ​​trúc sư, hơn cả một lập trình viên. Tôi thích phân tích, thiết kế, suy nghĩ, tranh luận, cải tiến - Tôi chỉ thích những thiết kế đơn giản, sạch sẽ và sắc nét.

Làm thế nào để chúng tôi thiết kế các giải pháp Scala tinh khiết?

Chắc chắn các sơ đồ trình tự thông thường, sơ đồ tương tác, sơ đồ đối tượng, v.v., tất cả đều có thể được thay thế hoặc cải thiện cho sự tốt đẹp của việc pha trộn các hệ thống hướng đối tượng bắt buộc và chức năng. Chắc chắn có một sự mở đầu cho một cái gì đó hoàn toàn khác!

Tôi không tìm kiếm sự phức tạp cồng kềnh - Tôi đang tìm kiếm sự đơn giản linh hoạt. Giống như Scala thực sự đơn giản và dễ dàng (mặc dù khác nhau), nhưng có thể được mở rộng để phù hợp với yêu cầu của bạn như một chiếc quần Yoga. Phải có một hệ thống thiết kế cho ngôn ngữ đáng yêu này sẽ bắt đầu đơn giản và có thể được mở rộng để phù hợp với yêu cầu của bạn và miền của bạn. Chắc chắn UML không thể là nó!

Vậy làm thế nào để chúng ta thiết kế các hệ thống Scala thuần túy? Hãy tưởng tượng trong một khoảnh khắc, bạn có sự sang trọng để thiết kế một hệ thống hoàn chỉnh từ đầu, và biết rằng bạn sẽ chỉ sử dụng Scala - Các mô hình của bạn sẽ trông như thế nào? Những loại sơ đồ bạn sẽ phải mô tả cấu trúc và hành vi? Làm thế nào bạn có thể mô hình hóa Tùy chọn, kết hợp, mixin, Đối tượng đơn lẻ, v.v. mà không bị lôi cuốn vào sự phức tạp của việc mở rộng các kỹ thuật mô hình hiện có thay vì một bộ công cụ sáng tạo, nhẹ, mới.

Liệu một thiết kế / quy trình / giải pháp như vậy tồn tại , hay đã đến lúc phát minh ra nó?


+1 cho "có thể được mở rộng để phù hợp với yêu cầu của bạn như một chiếc quần Yoga."
Russell

FWIW, tôi đã thấy một câu hỏi về UML và Scala, có thể bạn quan tâm. Ngoài ra, nếu bạn đi đến phía chức năng, thì các ký hiệu lý thuyết thể loại có thể đáng để xem xét. Gregory Meredith thường liên kết đến một số bài thuyết trình thú vị về nó, mặc dù tôi không chắc anh ấy có gì trong blog của mình - dù sao nó cũng đáng để kiểm tra.
Daniel C. Sobral

Nó đáng giá rất nhiều ;-) Nó cho tôi hướng đào. Cảm ơn Daniel
Jack

Đáng để kiểm tra, UML "đã sửa đổi" cho Scala, github.com/mnn/Dia2Scala/blob/master/other/Notation.md
WeiC Breath Lin

Câu trả lời:


12

Tôi thực sự không thể đưa ra câu trả lời cho câu hỏi này, nhưng hãy để tôi đưa ra một vài suy nghĩ.

Tôi là một sinh viên kỹ thuật máy tính trong một trường đại học, và học kỳ trước tôi và một nhóm đã làm một dự án phần mềm lớn trong đó ngôn ngữ chính của chúng tôi là Scala. Chúng tôi đã thiết kế theo cách truyền thống: các trường hợp sử dụng, mô hình miền, sơ đồ trình tự, sơ đồ lớp UML; tải thông thường. Và, như bạn đã biết, họ là một người kém phù hợp. Dưới đây là một số lý do.

Đầu tiên, hãy xem xét các sơ đồ trình tự. Các cảm nhận của một sơ đồ trình tự của một vài ổn định, sống lâu, diễn viên bán tự trị nói chuyện với nhau. Trong Scala, các đối tượng có xu hướng được tạo ra trong một thời gian ngắn. Hơn nữa, các lớp trường hợp khuyến khích các đối tượng "câm", chỉ có dữ liệu và không có mã, do đó, khái niệm truyền tin nhắn không phù hợp. Nhưng thách thức khó khăn nhất đối với các sơ đồ trình tự là chúng không có cách nào tốt để kết hợp các chức năng hạng nhất; trong một thiết kế OO chỉ sử dụng một cuộc gọi lại ở đây hoặc ở đó nó có thể được thực hiện để làm việc, nhưng nếu đó là phương tiện chính của điều khiển chuyển bạn sẽ thấy sơ đồ trình tự phản ánh rất ít mã thực tế của bạn.

Các sơ đồ lớp UML dễ điều chỉnh hơn Scala; vâng, mixins không thành công lắm, nhưng đó là thứ có thể được "điều chỉnh" thay vì đại tu. Nhưng tôi nghĩ rằng có thể thiếu điểm.

Xem xét lại tại sao Scala có "đối tượng câm". Nếu bạn viết một lớp tình huống không có phương thức:

case class NewInvite(user: User, league: League)

bạn không cần bất kỳ phương pháp nào, bởi vì các loại thành viên hứa hẹn điều gì đó về những gì bạn có thể làm với họ. Trong thực tế, họ hứa tất cả mọi thứ . Và, trong mọi phạm vi trong chương trình, các biến trong phạm vi và kiểu của chúng hứa hẹn một điều gì đó về nơi mã có thể đi vào thời điểm đó.

Vì vậy, có lẽ, nếu chúng ta lùi lại một chút, và thay vì suy nghĩ một cách tinh tế về các loại, hãy thiết kế chương trình của chúng tôi theo bối cảnh mà mã của chúng tôi sẽ sống và những gì được hứa cho người lập trình (và cuối cùng là người dùng ) trong mỗi bối cảnh này, chúng ta sẽ tìm thấy một mô tả phù hợp hơn với Scala. Tuy nhiên tôi chỉ đoán ở đây, và tôi nghĩ bạn đúng rằng cần phải khám phá nhiều hơn nữa trong lĩnh vực này.


"Những gì được hứa cho lập trình viên" - có một chiếc nhẫn đáng yêu với nó ;-)
Jack

12

UML nổi lên từ "Cuộc chiến bong bóng" cuối thập niên 80 và đầu thập niên 90. Nó luôn luôn là một sự thỏa hiệp cho ký hiệu , không phải là một phương pháp thiết kế. Nhiều trong số các sinh viên được gán cho UML là bí mật kết quả của một phương pháp thiết kế có nội dung "Bước 1: vẽ mô hình lớp."

Tôi đề nghị rằng chúng ta không cần phương pháp thiết kế mới nhiều như chúng ta nên hồi sinh một số phương pháp cũ. Bắt đầu với việc xác định và phân bổ trách nhiệm, sau đó chuyển sang tìm hiểu việc triển khai của họ và theo dõi với các ký hiệu và biểu diễn tốt để truyền đạt những ý tưởng đó.

Trách nhiệm

CRC hoạt động tốt cho Scala cũng như đối với bất kỳ ngôn ngữ OO nào khác, có nghĩa là nó hoạt động rất tốt! Mô hình hóa việc phân bổ trách nhiệm bằng cách nhân cách hóa các tác nhân và hiểu sự hợp tác của họ vẫn hoạt động tốt.

Ở quy mô lớn, bạn vẫn nên thiết kế với các đối tượng. Ranh giới đối tượng là ranh giới đóng gói. Giữ trạng thái có thể thay đổi và chi tiết thực hiện bên trong các ranh giới đối tượng. Các lớp trường hợp làm cho các đối tượng giao diện tốt, các bộ sưu tập vanilla và cấu trúc dữ liệu cũng vậy.

Hiểu việc thực hiện

Vượt qua các cấu trúc dữ liệu này qua các ranh giới đối tượng thay vì các đối tượng khác và bạn sẽ thấy a) việc giấu ruột của đối tượng dễ dàng hơn bên trong và b) triển khai chức năng của các hành vi đối tượng có ý nghĩa rất lớn.

Bạn sẽ không muốn coi cấu trúc quy mô lớn của chương trình của mình là "một nhóm lớn các chức năng nhỏ". Thay vào đó, bạn sẽ tự nhiên bị hút về các giao diện hẹp giữa các phần bị cô lập của hệ thống. Chúng nhìn và cảm nhận rất giống các đối tượng, vì vậy hãy tiếp tục và thực hiện chúng như các đối tượng!

Đại diện và ký hiệu

Vì vậy, trong cấu trúc thiết kế này, bạn vẫn cần lấy những suy nghĩ ra khỏi đầu và chia sẻ chúng với người khác.

Tôi đề nghị rằng UML vẫn có thể hữu ích để mô tả cấu trúc quy mô lớn của hệ thống của bạn. Nó sẽ không giúp đỡ ở mức độ chi tiết thấp hơn, mặc dù.

Tại hạt mịn của chi tiết, hãy thử kỹ thuật lập trình biết chữ.

Tôi cũng thích sử dụng minidocs. Một minidoc là một hoặc hai tài liệu trang mô tả một số khía cạnh cụ thể của hành vi hệ thống. Nó nên ngồi gần mã để nó được cập nhật và nó phải đủ ngắn để cho phép học tập đúng lúc. Cần có một số thực hành để đạt được mức độ trừu tượng đúng: nó cần phải đủ cụ thể để có ích nhưng không cụ thể đến mức nó bị vô hiệu bởi sự thay đổi mã tiếp theo.


9

Làm thế nào để chúng tôi thiết kế các giải pháp Scala tinh khiết?

Tôi nghĩ rằng bạn đang đi sai góc với câu hỏi này. Thiết kế tổng thể của bạn cho các giải pháp không nên được gắn với một ngôn ngữ cụ thể; đúng hơn, nó nên tương ứng với vấn đề trong tầm tay. Điều tuyệt vời của Scala là nó đủ linh hoạt để không cản trở bạn khi đến lúc thực hiện thiết kế của bạn. Mặt khác, Java thi hành một số quyết định thiết kế (chủ yếu, tâm lý mọi thứ là một lớp học) sẽ khiến nó cảm thấy hơi lộn xộn.

Khi thiết kế, cố gắng mô hình hóa trạng thái rõ ràng . Dữ liệu bất biến và trạng thái rõ ràng dẫn đến các thiết kế dễ lý luận hơn nhiều. Hầu hết thời gian, điều này sẽ chuyển độc đáo thành một giải pháp lập trình chức năng, mặc dù đôi khi bạn có thể thấy rằng nó hiệu quả hơn hoặc đơn giản hơn để sử dụng đột biến và một phong cách bắt buộc; Scala chứa cả hai khá độc đáo.

Một lý do khác khiến Scala rất tuyệt vời trong việc tránh xa bạn là khả năng tạo DSL phù hợp với nhu cầu của bạn . Bạn có thể tạo ngôn ngữ nhỏ của riêng mình để giải quyết một vấn đề nhất định theo cách "bình thường", và sau đó chỉ cần thực hiện nó trong Scala.

Tóm lại, điểm chính của tôi là bạn không nên cố gắng "thiết kế các giải pháp Scala thuần túy". Bạn nên thiết kế các giải pháp theo cách tự nhiên và dễ hiểu nhất có thể, và thực tế là Scala là một công cụ cực kỳ linh hoạt có thể giúp bạn thực hiện các giải pháp đó theo nhiều cách khác nhau. Khi tất cả những gì bạn biết là một cái búa, mọi vấn đề bắt đầu trông giống như một cái đinh, vì vậy hãy chắc chắn khám phá các phương pháp khác nhau có sẵn cho bạn. Đừng cố đóng quy trình thiết kế cho các bước X, Y và Z, vì sợ bạn bỏ lỡ các khả năng từ A đến W.


4

Bạn nói đúng rằng, hạn chế và lỗi thời. Ưu điểm chính của nó là nó được chỉ định và nghi thức rất tốt, với các tên lạ mắt cho mỗi mô hình và thủ thuật thiết kế tầm thường. Bạn sẽ không tìm thấy bất kỳ hệ thống tương đương nào cho các cách tiếp cận hợp lý và hiện đại hơn đối với thiết kế hệ thống.

Tôi chỉ có thể liệt kê một vài điều: một cách tiếp cận ngữ nghĩa để thiết kế, một tập hợp con được gọi là Lập trình hướng ngôn ngữ (và được cộng đồng Scala sử dụng nhiều) và Thiết kế hướng tên miền. Cái sau là một cái nhìn đơn giản hóa và OOPised về cách tiếp cận thiết kế ngữ nghĩa chung chung hơn, bạn sẽ chỉ có thể thưởng thức nó nếu bạn thích OOD.

Tôi cũng khuyên bạn nên học một hoặc hai mẹo từ các cộng đồng lập trình chức năng khác - ví dụ: Haskell và Scheme, không phải tất cả các bí quyết thiết kế của họ đã được chuyển sang Scala.


3

Câu hỏi là: Làm thế nào để chúng tôi thiết kế các giải pháp Scala thuần túy?

Câu trả lời như,

  1. Chúng tôi sử dụng XYZ vì ....
  2. Chúng tôi sử dụng ABC nhưng như vậy ....
  3. Chúng tôi bắt đầu sử dụng XYZ, nhưng sau đó thấy ABC tốt hơn vì ...

sẽ chỉ ra một số sự trưởng thành, hoặc thường được chấp nhận, của một bộ công cụ hoặc giải pháp như vậy.

Nhận xét liên quan đến việc có phù hợp để xem xét bộ công cụ thiết kế cụ thể của Scala hay không là một vấn đề khác. Ý kiến ​​của tôi về điều này là Scala mang tính cách mạng trong cách kết hợp lập trình mệnh lệnh và chức năng. Scala nắm bắt được một hơi thở tuyệt vời của các thực tiễn, khái niệm và nguyên tắc phát triển, và vì vậy, trong việc tìm ra một giải pháp phù hợp hoàn hảo với Scala, chúng ta có thể sẽ khám phá ra một giải pháp mà một tập hợp con cũng sẽ phục vụ rất nhiều ngôn ngữ khác.

Có an toàn không khi nói rằng chúng tôi biết câu trả lời cho câu hỏi dự phòng:

"... đã đến lúc phát minh ra chưa?"

Nó có thể là ? (Trong trường hợp ' ' không quy định phương tiện cho giải pháp. Nó có thể đạt được bằng cách mở rộng một giải pháp hiện có hoặc tạo ra một giải pháp từ đầu.

Bạn có thể bỏ phiếu trả lời của tôi xuống nếu bạn không đồng ý. Tôi sẽ coi nó như một người đàn ông.


Cách mạng? Tại sao? Lisp đã là một sự kết hợp hoàn hảo của các phương pháp tiếp cận và chức năng trong nhiều thập kỷ. Scala là thú vị vì hệ thống loại của nó.
SK-logic

3
Lời xin lỗi nếu 'cách mạng' là một từ mạnh mẽ mạnh mẽ. Tôi không ám chỉ Scala đã phát minh lại bánh xe - nhưng chắc chắn rằng địa ngục đã làm lại cao su. Trong thực tế, Scala là một sự pha trộn đáng yêu của tất cả sự tốt đẹp của nhiều ngôn ngữ lập trình. Tôi chắc chắn rằng nó cũng vay rất nhiều từ Lisp. Đối với tôi, và tôi không đưa ra yêu sách nào cho người khác, ngôn ngữ Scala mang đến một cuộc cách mạng trong đó tôi đang nghĩ về mã theo cách xuất hiện khá tự nhiên. Một ngôn ngữ thiết kế / mô hình mà làm như vậy chắc chắn sẽ là miễn phí. Đó là điểm duy nhất của tôi - không xúc phạm đến Lisp và tất cả các ngôn ngữ tuyệt vời khác.
Jack

2

Tôi sẽ không phân biệt giữa các ngôn ngữ, tôi sẽ làm theo cách tương tự trong java. Tuy nhiên, tôi đến từ trường OO chứ không phải là chức năng (đại số Haskell một hoặc một lisp). Thiết kế ứng dụng Haskell thực sự khác biệt với Scala hoặc Clojure. Ngoài ra, thiết kế ứng dụng Scala.js khác biệt do DOM trạng thái - thật khó để chống lại một phần trạng thái trong ứng dụng của bạn là bắt buộc. Theo thời gian, tôi đã quen với việc làm theo cách OO, trong khi cố gắng loại bỏ trạng thái và khả năng biến đổi càng nhiều càng tốt. Nếu tôi là một người hâm mộ đánh máy chữ hoặc scalaz, các ứng dụng của tôi có thể trông khá khác biệt.

  1. Quyết định về ngăn xếp công nghệ và các quyết định thiết kế chính như trách nhiệm của khách hàng / máy chủ, tính chất phân tán - chúng ta có thực sự cần sự kiên trì dữ liệu không? Những gì phù hợp với ứng dụng của chúng tôi tốt nhất? (chắc chắn không phải thư viện hoặc khung nào)

  2. Bắt đầu chỉ với một App.scalatệp duy nhất trong đó tôi xác định các loại khóa (đặc điểm và lớp trường hợp) và vai trò - rất nhiều suy ngẫm và suy nghĩ trong khi đang AFK. Thật dễ dàng để chơi với nó trong khi nó nằm trong một tệp. Ngay cả nguyên mẫu cũng có thể ra đời nếu nó là một ứng dụng đơn giản. Tôi dành rất nhiều thời gian cho giai đoạn này bởi vì không có gì quan trọng hơn việc có nguyên mẫu chính xác nhất và chủ yếu minh bạch và hợp lý nhất có thể. Tất cả giúp chúng ta suy ngẫm chính xác hơn và tăng khả năng thành công.

  3. Bây giờ khi chúng tôi đã chứng minh tính đúng đắn của giải pháp của mình, chúng tôi có tầm nhìn rõ ràng và tất cả các vấn đề tiềm ẩn đã được tiết lộ, đã đến lúc nghĩ loại thư viện hoặc phương pháp của bên thứ ba nào để đưa vào. Chúng tôi cần chơi khung hay chỉ một vài lib? Chúng ta sẽ làm cho các diễn viên nhà nước này, chúng ta thực sự cần sự kiên cường của Akka, .., .. hoặc có thể không? Chúng ta có sử dụng Rx cho các luồng này không? Chúng ta sử dụng gì cho UI để chúng ta không phát điên sau khi nó có 10 tính năng tương tác?

  4. chia App.scalatệp thành nhiều phần vì các đặc điểm và lớp mới xuất hiện và lớn hơn. Giao diện của họ nên nói về vai trò của họ. Bây giờ cũng là lúc để suy nghĩ về việc sử dụng các lớp loại và đa hình ad-hoc nếu có thể. Vì vậy, bất cứ ai gọi giao diện của bạn, nó phải linh hoạt cho họ. Vấn đề là chỉ thực hiện chức năng chung, để lại chi tiết cho người gọi. Đôi khi những gì bạn đang cố gắng thực hiện có thể giống như Turing, vì vậy bạn nên cung cấp một cách để người gọi tự thực hiện các chi tiết cụ thể thay vì chồng chất các yêu cầu tính năng trên GitHub. Công cụ này là khó để thêm sau này. Nó phải được suy nghĩ ngay từ đầu. Cũng như thiết kế DSL.

  5. suy nghĩ thiết kế thông qua vì ứng dụng sẽ phát triển và nó phải sẵn sàng chịu đựng các tính năng mới, tối ưu hóa, kiên trì, giao diện người dùng, từ xa, v.v. - những thứ chưa được triển khai hoặc bằng cách nào đó bị chế giễu hoặc trừu tượng hóa. Hãy nhớ rằng trong khi tất cả trong một tệp, việc thay đổi mọi thứ khá dễ dàng. Bộ não con người bắt đầu mất nó sau khi nó được trải rộng trên 10 tệp. Và nó giống như một khối u phát triển, đó là cách bắt đầu quá mức. Tôi nhận thấy rằng các ứng dụng của tôi kết thúc với một vài chức năng một phần dài tạo thành một loại xương sống của nó. Tôi thấy nó dễ dàng để làm việc với. Tôi đoán tôi đã bị nhiễm bởi các diễn viên Akka.

  6. Bây giờ các tính năng thực tế đầu tiên tồn tại, không chỉ là chức năng cốt lõi, đã đến lúc bắt đầu viết bài kiểm tra. Sao trễ vậy? Bởi vì trong thời gian này, bạn có thể đã trải qua các bài viết lớn và bạn đã lãng phí thời gian để duy trì các bài kiểm tra đó. Người ta không nên viết bài kiểm tra trừ khi người ta thực sự chắc chắn sẽ không có bất kỳ thiết kế lại lớn nào. Tôi thích các thử nghiệm tích hợp dễ dàng chịu được tái cấu trúc liên tục và tôi sẽ không dành nhiều thời gian hơn để thử nghiệm thực sự phát triển công cụ. Nó đã xảy ra với tôi một vài lần rằng tôi đã dành quá nhiều thời gian để duy trì các bài kiểm tra. Sửa các lỗi tiềm năng chắc chắn sẽ trả hết hơn là các bài kiểm tra tồi. Các xét nghiệm xấu hoặc xét nghiệm được viết từ giây phút đầu tiên có thể gây ra nỗi đau lớn. Lưu ý rằng tôi chắc chắn không phải là fan hâm mộ của TDD - IMHO thật nhảm nhí.

  7. Tái cấu trúc, làm và giữ cho thiết kế ứng dụng có thể đọc được, vai trò thành phần rõ ràng. Khi ứng dụng phát triển, không có cách nào nó tồn tại như vậy trừ khi bạn là một lập trình viên thiên tài và nếu bạn đọc câu trả lời này thì có lẽ bạn không :-) Cả tôi cũng vậy. điều đó - có thể gây ra vấn đề, cố gắng loại bỏ chúng. Ngoài ra hãy chắc chắn để loại bỏ mùi mã đã làm phiền bạn một thời gian. Lúc này người quản lý dự án của bạn (nếu bạn có) có lẽ bắt đầu lắc đầu. Nói với anh ta rằng nó sẽ trả hết.

  8. Xong, ứng dụng có được thiết kế tốt không? Nó phụ thuộc: Các thành phần có vai trò được xác định rõ có thực sự có ý nghĩa ngay cả ngoài đầu bạn không? Bạn có thể lấy một số trong số chúng và nguồn mở chúng mà không cần nỗ lực nhiều không? Có sự tách biệt rõ ràng mối quan tâm giữa họ? Bạn có thể thêm một tính năng mới mà không lo nó sẽ bị sập ở nơi khác không (dấu hiệu của bạn biết chính xác những gì bạn đang làm)? Nói chung, nó nên được đọc như một cuốn sách với các giải pháp thực tế đơn giản cho các vấn đề. IMHO là dấu hiệu chính của thiết kế tốt.

Nói chung, đó chỉ là một công việc khó khăn và thời gian mà bạn có thể sẽ không nhận được từ những người quản lý của mình. Tất cả những gì tôi mô tả ở đây cần rất nhiều thời gian, công sức, cà phê, trà và đặc biệt là suy nghĩ AFK. Bạn càng cho nó, thiết kế càng tốt. Không có công thức chung để thiết kế các ứng dụng, ý thức chung, tính thực dụng, KISS, chăm chỉ, kinh nghiệm có nghĩa là thiết kế tốt.

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.