Cái nhìn đầu tiên về lập trình lấy ý định làm trung tâm ft. Pint

Bài viết này được dịch máy
Xem bản gốc

Tác giả: Figo, IOSG Ventures

Lập trình mệnh lệnh so với lập trình khai báo: Một sự thay đổi trong Paradigm

Trong thế giới blockchain, các mô hình lập trình xác định cách các nhà phát triển tương tác với công nghệ và cách người dùng trải nghiệm kết quả. Hãy cùng phân tích những điểm khác biệt chính giữa cách tiếp cận mệnh lệnh truyền thống và cách tiếp cận khai báo mới nổi, bằng cách sử dụng phép so sánh dễ hiểu — gọi một tách cà phê tùy chỉnh tại quán cà phê yêu thích của bạn.

Lập trình mệnh lệnh: Thực hiện theo công thức

Hãy tưởng tượng bạn bước vào một quán cà phê và đưa cho nhân viên pha chế danh sách chi tiết các bước pha cà phê — “Xay 20g hạt cà phê, sử dụng 200ml nước ở nhiệt độ 90°C, pha trong 4 phút, đổ vào cốc gốm.” Bạn đang quản lý quá trình một cách chi tiết, đảm bảo rằng mọi bước đều được thực hiện chính xác để có được loại cà phê bạn muốn.

Đây là cách lập trình bắt buộc hoạt động trong blockchain. Các nhà phát triển viết hợp đồng thông minh chỉ đạo mọi bước của quy trình, từ việc lấy dữ liệu đến thực hiện giao dịch. Mặc dù điều này đảm bảo rằng quy trình được thực hiện theo đúng mục đích, nhưng nó có thể cứng nhắc và không hiệu quả, đặc biệt là nếu có những điều kiện bất ngờ phát sinh.

Lập trình khai báo: Xác định kết quả

Bây giờ, hãy tưởng tượng bạn bước vào quán cà phê đó và chỉ nói: "Tôi muốn một tách cà phê vừa đậm, không đường, trong một chiếc cốc gốm". Người pha chế biết bạn muốn gì và có thể chọn cách tốt nhất để pha chế, có thể là sử dụng phương pháp pha chế khác hoặc điều chỉnh kích thước xay dựa trên loại hạt cà phê có sẵn.

Đây là bản chất của lập trình khai báo. Thay vì chỉ định từng bước, bạn xác định kết quả mong muốn và hệ thống sẽ tìm ra cách tốt nhất để đạt được kết quả đó. Cách tiếp cận này linh hoạt hơn, cho phép điều chỉnh dựa trên các điều kiện hiện tại và sở thích của người dùng.

Dưới đây là bảng nêu bật những điểm khác biệt chính:

Nguồn : Figo, IOSG

Tại sao cần có Intent cho các ứng dụng Blockchain?

Hiểu ý định

Trong thiết lập blockchain truyền thống, bạn sẽ đưa ra hướng dẫn từng bước để đạt được một thay đổi trạng thái cụ thể. Nhưng nếu bạn chỉ có thể chỉ định mục tiêu cuối cùng và để hệ thống tìm ra cách tốt nhất để đạt được mục tiêu đó thì sao? Đó là ý tưởng đằng sau ý định trong blockchain — người dùng tuyên bố những gì họ muốn và hệ thống xử lý phần còn lại.

Ví dụ, thay vì yêu cầu blockchain "bán 1 ETH với mức giá tốt nhất hiện có", người dùng có thể tuyên bố ý định "nhận ít nhất 2500 USDT để đổi lấy 1 ETH của tôi". Sau đó, hệ thống sẽ tìm cách tốt nhất để thực hiện yêu cầu này, có thể là trên nhiều sàn giao dịch hoặc nhóm thanh khoản.

Những thách thức với Blockchain bắt buộc

Tính cứng nhắc của lập trình mệnh lệnh thường dẫn đến một số vấn đề:

  • Kết quả không chắc chắn: Người dùng thường không biết kết quả của giao dịch cho đến khi nó được xác nhận, điều này có thể gây căng thẳng và rủi ro.
  • Sự kém hiệu quả của thị trường: Việc thực hiện mệnh lệnh có thể trở nên tắc nghẽn khi có nhu cầu cao về các kết quả cụ thể, như trong giao dịch DeFi .
  • Rủi ro bảo mật: Các bước càng chi tiết thì càng có nhiều điểm lỗi tiềm ẩn, làm tăng nguy cơ xảy ra lỗi và khai thác.
