Dead Code Finder: സ്റ്റാറ്റിക് അനാലിസിസിന്റെ കഠിനമായ യാഥാർത്ഥ്യം

ഡെഡ് കോഡ് (dead code) കണ്ടെത്താനായി ഒരു ഹാക്കത്തോണിൽ (hackathon) ഞാൻ ഒരു ടൂൾ നിർമ്മിച്ചു. ലക്ഷ്യം ലളിതമായിരുന്നു: ആരും ഉപയോഗിക്കാത്ത (call ചെയ്യാത്ത) കോഡ് കണ്ടെത്തുക.

കോഡ് ഡിലീറ്റ് ചെയ്താൽ എന്തൊക്കെ തകരാറിലാകും എന്ന് അറിയാനല്ല ഞാൻ ശ്രമിച്ചത്. മറിച്ച്, ഒരു പ്രത്യേക കോഡ് ഭാഗം ആരെങ്കിലും ഉപയോഗിക്കുന്നുണ്ടോ എന്ന് അറിയാനാണ് ഞാൻ ആഗ്രഹിച്ചത്.

ഞാൻ ഇതിനെ Dead Code Finder എന്ന് വിളിച്ചു. കോൾ (calls), ഇംപോർട്ടുകൾ (imports) എന്നിവ കണ്ടെത്താൻ ഇത് ഒരു നോളജ് ഗ്രാഫ് (knowledge graph) ഉപയോഗിക്കുന്നു. ഓരോ കണ്ടെത്തലിനെയും ഇത് മൂന്ന് വിഭാഗങ്ങളായി തിരിക്കുന്നു:

• Confident: ഇൻകമിംഗ് എഡ്ജുകൾ (incoming edges) ഒന്നുമില്ലാത്തതും എന്നാൽ ഒരു എൻട്രി പോയിന്റും (entry point) അല്ലാത്തതും. • Uncertain: ഇൻഹെറിറ്റൻസ് (inheritance) പോലുള്ള സ്റ്റാറ്റിക് അനാലിസിസ് മാത്രം മതിയാകാത്ത സാഹചര്യങ്ങൾ. • Skipped: ഡെക്കറേറ്ററുകൾ (decorators) അല്ലെങ്കിൽ ടെസ്റ്റ് ഫ്രെയിംവർക്കുകൾ (test frameworks) പോലുള്ള ടൂളിന് പരിഹരിക്കാൻ കഴിയാത്ത കാര്യങ്ങൾ.

ഞാൻ ഒരു കർശനമായ നിയമം പാലിച്ചു: കോഡ് ഡിലീറ്റ് ചെയ്യാൻ സുരക്ഷിതമാണെന്ന് ഒരിക്കലും പറയരുത്. ഗ്രാഫിൽ ഒരു റഫറൻസും കണ്ടെത്തിയില്ല എന്ന് മാത്രമേ റിപ്പോർട്ട് പറയൂ.

ഞാൻ പ്രതീക്ഷിച്ചതിലും പ്രയാസകരമായിരുന്നു ഈ പ്രോജക്റ്റ്. പ്ലാറ്റ്‌ഫോമിൽ പ്രധാനമായും രണ്ട് പ്രശ്നങ്ങൾ ഞാൻ നേരിട്ടു:

  1. Missing Tools: കോൺഫിഗറേഷനിൽ (config) ഉണ്ടായിരുന്നിട്ടും റൺടൈമിൽ (runtime) ഗ്രാഫ് ടൂളുകൾ ലഭ്യമായിരുന്നില്ല.
  2. Unreliable Injection: ഏജന്റിന് (agent) ആവശ്യമായ പൂർണ്ണമായ ലോജിക് നൽകുന്നതിൽ സിസ്റ്റം ചിലപ്പോൾ പരാജയപ്പെട്ടു.

