फ़ाइल सिस्टम के लिए Rust
(lwn.net)- 2024 LSFMM+BPF Summit में Linux फ़ाइल सिस्टम पर Rust लागू करने के तरीकों पर चर्चा हुई, और दिसंबर 2023 के RFC के बाद आया दूसरा RFC patch चर्चा का केंद्र रहा
- Rust-for-Linux पक्ष फ़ाइल सिस्टम API की आवश्यकताओं को Rust type system में समाहित करके compile time पर errors पकड़ने, resource cleanup को automate करने, और memory से जुड़ी vulnerabilities कम करने का लक्ष्य रखता है
iget_locked()का उदाहरण दिखाता है कि C caller द्वारा सीधे संभाले जाने वाले null check, inode state का भेद, failure handling आदि को Rust काget_or_create_inode()types और automatic cleanup के ज़रिये enforce करना चाहता है- Dave Chinner, Christian Brauner, James Bottomley, Ted Ts'o आदि ने C API और Rust API के बीच नामों के असंगत होने, API synchronization, object lifecycle के अंतर, और 50 से अधिक फ़ाइल सिस्टमों को ध्यान में रखते हुए maintenance burden पर चिंता जताई
- टकराव का मूल बिंदु Rust abstraction के फ़ायदों से ज़्यादा इस बात पर है कि जब C code लगातार बदलता रहेगा, तब Rust bindings और abstractions को उसके साथ मिलाकर रखने का दर्द कौन उठाएगा
LSFMM+BPF में हुई फ़ाइल सिस्टम Rust session
- 2024 के Linux Storage, Filesystem, Memory Management, and BPF Summit में Wedson Almeida Filho और Kent Overstreet ने Linux फ़ाइल सिस्टम में Rust के इस्तेमाल के तरीकों पर चर्चा की
- Almeida ने दिसंबर 2023 में फ़ाइल सिस्टम के लिए Rust abstraction RFC patch set पोस्ट किया था, और इस approach को लेकर मतभेद थे
- session के मई मध्य में आयोजित होने वाले उसी दिन Almeida ने दूसरा RFC patch version भी पोस्ट किया ताकि अन्य Rust-related विषयों के साथ उस पर चर्चा की जा सके
Rust-for-Linux के फ़ाइल सिस्टम abstraction के लक्ष्य
- प्रस्तावित फ़ाइल सिस्टम abstraction, Rust-for-Linux project की दिशा को दर्शाता है
- इसका मुख्य विचार फ़ाइल सिस्टम API की आवश्यकताओं को Rust type system के ज़रिये अधिक स्पष्ट रूप में व्यक्त करना है ताकि compile time पर गलतियाँ पकड़ी जा सकें
- C code में आसानी से उपलब्ध न होने वाले कामों को भी automate करने की कोशिश है
- उदाहरण: resource cleanup
- लक्ष्य यह है कि फ़ाइल सिस्टम development का अनुभव अधिक productive बने, compiler से पकड़ी जा सकने वाली समस्याओं पर debugging का समय घटे, और memory-related vulnerabilities कम हों
- Overstreet ने कहा कि bcachefs में उन्होंने 2 हफ़्ते तक bug tracking बहुत बार झेली है, और उनके अनुसार Rust, C से अधिक सुविधा देता है
- Rust undefined behavior को हटाता है
- यह code के भीतर क्या हो रहा है, उसे देखने की क्षमता देता है
- उनका मानना है कि अगर Rust code की correctness सिद्ध की जा सके, तो feature development में बाधा डालने वाले bugs बहुत कम हो जाएंगे
iget_locked() के इर्द-गिर्द type system का उदाहरण
- Almeida ने अपनी slides में मौजूदा kernel के
iget_locked()का उदाहरण दिया, जिसमें जटिल requirements हैं - C caller को कई स्थितियाँ खुद संभालनी पड़ती हैं
- यह जाँचना कि return value null है या नहीं
- लौटाए गए
struct inodeके नए inode या मौजूदा inode होने की जाँच करना - अगर वह नया inode है, तो उपयोग से पहले उसका initialization करना
- अगर initialization विफल हो जाए, तो
iget_failed()को call करना
- Al Viro ने Almeida की slides में
iget_locked()caller requirements के कुछ हिस्सों से असहमति जताई, और विस्तृत व्यवहार को लेकर बहस आगे बढ़ी - Overstreet का मानना था कि इन नियमों को Rust types और abstractions में encapsulate करने पर compiler सही handling को enforce कर सकता है
- Almeida ने Rust पक्ष में इसके लिए
get_or_create_inode()नाम का corresponding function दिखाया- C की तरह failure की जाँच अब भी करनी होगी
- success पर caller को या तो एक सामान्य reference-counted inode मिलेगा या एक नया inode
- सामान्य inode के मामले में object का reference खत्म होने पर reference count अपने आप घटेगा
- नए inode के मामले में यदि initialization नहीं किया गया, तो
iget_failed()के समकक्ष handling अपने आप call होगी - नया inode एक बार initialize हो जाने पर सामान्य inode बन जाएगा, और उसके बाद automatic reference-count decrement लागू होगा
- ये व्यवहार type system द्वारा enforce किए जाएंगे
- Viro ने सवाल उठाया कि ये constraints असल source code में कहाँ define होंगी
- Almeida ने जवाब दिया कि Viro और अन्य फ़ाइल सिस्टम developers से constraints समझने के बाद, उन्हें enforce करने वाले types और abstractions बनाए जाएंगे
C API और Rust API के बीच disconnect
- Dave Chinner का कहना था कि अगर C API और Rust API के नाम अलग होंगे, तो मौजूदा developers के लिए C code देखकर Rust में उसके corresponding call को समझना कठिन होगा
- यह चिंता भी सामने आई कि यदि वही नाम न रखे जाएँ, तो यह मौजूदा development community के लिए पूरी तरह अपरिचित API बन सकती है
- C code बदलने पर Rust code को भी उसके साथ बदलना होगा, इसलिए यह सवाल बना रहता है कि वह काम कौन करेगा
- Almeida ने माना कि यह चर्चा का विषय है
- वे name changes के विरोध में नहीं हैं
- लेकिन उनका मानना था कि
iget_locked()बहुत अच्छा नाम नहीं है, और इसे बेहतर नाम देने के अवसर की तरह भी देखा जा सकता है
- Viro का कहना था कि
iget_locked()superblock object का member function नहीं बल्कि library function है, इसलिए यह उदाहरण उपयुक्त नहीं है - Almeida ने जवाब दिया कि
get_or_create_inode()को भी library function में बदला जा सकता है, और यह उदाहरण केवल constraints को types में encode करने का तरीका दिखाने के लिए था
सामान्य abstraction बनाम सरल फ़ाइल सिस्टम-केंद्रित approach
- Christian Brauner का कहना था कि पहले यह तय करना होगा कि Rust abstraction सभी kernel फ़ाइल सिस्टमों के लिए एक सामान्य abstraction है, या Rust में लिखे जाने वाले अपेक्षाकृत सरल फ़ाइल सिस्टमों की ज़रूरतों पर केंद्रित है
- लंबे समय में अगर
get_or_create_inode()जैसी function,iget_locked()की तुलना में कहीं अधिक constraints समाहित करती है, तो समस्या खड़ी हो सकती है - C code, खासकर शुरुआत में, Rust code से तेज़ी से evolve कर सकता है, इसलिए दोनों APIs को लगातार synchronize करना पड़ेगा
- Overstreet का कहना था कि Rust abstractions जोड़ते समय refactoring और cleanup साथ में किया जाएगा या नहीं, यही मुख्य बिंदु है, और उनके अनुसार यह ज़रूरी है
- James Bottomley के अनुसार object lifecycle Rust API में encode हो जाती है, लेकिन C में उसका कोई समकक्ष representation नहीं है
- अगर एक तरफ object lifecycle बदलती है, तो दूसरी तरफ bugs आ सकते हैं
- Chinner ने कहा कि inode object का lifecycle कभी-कभी फ़ाइल सिस्टम के हिसाब से अलग होता है
- अगर API में lifecycle की एक ही समझ डाल दी जाए, तो कुछ फ़ाइल सिस्टमों में वे functions काम नहीं कर सकतीं
- Almeida ने जवाब दिया कि यह उदाहरण केवल उन फ़ाइल सिस्टमों पर लागू होगा जो अभी
iget_locked()call करते हैं और इससे लाभ ले सकते हैं- Rust developers फ़ाइल सिस्टमों को उनका मौजूदा तरीका बदलने के लिए मजबूर नहीं करना चाहते
“दर्द कौन उठाएगा”
- Ted Ts'o ने कहा कि ऐसा लग सकता है जैसे सबको Rust नामक “धर्म” में बदला जा रहा हो, लेकिन Linux में 50 से अधिक फ़ाइल सिस्टम हैं और वे तुरंत Rust में नहीं बदलने वाले
- C code में सुधार जारी रहेगा, और यदि उन बदलावों से Rust bindings टूटती हैं, तो उन bindings पर निर्भर फ़ाइल सिस्टम भी टूट सकते हैं
- Ts'o का मानना था कि फिलहाल Rust bindings दूसरे दर्जे की नागरिक हैं, और टूटी हुई Rust bindings पूरी फ़ाइल सिस्टम community की नहीं बल्कि Rust-for-Linux developers की समस्या हैं
- उनका मानना था कि C code के evolution और Rust bindings development को साथ-साथ चलने देते हुए, type system में बड़े पैमाने पर semantics encode करने वाला approach अच्छा है या बुरा, यह 1-2 साल में स्पष्ट हो जाएगा
- Ts'o के लिए बड़ा बदलाव अंततः दर्द के बँटवारे का प्रश्न है
- C API बदलने वाला developer प्रभावित C code तो ठीक कर सकता है, लेकिन Rust न जानने के कारण यह कह सकता है कि वह Rust bindings नहीं ठीक करेगा
- Almeida ने जवाब दिया कि उनका लक्ष्य C API को स्थिर करना नहीं, बल्कि फ़ाइल सिस्टम developers से API का semantics समझकर उसे Rust में encode करना है
- Bottomley का मानना था कि bindings में semantics जितनी अधिक encode होगी, synchronization के दृष्टिकोण से वे उतनी अधिक fragile हो सकती हैं
- Almeida ने कहा कि API बदलने पर API users को update करना पड़ता है, और यह बाकी users की तरह ही है
methods, functions और types में क्या रखा जाए
- Viro ने फिर यह आपत्ति उठाई कि
iget_locked()का विकल्प methods पर निर्भर करता है- उनका मानना था कि method इस्तेमाल करने पर arguments स्पष्ट रूप से निर्दिष्ट नहीं होते
- Overstreet का कहना था कि methods के प्रति यह असंतोष उन भाषाओं से आता है जो C++ की तरह inheritance पर अत्यधिक निर्भर हैं
- उनके अनुसार Rust ऐसा नहीं करता, और Rust में methods अधिकतर syntactic element हैं
- Jan Kara ने inode से जुड़े behavior और
iget_locked()function में निहित behavior के बीच अंतर किया- inode के साथ reference count और उसकी handling जैसी behavior जुड़ी होती है
iget_locked()function में अलग behavior अंतर्निहित होती है
- Overstreet और Almeida ने जवाब दिया कि दोनों हिस्से types में encode होते हैं लेकिन अलग रहते हैं, और inode type का उपयोग करने वाली अन्य functions अलग-अलग properties वाले return values दे सकती हैं
- Viro ने समझाया कि VFS में inode मौजूदा तरीके से क्यों काम करता है, और इस बात से सहमत हुए कि छोटा शुरू करके आगे की दिशा देखनी चाहिए
- Overstreet ने कहा कि यह उदाहरण शायद अपनी जटिलता के कारण शुरुआत के लिए अच्छा नहीं था, और Viro ने “नहीं, ऐसा नहीं है” कहते हुए session का समापन किया
1 टिप्पणियां
Hacker News टिप्पणियाँ
यह समझ नहीं आता कि हर file system का inode lifecycle कस्टम होता है, फिर भी वही lifecycle management functions इस्तेमाल होते हैं और बस semantics बदल जाती है
अगर एक ही function को implementation details के हिसाब से अलग तरह से इस्तेमाल करना पड़े, तो यह abstraction layer के उलट लगता है
अगर inode lifecycle file system के हिसाब से अलग है, तो उसे file-system-specific functions से मैनेज किया जाना चाहिए
ऐसी जानकारी इकट्ठा करते हुए शायद ऐसे refactoring points दिखें, जिनसे यह सवाल शुरुआत में ही न उठे, और यह अच्छी बात है
यह VFS layer का overview है, जो file-system-specific behavior को संभालते हुए भी kernel side पर एक consistent interface बनाए रखता है
inode lifecycle शायद चर्चा शुरू करने के लिए एक शुरुआती उदाहरण रहा हो
compiler temporary references में मदद कर सकता है, लेकिन file system को अब भी link count डिस्क पर स्टोर करनी होगी
iget_locked()पर है, जो उनमें से एक खास pattern हैसभी file systems इस तरीके का इस्तेमाल नहीं करते, और कुछ स्थितियों में इसे इस्तेमाल नहीं किया जाता
उदाहरण के लिए, FAT inode numbers बना देता है और FAT location से inode तक अपनी mapping बनाए रखता है, इसलिए वह इसका इस्तेमाल नहीं करता
procजैसे file systems भी हैं, जो inode objects को cache नहीं करतेinode object खुद चाहे कहीं से भी आया हो, उसका state flow एक जैसा लगता है, इसलिए consumer के नज़रिए से
inodeका इस्तेमाल बदलता नहीं हैजो बदलता है, वह यह है कि file system layer inode object को कैसे बनाती है और अंदरूनी तौर पर कैसे handle करती है
शायद सवाल गलत तरह से पूछा जा रहा है
क्या Rust को इस तरह बदलना चाहिए कि वह C को कॉल करना और आसान बना दे?
मैंने Rust थोड़ा इस्तेमाल किया है, लेकिन एक hobby developer के नज़रिए से अभी भी यह साफ़ नहीं है कि C के साथ interoperate कैसे करना चाहिए
जबकि C++ या Objective C में सही header include करके function call कर देते हैं
Swift में Objective C files शामिल की जा सकती हैं, और वहाँ से C को कॉल किया जा सकता है
इस मामले में, kernel developers से भाषा के हिसाब से ढलने की उम्मीद करने के बजाय, शायद Rust language को थोड़ा और लचीला होना चाहिए
बस external function declare करके उसे call करना होता है
उदाहरण के लिए, Rust book के https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#usin... में दिखाया गया है कि
extern "C"से declare किया जा सकता हैअगर किसी complex library में सारे declarations हाथ से नहीं लिखने हैं, तो C header files से
externdeclarations auto-generate करने के लिए bindgen जैसे tool का इस्तेमाल किया जा सकता है: https://github.com/rust-lang/rust-bindgenयह तर्क दिया जा सकता है कि bindgen जैसी चीज़ Rust में ही शामिल हो ताकि third-party dependency या
build.rssetup के बिना इस्तेमाल हो सके, लेकिन इस लेख का मुख्य बिंदु वह नहीं हैसमस्या low-level binding नहीं, बल्कि Rust-शैली के high-level wrapper हैं, और मनमाने C code से ऐसे wrappers अपने-आप बनाने वाला कोई general tool हो ही नहीं सकता
लेख इस बारे में है कि Rust में kernel filesystem driver वगैरह को वास्तव में implement कैसे किया जाए
यह भी महत्वपूर्ण है कि kernel के अंदर का Rust code अनिवार्य रूप से C interface को consume करता है
जिन use cases की बात हो रही है, उनमें bindgen काफ़ी ठीक बैठता है: https://github.com/rust-lang/rust-bindgen
Rust से कॉल करने के लिए
extern "C" fn foo() -> Tdeclare कर दें, और#[link]attribute याbuild.rsसे link flags पास कर देंbindgencrate से bindings पहले से generate की जा सकती हैं, याbuild.rsमें बनाकरinclude!()से शामिल किया जा सकता हैआम तौर पर generated bindings ही रखने वाला एक
-syscrate बनाया जाता है, और actual code उस sys crate की bindings को सामान्य तरीके सेuseकरता हैC++ और Objective C में भी सिर्फ सही header include करना ही नहीं, library के साथ link भी करना पड़ता है
दोनों दिशाओं में call संभव है, लेकिन अगर C वह व्यक्त ही नहीं कर सकता जो Rust व्यक्त कर सकता है, तो इससे उस API design पर बड़ा असर पड़ता है जिसे दोनों तरफ़ को साझा करना है
C function को
extern "C"के रूप में declare करके call कर दीजिएआम तौर पर
unsafeचाहिए होता है, और references को raw pointers में बदलना या cast करना पड़ता है, लेकिन syntax ख़ुद सीधा हैC header files को scan करके declarations बनाने वाले tools भी हैं, और bindgen सबसे ज़्यादा इस्तेमाल होता है
इस लेख का मुद्दा भाषा ख़ुद नहीं, बल्कि Rust का इस्तेमाल कैसे किया जाए, इसके ज़्यादा क़रीब है
Rust-for-Linux developers चाहते हैं कि Rust की सुविधाओं और type system से API calls की semantics को encode किया जाए ताकि चीज़ें ज़्यादा सुरक्षित हों और कम errors हों
C पक्ष के लोग चिंतित हैं कि ऐसा करने से C API के behavior और semantics को आगे विकसित करना मुश्किल हो जाएगा
क्योंकि जब C API बदलेगा, तो Rust API भी ठीक करना पड़ेगा, और वे यह बोझ नहीं उठाना चाहते
ज़्यादा स्वीकार्य विकल्प यह है कि Rust API में semantics encode करने के लिए Rust की सुविधाओं और type system का कम इस्तेमाल किया जाए
तब C API बदलने पर Rust API को अपडेट करना mechanical और सरल हो जाएगा, लेकिन अगर Rust-for-Linux, Rust की सुविधाओं से बेहतर और ज़्यादा सुरक्षित API ही नहीं बना सकता, तो फिर इस काम का मतलब क्या है, यह सवाल उठता है
हालाँकि, अगर कोई मानता है कि वह भाषा को पर्याप्त नहीं समझता, तो इस विषय पर बहुत निर्णायक ढंग से बोलना थोड़ा अजीब लगता है
मुझे साफ़ नहीं था कि यह Rust API C API को wrap कर रही है, या उसका reimplementation है, क्योंकि Linux filesystem के बारे में मेरी जानकारी कम है
अगर यह reimplementation है या अलग API है, तो C API के नामों को जस का तस रखना समय के साथ और ज़्यादा भ्रम पैदा करेगा
शुरुआत में भले ही इससे परिचित developers को जल्दी समझने में मदद मिले, फिर भी ऐसा लगता है
iget_locked()के समकक्ष चीज़ दिखाई थी, और उसका नामget_or_create_inode()थाजवाब यह है कि यह reimplementation है, और लगता है कि वही नाम इस्तेमाल नहीं किए जा रहे
इस तरह की चर्चाएँ आम तौर पर जिस दिशा में जाती हैं और बदलाव की जो मात्रा यहाँ है, उसे देखते हुए यह चर्चा आश्चर्यजनक रूप से शिष्ट है
मैं इस thread के नकारात्मक माहौल से सहमत नहीं हूँ
मुझे इस बात से काफ़ी आशा मिलती है कि जुड़े हुए लोगों ने मुख्य pain points को बिना बकवास के साफ़-साफ़ रखा है
असली चर्चा शायद programming language की बहस की तरह काफ़ी तीखी, बिखरी हुई और nitpicking से भरी रही होगी, जहाँ मज़बूत राय रखने वाले अजीब लोग भिड़ते हैं
यह summary लिखने वाले Jake Edge शायद उन हिस्सों को हटाकर सिर्फ़ मुख्य बात लिखने में बहुत अच्छे हैं
lwn.net पेज के नीचे कुछ comments काफ़ी असभ्य हैं
ज़रा कल्पना कीजिए कि जिस open source project में आप योगदान दे रहे हैं, उस पर Science advances one funeral at a time जैसी टिप्पणी मिले
Linux kernel में ज़्यादा विकल्प होना हमेशा फायदेमंद है
लेकिन Rust हर चीज़ का जवाब हो, यह ज़रूरी नहीं
Rust एक सुरक्षित programming model सुनिश्चित करने की पूरी कोशिश करता है, लेकिन उस model की भी सीमाएँ हैं
यह ऐसा लग सकता है कि memory issues हों तो Rust इस्तेमाल करो, और concurrency issues हों तो Rust में बदल दो, लेकिन
unsafeblocks के बिना C जो कुछ करता है वह सब नहीं किया जा सकताRust इन समस्याओं पर एक नया नज़रिया दे सकता है, लेकिन यह कोई पूरा समाधान नहीं है
C, ख़ासकर kernel में इस्तेमाल होने वाला C, हर व्यक्ति पर यह ज़िम्मेदारी डाल देता है कि वह सभी implicit rules पूरी तरह जानता हो
यह scalable नहीं है
एक ही data structure का इस्तेमाल करने वाले kernel developers भी एक कमरे में इकट्ठा होकर उन नियमों पर पूरी सहमति नहीं बना पाए
Rust उन नियमों को सामने लाने में मज़बूत है जिन्हें जानना ज़रूरी है, और अगर कोई दूसरा व्यक्ति rule compliance की गारंटी दे सकता है, तो उसे मेरी समस्या न रहने देने में भी
कभी-कभी नतीजा कम optimal हो सकता है, लेकिन Linux kernel में भी कई बार कम optimal default ही सही होता है, और जो लोग बेहतर performance के लिए छह और अजीब rules सीख सकते हैं, उनके लिए
unsafeescape hatch दे देना काफ़ी हैunsafeblocks इस्तेमाल किए जा सकते हैंबस इन्हें तभी इस्तेमाल करना चाहिए जब वाकई ज़रूरत हो
बहुत सीमित प्रभाव वाले
unsafeblock का उपयोग करने से बाकी code में मिलने वाली guarantees पूरी तरह गायब नहीं हो जातींunsafecode चाहिए होता हैलेकिन
unsafeका इस्तेमाल करना पड़ता है, इसलिए Rust उपयुक्त नहीं है — यह एक ग़लतफ़हमी हैRust का safe/unsafe विभाजन इस मकसद से है कि code के कौन-से हिस्से unsafe हैं यह साफ़ दिखे, ताकि audit छोटे हिस्सों पर केंद्रित किया जा सके और अगर वे हिस्से सही हों तो बाकी के सही काम करने पर भरोसा किया जा सके
क्या filesystem code में ऐसा कोई ठोस कारण है कि कुछ चीज़ें अनिवार्य रूप से
unsafeही हों?शायद यह सिर्फ़ कुछ जगहों पर ज़रूरी बहुत छोटे subset तक सीमित होगा
अंदर वास्तव में क्या हो रहा है, यह सहज रूप से समझ में नहीं आता
minutes को देखें तो kernel के अंदर Rust एक additional complexity cost जैसा लगता है
अगर operating system को बिल्कुल शुरुआत से फिर से लिखा जा रहा हो, तो language की ताकत का पूरा फ़ायदा उठाया जा सकता है
लेकिन जब इसे पहले से मौजूद विशाल codebase के बगल में जोड़ा जाता है, तो जैसा यहाँ दिख रहा है, अतिरिक्त समस्याएँ पैदा होती हैं
Asahi Linux के Rust GPU driver के एक महीने में बन जाने वाली blog post देखी जा सकती है
Google में
tales of the m1 gpuखोजें; लेखक की Hacker News के बारे में बहुत नकारात्मक राय हैचाहें तो लिंक से पढ़ सकते हैं: https://asahilinux.org/2022/11/tales-of-the-m1-gpu/
क्या यह व्यापक रूप से लागू होगा, यह आने वाले कुछ वर्षों में ही पता चलेगा
उस cost को future और progress को अपनाने के लिए ज़रूरी माना जाएगा
समझ नहीं आता कि इसे safe subset तक सीमित क्यों नहीं किया जाता, बजाय इसके कि बहुत-से अज्ञात bugs और trade-offs वाले इस बड़े बहाव में कूद पड़े
सिर्फ़ इसलिए कि चीज़ पहले से बहुत बड़ी है, इसका मतलब यह नहीं कि innovation रोक दी जाए और उसे अनिश्चितकाल के लिए maintenance mode में डाल दिया जाए
जैसे वास्तविक कर व्यवस्था में, अगर एक तरफ़ की cost किसी दूसरी समस्या की भरपाई में इस्तेमाल हो सके, तो वह net loss नहीं भी हो सकती
अभी निष्कर्ष तक न पहुँची एक अकेली चर्चा देखकर यह कह देना कि इससे कोई समस्या offset नहीं होगी, तर्क को बहुत छोटा कर देता है
C API और Rust API के नाम मेल न खाने की वजह से C code देखकर उसके बराबर का Rust call समझ में न आना, पुरानी naming conventions से लड़ाई जैसा लगता है
एक ही नाम बनाए रखते हुए, और जब कोई वैकल्पिक नाम चाहिए हो तो नया नाम पुराने नाम को wrap करे — इस तरीके से चीज़ें अच्छी तरह सुलझती देखी गई हैं
फिर भी naming कठिन है
बाकी दो हैं concurrency और off-by-one errors