Nguồn : Essential Docs

Những vấn đề này đặc biệt phổ biến trong các môi trường như DeFi, nơi người dùng phải đối mặt với các vấn đề như giao dịch không thành công, Slippage (Trượt giá) cao và tiếp xúc với MEV (Giá trị có thể trích xuất của thợ đào).

Sự trỗi dậy của Blockchain khai báo

Các blockchain khai báo như Essential hướng đến giải quyết những vấn đề này bằng cách tập trung vào kết quả thay vì quy trình. Bằng cách xác định trạng thái cuối cùng nên là gì và sử dụng ý định để đạt được trạng thái đó, các hệ thống này mang lại một số lợi thế:

  • Kết quả có thể dự đoán được: Người dùng có thể tin tưởng rằng blockchain sẽ mang lại kết quả mong muốn.
  • Cải thiện tính bảo mật: Ít bước hơn có nghĩa là ít có khả năng xảy ra sai sót hơn.
  • Khả năng mở rộng: Bằng cách tối ưu hóa kết quả, blockchain khai báo có thể xử lý các hoạt động phức tạp hơn mà không cần nhiều tài nguyên tính toán hơn.

Một ngôn ngữ tập trung vào ý định

Khi lập trình tập trung vào ý định ngày càng được ưa chuộng trong không gian blockchain, các ngôn ngữ như Pint (do Essential phát triển) và Juvix (do Anoma phát triển) đã xuất hiện để giúp các nhà phát triển tập trung vào kết quả thay vì các bước cụ thể. Các ngôn ngữ này cung cấp một cách mới để tiếp cận phát triển blockchain, ưu tiên trạng thái mong muốn của hệ thống hơn là các hướng dẫn thủ tục để đạt được trạng thái đó.

Trong phần này, chúng ta sẽ đi sâu vào Pint , ngôn ngữ đằng sau blockchain khai báo của Essential, để khám phá cách thức hoạt động của nó và điều gì khiến nó khác biệt so với những gì chúng ta thường thấy.

Pint là một ngôn ngữ mô hình hóa ràng buộc chuyên biệt được thiết kế riêng cho blockchain tập trung vào ý định của Essential. Không giống như các ngôn ngữ hợp đồng thông minh bắt buộc truyền thống, Pint nhấn mạnh vào việc xác định kết quả mong muốn của các thay đổi trạng thái mà không chỉ định các bước chính xác để đạt được các kết quả đó. Sự thay đổi trọng tâm này cho phép linh hoạt hơn, bảo mật hơn và hiệu quả hơn trong cách các ứng dụng blockchain được phát triển và thực hiện.

Điều gì làm cho Pint khác biệt?

Pint cung cấp một cách độc đáo để xử lý logic blockchain bằng cách tập trung vào các ràng buộc và vị từ thay vì các mô hình thực thi truyền thống. Sau đây là cách thức hoạt động:

  • Hợp đồng : Trong Pint, hợp đồng xác định các quy tắc để cập nhật trạng thái blockchain. Không giống như hợp đồng truyền thống, hợp đồng không chỉ định cách thực hiện thay đổi; thay vào đó, hợp đồng xác thực xem thay đổi trạng thái được đề xuất có đáp ứng các tiêu chí nhất định hay không.
  • Các vị ngữ : Các vị ngữ là các điều kiện cần phải đáp ứng để thay đổi trạng thái có hiệu lực. Chúng đóng vai trò như các bộ lọc xác định xem một quá trình chuyển đổi trạng thái cụ thể có thể xảy ra hay không.
  • Ràng buộc : Ràng buộc là các khối xây dựng của các vị từ. Các biểu thức Boolean này phải đánh giá là True để một vị từ có thể vượt qua. Ví dụ, một ràng buộc có thể yêu cầu bộ đếm tăng chính xác một, đảm bảo tính nhất quán trong các bản cập nhật trạng thái.
  • State : Biến state biểu diễn các giá trị trên blockchain. Không giống như các ngôn ngữ mệnh lệnh truyền thống, nơi các nhà phát triển viết một số lệnh thực thi được áp dụng cho pre-state để xác định post-state, Pint cung cấp cả pre-state và post-state làm đầu vào. Đối với một trạng thái khai báo foo đã cho, foo tham chiếu đến pre-state, trong khi foo' tham chiếu đến post-state.
  • Biến quyết định : Biến quyết định cho phép người giải cung cấp dữ liệu bổ sung có thể cần thiết để đáp ứng các ràng buộc của một vị từ. Ví dụ, vị từ chuyển giao của hợp đồng Token có thể yêu cầu chữ ký hợp lệ.