ഒരു ഫോളബാക്ക് മോഡ് (fallback mode) നിർമ്മിച്ചുകൊണ്ട് ഞാൻ ഇത് പരിഹരിച്ചു. ഗ്രാഫ് ടൂളുകൾ ലഭ്യമല്ലെങ്കിൽ, ടൂൾ റിപ്പോസിറ്ററിയിലെ (repository) യഥാർത്ഥ ഫയലുകൾ വായിക്കുന്നു. റഫറൻസുകൾ കണ്ടെത്താൻ ഇത് ഫയൽ സെർച്ചുകൾ ഉപയോഗിക്കുന്നു. ഈ രീതി ഉപയോഗിക്കുകയാണെങ്കിൽ, കണ്ടെത്തിയ കാര്യങ്ങളെ 'inferred' എന്ന് അടയാളപ്പെടുത്തുന്നു.

ചില പ്രത്യേക സാഹചര്യങ്ങളിലെ ലോജിക് പിശകുകളും എനിക്ക് പരിഹരിക്കേണ്ടി വന്നു:

  • Dunder methods: __init__ പോലുള്ള മെത്തേഡുകൾ പലപ്പോഴും സീറോ ഇൻകമിംഗ് എഡ്ജുകൾ കാണിക്കുന്നു, കാരണം ഗ്രാഫ് ആ കോളിനെ മെത്തേഡിന് പകരം ക്ലാസുമായിട്ടാണ് ബന്ധിപ്പിക്കുന്നത്. എൻക്ലോസിംഗ് ക്ലാസ് (enclosing class) പരിശോധിച്ചുകൊണ്ട് ഞാൻ ഇത് പരിഹരിച്ചു.
  • Decorators: ഒരു ഡിക്ഷണറിയിലെ സ്ട്രിംഗ് ലുക്കപ്പിലൂടെ (string lookups) വിളിക്കപ്പെടുന്ന ഫംഗ്ഷനുകൾ സ്റ്റാറ്റിക് ഗ്രാഫിന് 'ഡെഡ്' ആയി തോന്നും. ഇവയെ ഞാൻ Skipped വിഭാഗത്തിലേക്ക് മാറ്റി.
  • Tests: ടെസ്റ്റ് ഫ്രെയിംവർക്കുകൾ റിഫ്ലക്ഷൻ (reflection) വഴി മെത്തേഡുകൾ കണ്ടെത്തുന്നു. ഇവയും Skipped വിഭാഗത്തിലേക്ക് മാറ്റുന്നു.

ഫലങ്ങൾ വിശ്വസനീയമായിരുന്നു. എന്റെ ഫോളബാക്ക് മോഡ് ഡെഡ് കോഡ് കൃത്യമായി തിരിച്ചറിയുകയും യഥാർത്ഥ ഗ്രാഫ് ഡാറ്റയുമായി പൊരുത്തപ്പെടുകയും ചെയ്തു. ഇൻഹെറിറ്റൻസ് പോലുള്ള അനിശ്ചിതത്വമുള്ള സാഹചര്യങ്ങളെയും ഇത് കൃത്യമായി അടയാളപ്പെടുത്തി.

പഠിച്ച പാഠങ്ങൾ:

  • അവയെ ആശ്രയിക്കുന്ന ലോജിക് എഴുതുന്നതിന് മുമ്പ് ലഭ്യമായ ടൂളുകൾ ഉറപ്പുവരുത്തുക.
  • "എനിക്കറിയില്ല" എന്ന് പറയുന്ന ഒരു റിപ്പോർട്ട്, തെറ്റായ കാര്യങ്ങൾ ആത്മവിശ്വാസത്തോടെ പറയുന്ന റിപ്പോർട്ടിനേക്കാൾ നല്ലതാണ്.
  • അനിശ്ചിതത്വം അടയാളപ്പെടുത്തുന്നത് നിങ്ങളുടെ കൃത്യമായ കണ്ടെത്തലുകളെ കൂടുതൽ വിശ്വസനീയമാക്കുന്നു.

Source: https://dev.to/hereforlolz/dead-code-finder-gitlab-orbit-based-static-analysis-that-turned-out-to-be-harder-than-expected-4jgk

Optional learning community: https://t.me/GyaanSetuAi