באגים של אחרים

11/09/2019

במעבר שלנו למתכנתים שמשתמשים כל היום בספריות חיצוניות (npm, pip, gem, nuget) קל לראות כמה פחות עבודה אנחנו צריכים להשקיע בכתיבת קוד - כי מישהו אחר כבר כתב את זה - אבל גם קל לפספס את השעות שאנחנו מאבדים בחקירה ותיקון באגים של אחרים.

אז הבוקר שלי התחיל עם שדרוג לאחת הספריות ב npm ובגלל חוסר תשומת לב שדרגתי בטעות עוד כמה, מה שיצר package.json שנראה בערך כך:

{
  "name": "myapp",
  "version": "1.1.0",
  "dependencies": {
    "actioncable": "^5.1.1",
    "babel-core": "6.26.3",
    "babel-eslint": "^10.0.1",
    "babel-loader": "^8.0.5",
    "babel-plugin-react-transform": "^3.0.0",
    "babel-polyfill": "^6.8.0",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "babel-preset-stage-0": "^6.5.0",
    "babel-runtime": "^6.6.1",
    "body-parser": "^1.15.1",
    "classnames": "^2.2.5",
    "create-react-class": "15.6.3",
    "css-loader": "^2.1.1",
    "es5-shim": "^4.5.8",
    "es6-promise": "^4.1.0",
    "eslint-plugin-import": "^2.3.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "exports-loader": "^0.7.0",
    "expose-loader": "^0.7.1",
    "github-api": "^3.0.0",
    "history": "4.9.0",
    "immutable": "^4.0.0-rc.12",
    "imports-loader": "^0.8.0",
    "isomorphic-fetch": "^2.2.1",
    "jquery": "^3.2.1",
    "jquery-ui": "^1.10.5",
    "jquery-ujs": "^1.2.1",
    "loader-utils": "^1.1.0",
    "mirror-creator": "1.1.0",
    "nighthawk": "2.2.0",
    "null-loader": "^1.0.0",
    "prop-types": "^15.7.2",
    "query-string": "^6.5.0",
    "react": "^16.8.6",
    "react-addons-linked-state-mixin": "^15.0.2",
    "react-bootstrap": "^1.0.0-beta.8",
    "react-burger-menu": "^2.0.2",
    "react-dom": "^16.8.6",
    "react-dropzone": "^10.1.4",
    "react-immutable-proptypes": "^2.1.0",
    "react-on-rails": "11.2.2",
    "react-quill": "^1.0.0-rc.2",
    "react-redux": "^7.0.3",
    "react-scroll": "^1.0.16",
    "react-sticky": "^6.0.1",
    "react-transition-group": "^4.0.0",
    "redux": "^4.0.1",
    "redux-batched-subscribe": "^0.1.6",
    "redux-promise": "^0.6.0",
    "redux-thunk": "^2.1.0",
    "router": "^1.1.4",
    "scriptjs": "^2.5.8",
    "strftime": "^0.10.0",
    "underscore": "^1.8.3",
    "url-parse": "^1.1.1"
  },
  "devDependencies": {
    "@babel/core": "^7.6.0",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/preset-env": "^7.6.0",
    "@babel/preset-react": "^7.0.0",
    "bootstrap-sass": "^3.3.6",
    "bootstrap-sass-loader": "^1.0.10",
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "17.1.0",
    "eslint-plugin-react": "^7.0.1",
    "esprima-fb": "^15001.1001.0-dev-harmony-fb",
    "express": "^4.13.4",
    "file-loader": "^3.0.1",
    "jade": "^1.11.0",
    "jscs": "^3.0.3",
    "node-sass": "^4.5.3",
    "react-transform-hmr": "^1.0.4",
    "sass-loader": "^7.1.0",
    "speed-measure-webpack-plugin": "^1.3.1",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.39.3",
    "webpack-bundle-analyzer": "^3.4.1",
    "webpack-cli": "^3.3.8"
  }
}

וכן יש פה המון ספריות. וכן בחצי מהן אני לא משתמש. וגם יש שם בעיה.

העניין שכשמשהו מתנהג לא כמו שצריך להתנהג התוצאה יכולה היתה להיות הודעה על המסך שבטעות בחרת גירסא לא נכונה של ספריה, אבל זה כמעט אף פעם לא מה שקורה. מה שקורה בדרך כלל זה שאיזה שורת קוד במקום לא קשור בכלל מחזירה תוצאה דומה-אבל-לא-בדיוק למה שהיתה אמורה להחזיר, והערך מתגלגל כמו כדור שלג עד שמתפוצץ רחוק מאוד מהמקום בו הבעיה התחילה.

לקח לי כמעט שעה להבין שהבעיה בכלל קשורה לשדרוג. מסתבר ששדרוג Minor Versions בספריה מסוימת יצר התנגשות עם ספריה אחרת ופיצוץ במקום רחוק. שנמוך גירסא של Immutable.JS בחזרה לגירסא 3.8.2 הציל את המצב, למרות שאני עדיין לא יודע להסביר למה.

כדאי לזכור שמחשבים לא משקרים, ושאם לא שיניתם שום דבר בקוד ודברים מתחילים להישבר כדאי להיות חשדנים לגבי ספריות חיצוניות וקוד של אחרים. שנמוך לגירסאות יציבות הוא לפעמים פתח המילוט המהיר ביותר.