Cái nhìn đầu tiên về Pint: Ví dụ về bộ đếm đơn giản

Để hiểu rõ hơn về cách Pint hoạt động, chúng ta hãy xem xét một ví dụ đơn giản — một hợp đồng đối ứng.

 kho {
bộ đếm: int,
}

vị ngữ Tăng dần {
bộ đếm trạng thái: int = storage::counter; // Đọc giá trị hiện tại của bộ đếm

ràng buộc (counter == nil && counter' == 1) || counter' == counter + 1;
// Ràng buộc này đảm bảo rằng nếu bộ đếm không được thiết lập, nó sẽ bắt đầu từ 1.
// Nếu không, nó sẽ tăng giá trị hiện tại lên 1.
}

Block lưu trữ :

  • Block lưu trữ định nghĩa một bộ đếm biến số nguyên duy nhất sẽ được lưu trữ trên blockchain. Đây là nơi lưu giữ giá trị hiện tại của bộ đếm.

Tăng vị ngữ :

  • Thuật ngữ Increment định nghĩa logic để tăng bộ đếm.
  • Bộ đếm trạng thái dòng: int = storage::counter; đọc giá trị hiện tại của bộ đếm từ bộ nhớ.
  • Ràng buộc (counter == nil && counter' == 1) || counter' == counter + 1; đảm bảo rằng nếu bộ đếm chưa được khởi tạo (tức là nil), thì nó sẽ bắt đầu từ 1. Nếu không, bộ đếm sẽ tăng thêm 1.

Nói một cách đơn giản, hợp đồng này nêu rằng, "Nếu bộ đếm chưa tồn tại, hãy bắt đầu từ 1. Nếu đã tồn tại, hãy thêm 1 vào bất kỳ giá trị hiện tại nào". Ví dụ này minh họa cách Pint cho phép các nhà phát triển xác định kết quả mong muốn (tăng bộ đếm) mà không cần phải chỉ định từng bước (kiểm tra bộ đếm, thêm vào bộ đếm, ETC).

Xây dựng một loại tiền điện tử đơn giản từ đầu

Bây giờ thì sao về một ví dụ phức tạp hơn? Chúng ta hãy thực hiện từng bước để xem cách chúng ta có thể xây dựng một loại tiền điện tử cơ bản bằng Pint, bắt đầu từ những nguyên tắc đầu tiên. Hãy tưởng tượng chúng ta được giao nhiệm vụ tạo ra một hệ thống tiền kỹ thuật số. Chúng ta cần gì?

Bước 1: Xác định các thành phần cốt lõi

Đầu tiên, chúng ta cần quyết định các yếu tố cơ bản của tiền điện tử. Ở mức cơ bản nhất, chúng ta cần:

  1. Bản ghi về tổng nguồn cung tiền tệ : Theo dõi số lượng đơn vị tiền tệ hiện có.
  2. Một cách để theo dõi số dư : Chúng ta cần biết mỗi tài khoản có bao nhiêu tiền.

Trong Pint, chúng ta có thể xác định những điều này bằng cách sử dụng Block lưu trữ:

 kho {
tổng_cung: int,
số dư: (b256 => int),
}
  • total_supply : Số nguyên này theo dõi tổng số tiền tệ.
  • số dư : Đây là bản đồ (hoặc từ điển) liên kết mỗi địa chỉ (được biểu thị bằng b256, Hash 256 Bit ) với số dư tương ứng.

Bước 2: Tạo loại tiền tệ mới

Tiếp theo, chúng ta cần một cách để tạo ra loại tiền tệ mới — còn được gọi là đúc tiền. Khi đúc tiền tệ, chúng ta muốn tăng tổng cung và cập nhật số dư của người nhận.

Hãy cùng xem xét các bước sau:

  • Chúng ta cần chỉ định ai sẽ nhận được loại tiền mới đúc và số tiền họ sẽ nhận được là bao nhiêu.
  • Sau đó, chúng ta cần cập nhật tổng nguồn cung và số dư của người nhận cho phù hợp.

Logic này trông như thế nào trong Pint:

 vị ngữ Mint {
var người nhận: b256;
var số lượng: int;

trạng thái receiver_balance = mut storage::balances[receiver];
trạng thái total_supply = mut storage::total_supply;

ràng buộc total_supply' == total_supply + số lượng;
ràng buộc receiver_balance' == receiver_balance + số tiền;
}

Phân tích chi tiết:

  • Biến quyết định : người nhận và số tiền thể hiện địa chỉ người nhận và số lượng tiền cần Mint.
  • Biến trạng thái : Chúng ta tham chiếu trạng thái của total_supply và receiver_balance, khai báo chúng có thể thay đổi (mut), nghĩa là chúng có thể được cập nhật.
  • Hạn chế :
    — Ràng buộc đầu tiên đảm bảo rằng tổng nguồn cung tăng theo số lượng được đúc.
    — Ràng buộc thứ hai đảm bảo số dư của người nhận được cập nhật theo số tiền được đúc.

Tuy nhiên, điều quan trọng cần lưu ý là ví dụ này được đơn giản hóa để dễ hiểu. Hợp đồng, theo như đã viết, không có xác thực tích hợp sẵn. Điều này có nghĩa là bất kỳ ai cũng có thể Mint tiền mới hoặc chuyển chúng từ bất kỳ tài khoản nào sang tài khoản khác. Trong một kịch bản thực tế, việc thiếu bảo mật này sẽ là một vấn đề đáng kể. Trong các phần sau, chúng ta sẽ khám phá cách thêm xác thực để đảm bảo rằng chỉ những người dùng được ủy quyền mới có thể Mint hoặc chuyển tiền, giúp hệ thống an toàn hơn.

Bước 3: Chuyển tiền giữa những người dùng

Bây giờ chúng ta có thể tạo ra tiền tệ, bước tiếp theo là cho phép người dùng gửi tiền tệ cho nhau. Để làm được điều này, chúng ta cần:

  • Kiểm tra xem người gửi có đủ tiền để gửi hay không.
  • Trừ số tiền đó vào số dư của người gửi.
  • Thêm số tiền vào số dư của người nhận.

Sau đây là mã Pint tương ứng:

 vị ngữ Gửi {
var từ: b256;
var người nhận: b256;
var số lượng: int;

trạng thái từ_số_cân = mut storage::balances[từ];
trạng thái receiver_balance = mut storage::balances[receiver];

số lượng ràng buộc < từ_số_cân_đối;
ràng buộc from_balance' == from_balance - số tiền;
ràng buộc receiver_balance' == receiver_balance + số tiền;
}

Phân tích chi tiết:

  • Biến quyết định : từ, người nhận và số tiền chỉ rõ ai là người gửi tiền, ai là người nhận tiền và số tiền được gửi là bao nhiêu.
  • Biến trạng thái : from_balance và receiver_balance là số dư hiện tại của người gửi và người nhận, có thể thay đổi.
  • Hạn chế :
    — Ràng buộc đầu tiên kiểm tra xem người gửi có đủ số dư để thực hiện giao dịch chuyển tiền hay không.
    — Ràng buộc thứ hai khấu trừ số tiền đó vào số dư của người gửi.
    — Ràng buộc thứ ba là thêm số tiền vào số dư của người nhận.

Một lần nữa, tính đơn giản ở đây bỏ qua xác thực, điều này trên thực tế là cần thiết để ngăn chặn việc chuyển giao trái phép. Việc thêm các lớp bảo mật như vậy sẽ liên quan đến các điều kiện phức tạp hơn để xác minh danh tính của người dùng trước khi cho phép giao dịch.

Sau đây là hợp đồng đầy đủ, bao gồm cả chức năng đúc tiền và chuyển giao kết hợp:

 kho {
tổng_cung: int,
số dư: (b256 => int),
}

vị ngữ Mint {
var người nhận: b256;
var số lượng: int;

trạng thái receiver_balance = mut storage::balances[receiver];
trạng thái total_supply = mut storage::total_supply;

ràng buộc total_supply' == total_supply + số lượng;
ràng buộc receiver_balance' == receiver_balance + số tiền;
}

vị ngữ Gửi {
var từ: b256;
var người nhận: b256;
var số lượng: int;

trạng thái từ_số_cân = mut storage::balances[từ];
trạng thái receiver_balance = mut storage::balances[receiver];

số lượng ràng buộc < từ_số_cân_đối;
ràng buộc from_balance' == from_balance - số tiền;
ràng buộc receiver_balance' == receiver_balance + số tiền;
}

Hợp đồng tiền phụ này cung cấp một khuôn khổ nền tảng cho một loại tiền điện tử cơ bản, minh họa cách lập trình tập trung vào mục đích đơn giản hóa quy trình bằng cách tập trung vào kết quả mong muốn của mỗi hoạt động.

Xây dựng hợp đồng NFT

Bây giờ chúng ta đã xây dựng được một loại tiền điện tử cơ bản, hãy cùng khám phá một ứng dụng phức tạp và tinh tế hơn: quản lý NFT (Non-Fungible Token). Không giống như các token Có thể hoán đổi , trong đó mỗi đơn vị đều giống hệt nhau, NFT đại diện cho các tài sản độc đáo, đòi hỏi thiết kế hợp đồng phức tạp hơn.

Sau đây là cách bạn có thể xây dựng hệ thống NFT trong Pint:

 sử dụng std::lib::PredicateAddress;
sử dụng std::auth::@auth;
sử dụng std::lib::@safe_increment;
sử dụng std::lib::@mut_keys;

kho {
chủ sở hữu: (int => b256),
Nonce: (b256 => int),
}

giao diện Auth {
vị ngữ Vị ngữ {
// Địa chỉ mà thuật ngữ ủy quyền đang xuất ra.
// Điều này trỏ vị ngữ ủy quyền tới một vị ngữ trong tập hợp này.
// Bằng cách thiết lập địa chỉ này, quyền ủy quyền không thể được sử dụng với vị từ sai.
pub var addr: { hợp đồng: b256, addr: b256 };
}
}

vị ngữ Mint {
Token var : int;
var chủ sở hữu mới: b256;

chủ sở hữu trạng thái = mut storage::owners[Token];
ràng buộc chủ sở hữu == nil;
chủ sở hữu ràng buộc' == chủ sở hữu mới;
}

vị ngữ Chuyển {
// Địa chỉ mà số tiền được gửi đi.
công khai var khóa: b256;
// Địa chỉ mà số tiền được gửi tới.
pub var tới: b256;
// Token đang được chuyển.
pub var Token: int;

chủ sở hữu trạng thái = mut storage::owners[Token];
trạng thái Nonce = mut storage:: Nonce[khóa];

ràng buộc chủ sở hữu == khóa;
ràng buộc chủ sở hữu' == đến;
ràng buộc @safe_increment(Nonce);

// Kiểm tra điều kiện xác thực.
var auth_addr: Địa chỉ vị ngữ;
giao diện AuthI = Auth(auth_addr.contract);
vị ngữ A = AuthI::Predicate(auth_addr.addr);

@auth(khóa; A::addr; auth_addr; @transfer());
}

vị ngữ Hủy bỏ {
// Tài khoản đang hủy chuyển nhượng hoặc đốt.
công khai var khóa: b256;

trạng thái Nonce = mut storage:: Nonce[khóa];

// Tăng Nonce để bất kỳ chuyển nhượng đang chờ xử lý hoặc
// các vết bỏng đều không hợp lệ.
ràng buộc @safe_increment(Nonce);

// Kiểm tra điều kiện xác thực.
var auth_addr: Địa chỉ vị ngữ;
giao diện AuthI = Auth(auth_addr.contract);
vị ngữ A = AuthI::Predicate(auth_addr.addr);

@auth(khóa; A::addr; auth_addr; @cancel());
}

macro @transfer() { { hợp đồng: signed::ADDRESS, địa chỉ: signed::Transfer::ADDRESS } }
macro @cancel() { { hợp đồng: signed::ADDRESS, địa chỉ: signed::Cancel::ADDRESS } }

Block lưu trữ :

  • chủ sở hữu: Ánh xạ ID Token thông báo tới chủ sở hữu tương ứng của họ.
  • Nonce: Theo dõi nonce cho mỗi tài khoản để đảm bảo các giao dịch là duy nhất và không thể phát lại.

Mint vị ngữ :

  • Đúc NFT mới bằng cách chỉ định ID Token cho chủ sở hữu mới.
  • Ràng buộc này đảm bảo rằng ID Token chưa được gán trước đó (owner == nil) và sau đó gán nó cho new_owner.

Chuyển vị ngữ :

  • Quản lý việc chuyển giao NFT từ chủ sở hữu này sang chủ sở hữu khác.
  • Nó bao gồm các kiểm tra ủy quyền để đảm bảo rằng chỉ chủ sở hữu hiện tại mới có thể chuyển nhượng Token.
  • Macro @auth tích hợp với hợp đồng ủy quyền bên ngoài để xác minh giao dịch.

Hủy bỏ vị ngữ :

  • Cho phép tài khoản hủy các giao dịch chuyển tiền hoặc đốt tiền đang chờ xử lý bằng cách tăng Nonce, làm mất hiệu lực mọi giao dịch đã ký trước đó.
  • Nó cũng tích hợp với hệ thống ủy quyền để đảm bảo rằng chỉ người dùng được ủy quyền mới có thể hủy giao dịch.

Hợp đồng NFT này minh họa cách Pint có thể xử lý các ứng dụng phức tạp hơn, thực tế hơn trong khi tích hợp các tính năng bảo mật thiết yếu như kiểm tra tính toàn vẹn của giao dịch và ủy quyền. Nó chứng minh cách lập trình tập trung vào ý định có thể đơn giản hóa quá trình phát triển các ứng dụng blockchain nâng cao bằng cách tập trung vào những gì hệ thống cần đạt được, để lại việc quản lý quy trình cơ bản cho ngôn ngữ và trình giải quyết của nó.

Tại sao các nhà phát triển nên quan tâm

Lập trình lấy ý định làm trung tâm, như Pint minh họa, đại diện cho một cách suy nghĩ mới về phát triển blockchain. Bằng cách trừu tượng hóa các chi tiết thực hiện và tập trung vào kết quả, các nhà phát triển có thể tạo ra các ứng dụng mạnh mẽ, an toàn và linh hoạt hơn. Sự thay đổi Paradigm này làm giảm khả năng xảy ra lỗi, đơn giản hóa quy trình mã hóa và mở ra cánh cửa cho các giải pháp sáng tạo và hiệu quả hơn.

Khi công nghệ blockchain tiếp tục phát triển, việc thành thạo các ngôn ngữ như Pint sẽ rất cần thiết đối với các nhà phát triển muốn đi đầu và xây dựng thế hệ Các ứng dụng phi tập trung (DAPPS) tiếp theo.

Suy nghĩ kết thúc

Lập trình lấy ý định làm trung tâm không chỉ là một cách mới để viết hợp đồng thông minh — mà là một sự tái thiết cơ bản về cách các ứng dụng blockchain có thể được thiết kế và thực hiện. Bằng cách tập trung vào kết quả thay vì hướng dẫn, các nhà phát triển có thể tạo ra các ứng dụng an toàn hơn, có khả năng mở rộng và thân thiện với người dùng hơn, phù hợp hơn với môi trường năng động và phức tạp của blockchain hiện đại.

Khi lập trình tập trung vào ý định trở nên phổ biến hơn, chúng ta có thể thấy các nguyên tắc của nó mở rộng ra ngoài blockchain vào các lĩnh vực khác của phát triển phần mềm, chẳng hạn như IoT, AI và thậm chí là các ứng dụng web truyền thống. Bằng cách tập trung vào kết quả thay vì quy trình, các nhà phát triển trên khắp các ngành có thể mở khóa các cấp độ hiệu quả, bảo mật và tính linh hoạt mới. Tương lai của phần mềm có thể được xác định rất tốt bởi sự thay đổi Paradigm này.

Để tìm hiểu thêm về Pint và đi sâu hơn vào lập trình tập trung vào ý định, hãy xem tài liệu Pint để biết hướng dẫn chi tiết và ví dụ. Đối với những ai quan tâm đến việc triển khai trên Essential, hãy truy cậptài liệu chính thức của Essential để bắt đầu xây dựng và triển khai các ứng dụng tập trung vào ý định của riêng bạn.


Cái nhìn đầu tiên về lập trình tập trung vào ý định ft. Pint ban đầu được xuất bản trên IOSG Ventures trên Trung bình, nơi mọi người tiếp tục cuộc trò chuyện bằng cách làm nổi bật và phản hồi câu chuyện này.

Medium
Tuyên bố từ chối trách nhiệm: Nội dung trên chỉ là ý kiến của tác giả, không đại diện cho bất kỳ lập trường nào của Followin, không nhằm mục đích và sẽ không được hiểu hay hiểu là lời khuyên đầu tư từ Followin.
Thích
5
Thêm vào Yêu thích
1
Bình luận
1