Rich Hickey ਅਤੇ Clojure ਦੇ ਵਿਚਾਰ—ਸਰਲਤਾ, ਅਪਰਿਵਰਤਨੀਯਤਾ ਅਤੇ ਵਧੀਆ ਡਿਫਾਲਟ—ਇਹ ਪ੍ਰਯੋਗਿਕ ਸਬਕ ਹਨ ਜੋ ਜਟਿਲ ਪ੍ਰਣਾਲੀਆਂ ਨੂੰ ਠੰਡੀ, ਬੇਹਤਰ ਅਤੇ ਭਰੋਸੇਯੋਗ ਬਣਾਉਂਦੇ ਹਨ।

ਸਾਫਟਵੇਅਰ ਅਕਸਰ ਇੱਕੋ ਵਾਰ ਵਿੱਚ ਉੱਚੀ ਜਟਿਲਤਾ ਨਹੀਂ ਬਣਦਾ। ਇਹ ਹਰ "ਤਰਕਯੋਗ" ਫੈਸਲੇ ਨਾਲ ਆਹਿਸਤਾ-ਆਹਿਸਤਾ ਬਣਦਾ ਹੈ: ਡੈਡਲਾਈਨ ਹਿੱਟ ਕਰਨ ਲਈ ਇੱਕ ਛੋਟਾ cache, ਨਕਲ ਕਰਨ ਦੀ ਥਾਂ ਸਾਂਝਾ ਮਯੂਟੇਬਲ ਆਬਜੈਕਟ, "ਇਹ ਇਕ ਵਿਸ਼ੇਸ਼ ਮਾਮਲਾ ਹੈ" ਦੇ ਕੇ ਨਿਯਮਾਂ ਤੋਂ ਅਪਵਾਦ। ਹਰ ਚੋਣ ਛੋਟੀ ਲੱਗਦੀ ਹੈ, ਪਰ ਇਕੱਠੇ ਹੋ ਕੇ ਉਹ ਸਿਸਟਮ ਬਣਾਉਂਦੇ ਹਨ ਜਿੱਥੇ ਬਦਲਾਅ ਜੋਖਿਮ ਭਰਿਆ ਮਹਿਸੂਸ ਹੁੰਦਾ ਹੈ, ਬੱਗਸ ਦੁਹਰਾਉਣਾ ਮੁਸ਼ਕਿਲ ਹੁੰਦਾ ਹੈ, ਅਤੇ ਨਵੀਆਂ ਫੀਚਰਾਂ ਸ਼ਾਮਿਲ ਕਰਨਾ ਬਣਾਉਣ ਤੋਂ ਜ਼ਿਆਦਾ ਸਮਾਂ ਲੈਣਾ ਸ਼ੁਰੂ ਕਰ ਦਿੰਦਾ ਹੈ।
ਜਟਿਲਤਾ ਇਸ ਲਈ "ਜਿੱਤਦੀ" ਹੈ ਕਿਉਂਕਿ ਇਹ ਅਸਥਾਈ ਰਾਹਤ ਦਿੰਦੀ ਹੈ। ਇੱਕ ਨਵੀਂ ਡਿਪੈਂਡੈਂਸੀ ਜੋੜਨੀ ਅਕਸਰ ਫਿਲਹਾਲ ਤੇਜ਼ ਹੁੰਦੀ ਹੈ ਬਜਾਏ ਮੌਜੂਦਾ ਚੀਜ਼ ਨੂੰ ਸਧਾਰਨ ਕਰਨ ਦੇ। ਸਟੇਟ ਨੂੰ ਪੈਚ ਕਰਨਾ ਆਸਾਨ ਹੋ ਸਕਦਾ ਹੈ ਬਜਾਏ ਇਸ ਦੇ ਕਿ ਸਵਾਲ ਪੁੱਛੋ ਕਿ ਸਟੇਟ ਪੰਜ ਸਰਵਿਸਾਂ ਵਿੱਚ ਕਿਉਂ ਫੈਲਿਆ ਹੋਇਆ ਹੈ। ਅਤੇ ਜਦੋਂ ਸਿਸਟਮ ਡੌਕਯੂਮੈਂਟੇਸ਼ਨ ਨਾਲੋਂ ਤੇਜ਼ ਵਧਦਾ ਹੈ ਤਾਂ conventions ਅਤੇ tribal knowledge 'ਤੇ ਨਿਰਭਰ ਹੋਣਾ ਲੁਭਾਉਣ ਵਾਲਾ ਹੁੰਦਾ ਹੈ।
ਇਹ Clojure ਦਾ ਟਿਊਟੋਰਿਯਲ ਨਹੀਂ ਹੈ, ਅਤੇ ਤੁਹਾਨੂੰ Clojure ਜਾਣਨ ਦੀ ਲੋੜ ਨਹੀਂ ਕਿ ਇਸ ਤੋਂ ਫਾਇਦਾ ਲੈ ਸਕੋ। ਮਕਸਦ Rich Hickey ਦੇ ਕੰਮ ਨਾਲ ਜੁੜੀਆਂ ਪ੍ਰਯੋਗਿਕ ਵਿਚਾਰਾਂ ਨੂੰ ਲੈਣਾ ਹੈ—ਇਹੋ ਜਿਹੇ ਵਿਚਾਰ ਜੋ ਤੁਸੀਂ ਹਰ-ਰੋਜ਼ ਦੀ ਇੰਜੀਨੀਅਰਿੰਗ ਫੈਸਲਿਆਂ ਵਿੱਚ ਲਾਗੂ ਕਰ ਸਕਦੇ ਹੋ, ਭਾਵੇਂ ਭਾਸ਼ਾ ਕੋਈ ਵੀ ਹੋਵੇ।
ਜ਼ਿਆਦਾਤਰ ਜਟਿਲਤਾ ਉਹ ਕੋਡ ਨਹੀਂ ਬਣਾਉਂਦੀ ਜੋ ਤੁਸੀਂ ਜਾਣ-ਬੁਝ ਕੇ ਲਿਖਦੇ ਹੋ; ਇਹ ਉਹ ਹੈ ਜੋ ਤੁਹਾਡੇ ਟੂਲਸ ਡਿਫਾਲਟ ਰੂਪ ਵਿੱਚ ਆਸਾਨ ਬਣਾਉਂਦੇ ਹਨ। ਜੇ ਡਿਫਾਲਟ "ਹਰ ਥਾਂ mutable ਆਬਜੈਕਟ", ਤਾਂ ਛੁਪਾ coupling ਬਣੇਗਾ। ਜੇ ਡਿਫਾਲਟ "ਸਟੇਟ memory ਵਿੱਚ ਹੈ", ਤਾਂ ਡੀਬੱਗਿੰਗ ਅਤੇ traceability ਨਾਲ ਝੱਝਕ ਹੋਵੇਗੀ। ਡਿਫਾਲਟਸ ਆਦਤਾਂ ਬਣਾਉਂਦੇ ਹਨ, ਅਤੇ ਆਦਤਾਂ ਸਿਸਟਮਾਂ ਬਣਾਉਂਦੀਆਂ ਹਨ।
ਅਸੀਂ ਤਿੰਨ ਥੀਮਾਂ 'ਤੇ ਧਿਆਨ ਦੇਵਾਂਗੇ:
ਇਹ ਵਿਚਾਰ ਤੁਹਾਡੇ ਡੋਮੇਨ ਦੀ ਜਟਿਲਤਾ ਘਟਾਉਂਦੇ ਨਹੀਂ, ਪਰ ਤੁਹਾਡੇ ਸਾਫਟਵੇਅਰ ਨੂੰ ਉਸਦੀਆਂ ਵਧਣ ਤੋਂ ਰੋਕ ਸਕਦੇ ਹਨ।
Rich Hickey ਲੰਬੇ ਸਮੇਂ ਦਾ ਸਾਫਟਵੇਅਰ ਡਿਵੈਲਪਰ ਅਤੇ ਡਿਜ਼ਾਈਨਰ ਹੈ, ਜਿਸਦਾ ਸਭ ਤੋਂ ਵੱਧ ਜਾਣਿਆ ਜਾਣ ਵਾਲਾ ਕੰਮ Clojure ਬਣਾਉਣਾ ਅਤੇ ਐਸੀਆਂ ਗੱਲਾਂ ਤੇ ਟੌਕ ਦੇਣਾ ਹੈ ਜੋ ਆਮ ਪ੍ਰੋਗਰਾਮਿੰਗ ਆਦਤਾਂ ਨੂੰ ਚੈਲੈਂਜ ਕਰਦੀਆਂ ਹਨ। ਉਹ ਫੈਡਾਂ ਮੋੜਾਂ ਦੀ ਪਿੱਛੇ ਨਹੀਂ ਦੌੜਦਾ—ਉਹ ਤਰਜੀਹ ਰਖਦਾ ਹੈ ਕਿ ਕਿਉਂ ਸਿਸਟਮ ਬਦਲਣ ਵਿੱਚ ਮੁਸ਼ਕਿਲ, ਸਮਝਣ ਵਿੱਚ ਔਖਾ ਅਤੇ ਵੱਡੇ ਹੋਣ 'ਤੇ ਭਰੋਸੇਯੋਗ ਨਹੀਂ ਬਣਦੇ।
Clojure ਇੱਕ ਆਧੁਨਿਕ ਪ੍ਰੋਗ੍ਰਾਮਿੰਗ ਭਾਸ਼ਾ ਹੈ ਜੋ JVM (Java ਦਾ runtime) ਅਤੇ JavaScript ਵਰਗੇ ਜਾਣੇ-ਪਹਿਚਾਣੇ ਪਲੇਟਫਾਰਮਾਂ 'ਤੇ ਚਲਦੀ ਹੈ। ਇਹ ਮੌਜੂਦਾ ਇਕੋਸਿਸਟਮਾਂ ਨਾਲ ਕੰਮ ਕਰਨ ਲਈ ਬਣਾਈ ਗਈ ਹੈ ਜਦੋਂ ਕਿ ਇੱਕ ਵਿਸ਼ੇਸ਼ ਅੰਦਾਜ਼ ਦੀ ਪ੍ਰੋਤਸਾਹਨਾ ਕਰਦੀ ਹੈ: ਜਾਣਕਾਰੀ ਨੂੰ ਸਧਾਰਨ ਡੇਟਾ ਰੂਪ ਵਿੱਚ ਦਰਸਾਓ, ਅਪਰਿਵਰਤਨੀਯ ਮੁੱਲਾਂ ਨੂੰ ਤਰਜੀਹ ਦਿਓ, ਅਤੇ "ਕੀ ਹੋਇਆ" ਨੂੰ "ਕਿੰਝ ਤੁਸੀਂ ਸਕਰੀਨ 'ਤੇ ਦਿਖਾਉਂਦੇ ਹੋ" ਤੋਂ ਵੱਖ ਰੱਖੋ।
ਤੁਸੀਂ ਇਸਨੂੰ ਐਸਾ ਭਾਸ਼ਾ ਸਮਝ ਸਕਦੇ ਹੋ ਜੋ ਤੁਹਾਨੂੰ ਸਾਫ਼ ਬਿਲਡਿੰਗ ਬਲੌਕਾਂ ਵੱਲ ਧੱਕੇ ਅਤੇ ਛੁਪੇ ਸਾਈਡ-ਇਫੈਕਟਸ ਤੋਂ ਦੂਰ ਰੱਖੇ।
Clojure ਛੋਟੇ ਸਕ੍ਰਿਪਟ ਛੋਟੇ ਕਰਨ ਲਈ ਬਣਾਈ ਨਹੀਂ ਗਈ ਸੀ। ਇਸਦਾ ਟੀਚਾ ਦੁਹਰਾਈ ਜਾਣ ਵਾਲੇ ਪ੍ਰਾਜੈਕਟ ਦਰਦਾਂ ਤੇ ਸੀ:
Clojure ਦੇ ਡਿਫਾਲਟਸ ਘੱਟ moving parts ਵੱਲ ਧੱਕਦੇ ਹਨ: ਸਥਿਰ ਡੇਟਾ ਸਟ੍ਰਕਚਰ, ਸਪਸ਼ਟ ਅਪਡੇਟ, ਅਤੇ ਏਸੇ ਤਰ੍ਹਾਂ ਦੇ ਟੂਲ ਜੋ ਕੋਆਰਡੀਨੇਸ਼ਨ ਨੂੰ ਸੁਰੱਖਿਅਤ ਬਣਾਉਂਦੇ ਹਨ।
ਮੁੱਲ ਭਾਸ਼ਾ ਬਦਲਣ ਤੱਕ ਸੀਮਤ ਨਹੀਂ। Hickey ਦੇ ਕੋਰ ਵਿਚਾਰ—ਜ਼ਰੂਰਤਹੀਣ interdependencies ਨੂੰ ਹਟਾ ਕੇ ਸਰਲਤਾ, ਡੇਟਾ ਨੂੰ ਟਿਕਾਉ ਤੱਥਾਂ ਵਜੋਂ ਵੇਖਣਾ, ਅਤੇ mutable state ਘਟਾਉਣਾ—Java, Python, JavaScript ਆਦਿ ਵਿੱਚ ਵੀ ਪ੍ਰਣਾਲੀਆਂ ਨੂੰ ਸੁਧਾਰ ਸਕਦੇ ਹਨ।
Rich Hickey ਨੇ simple ਅਤੇ easy ਵਿਚਕਾਰ ਤੇਜ਼ ਰੇਖਾ ਖਿੱਚੀ ਹੈ—ਅਤੇ ਇਹ ਇੱਕ ਰੇਖਾ ਹੈ ਜੋ ਜ਼ਿਆਦਾਤਰ ਪ੍ਰਾਜੈਕਟ ਬਿਨਾਂ ਧਿਆਨ ਦਿੱਤੇ ਪਾਰ ਕਰ ਲੈਂਦੇ ਹਨ।
Easy ਹੁੰਦਾ ਹੈ ਕਿਵੇਂ ਕੁਝ ਅੱਜ ਮਹਿਸੂਸ ਹੁੰਦਾ ਹੈ। Simple ਹੁੰਦਾ ਹੈ ਕਿੰਨੇ ਹਿੱਸੇ ਹਨ ਅਤੇ ਉਹ ਕਿੰਨੇ ਗਾਢੇ ਤੌਰ 'ਤੇ ਜੁੜੇ ਹੋਏ ਹਨ।
ਸਾਫਟਵੇਅਰ ਵਿੱਚ, "ਆਸਾਨ" ਅਕਸਰ ਮਤਲਬ ਹੁੰਦਾ ਹੈ "ਅੱਜ ਟਾਈਪ ਕਰਨ ਲਈ ਤੇਜ਼", ਜਦਕਿ "ਸਰਲ" ਮਤਲਬ ਹੁੰਦਾ ਹੈ "ਅਗਲੇ ਮਹੀਨੇ ਤਕ ਟੁੱਟਣਾ ਮੁਸ਼ਕਿਲ"।
ਟੀਮਾਂ ਅਕਸਰ ਉਹ shortcuts ਚੁਣਦੀਆਂ ਹਨ ਜੋ ਤੁਰੰਤ friction ਘਟਾਉਂਦੀਆਂ ਹਨ ਪਰ ਅਦਿੱਖੀ ਸੰਰਚਨਾ ਜੋਰ ਦਿੰਦੀ ਹਨ ਜੋ ਰੱਖ-ਰਖਾਅ ਦੀ ਲੋੜ ਪੈਦੀ ਹੈ:
ਹਰ ਚੋਣ ਦਿਖਦੀ ਹੈ ਜਿਵੇਂ ਰਫ਼ਤਾਰ, ਪਰ ਇਹ moving parts, ਖਾਸ ਕੇਸਾਂ ਅਤੇ cross-dependencies ਦੀ ਗਿਣਤੀ ਵਧਾਉਂਦੀ ਹੈ। ਇਸ ਲਈ ਪ੍ਰਣਾਲੀਆਂ ਬਿਨਾਂ ਕਿਸੇ ਇਕ ਵੱਡੇ ਗਲਤ ਫੈਸਲੇ ਦੇ ਨਾਜ਼ੁਕ ਹੋ ਜਾਂਦੀਆਂ ਹਨ।
ਤੇਜ਼ੀ ਨਾਲ ship ਕਰਨਾ ਵਧੀਆ ਹੋ ਸਕਦਾ ਹੈ—ਪਰ ਸਰਲਤਾ ਬਿਨਾਂ ਰਫ਼ਤਾਰ ਅਕਸਰ ਇਸਦਾ ਮਤਲਬ ਹੁੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਭਵਿੱਖ 'ਤੇ ਕਰਜ਼ਾ ਲੈ ਰਹੇ ਹੋ। ਇਸ ਦਾ ਬਿਆਨ ਬੱਗਸ ਦੇ ਰੂਪ ਵਿੱਚ ਆਉਂਦਾ ਹੈ ਜੋ ਦੁਹਰਾਉਣਾ ਔਖਾ ਹੁੰਦੇ ਹਨ, onboarding ਸੁਸਤ ਹੁੰਦਾ ਹੈ, ਅਤੇ ਬਦਲਾਅ "ਧਿਆਨ ਨਾਲ ਕੋਆਰਡੀਨੇਟ" ਕਰਨ ਦੀ ਲੋੜ ਹੋੰਦੀ ਹੈ।
ਡਿਜ਼ਾਈਨ ਜਾਂ PR ਸਮੀਖਿਆ ਵੇਲੇ ਇਹ ਸਵਾਲ ਪੁੱਛੋ:
"ਸਟੇਟ" ਸਿੱਧਾ ਉਹ ਚੀਜ਼ ਹੈ ਜੋ ਤੁਹਾਡੀ ਸਿਸਟਮ ਵਿੱਚ ਬਦਲ ਸਕਦੀ ਹੈ: ਯੂਜ਼ਰ ਦਾ ਕਾਰਟ, ਖਾਤਾ ਬੈਲੈਂਸ, ਮੌਜੂਦਾ ਸੰਰਚਨਾ, ਵਰਕਫਲੋ ਦਾ ਕਦਮ। ਮੁਸ਼ਕਲ ਗੱਲ ਇਹ ਨਹੀਂ ਕਿ ਬਦਲਾਅ ਮੌਜੂਦ ਹੈ—ਬਦਲਾਅ ਹਰ ਵਾਰ ਇੱਕ ਨਵਾਂ ਮੌਕਾ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਚੀਜ਼ਾਂ ਅਸਮਝਦਾਰ ਹੋ ਸਕਦੀਆਂ ਹਨ।
ਲੋਕ ਜਦੋਂ ਕਹਿੰਦੇ ਹਨ "ਸਟੇਟ ਬੱਗਸ ਬਣਾਉਂਦੀ ਹੈ", ਉਹ ਆਮ ਤੌਰ 'ਤੇ ਇਸਦਾ ਮਤਲਬ ਹੈ: ਜੇ ਇਕੋ ਜਾਣਕਾਰੀ ਵੱਖ-ਵੱਖ ਸਮੇਂ ਜਾਂ ਥਾਵਾਂ 'ਤੇ ਵੱਖ-ਵੱਖ ਹੋ ਸਕਦੀ ਹੈ, ਤਾਂ ਤੁਹਾਡੇ ਕੋਡ ਨੂੰ ਲਗਾਤਾਰ ਇਹ ਪ੍ਰਸ਼ਨ ਉੱਤਰਣਾ ਪੈਂਦਾ ਹੈ, “ਹੁਣ ਸੱਚਾ ਵਰਜਨ ਕਿਹੜਾ ਹੈ?” ਇਸ ਨੂੰ ਗਲਤ ਸਮਝਣ ਨਾਲ ਐਸੇ ਬੱਗ ਆਉਂਦੇ ਹਨ ਜੋ ਬੇਸੁਤਰ ਮਹਿਸੂਸ ਹੁੰਦੇ ਹਨ।
Mutability ਮਤਲਬ ਹੈ ਕਿ ਇੱਕ ਆਬਜੈਕਟ ਨੂੰ ਉਸਦੀ ਥਾਂ 'ਤੇ ਸੋਧਿਆ ਜਾਂਦਾ ਹੈ: "ਉਹੀ" ਚੀਜ਼ ਸਮੇਤ ਸਮੇਂ ਵਿੱਚ ਵੱਖਰੀ ਹੋ ਜਾਂਦੀ ਹੈ। ਇਹ ਪ੍ਰਭਾਵਸ਼ਾਲੀ ਲੱਗ ਸਕਦਾ ਹੈ, ਪਰ ਇਹ reasoning ਨੂੰ ਔਖਾ ਬਣਾਉਂਦਾ ਹੈ ਕਿਉਂਕਿ ਤੁਸੀਂ ਜੋ ਇੱਕ ਪਲ ਪਹਿਲਾਂ ਵੇਖਿਆ ਸੀ, ਉਸ 'ਤੇ ਭਰੋਸਾ ਨਹੀਂ ਕਰ ਸਕਦੇ।
ਇੱਕ ਸੰਬੰਧਿਤ ਉਦਾਹਰਣ ਸਾਂਝੀ spreadsheet ਜਾਂ ਦਸਤਾਵੇਜ਼ ਹੈ। ਜੇ ਕਈ ਲੋਕ ਇਕੋ ਸੈੱਲ ਨੂੰ ਇੱਕੋ ਸਮੇਂ ਸੋਧ ਸਕਦੇ ਹਨ, ਤਾਂ ਤੁਹਾਡੀ ਸਮਝ ਫੌਰਨ ਅਣ-ਸਹੀ ਹੋ ਸਕਦੀ ਹੈ: totals ਬਦਲ ਜਾਂਦੇ ਹਨ, ਫਾਰਮੂਲੇ ਟੁੱਟ ਜਾਂਦੇ ਹਨ, ਜਾਂ ਕੋਈ ਕਤਾਰ ਗੁਆ ਜਾਂਦੀ ਹੈ। ਇੱਥੇ ਮੁੱਦਾ ਇਸ ਦੀ ਸਾਂਝੀ, ਸੋਧਯੋਗ ਕੁਦਰਤ ਹੈ।
ਸਾਫਟਵੇਅਰ ਸਟੇਟ ਵੀ ਏਸੇ ਤਰ੍ਹਾਂ ਵਰਤਦੀਆ ਹੈ। ਜੇ ਦੋ ਹਿੱਸੇ ਇੱਕੋ mutable ਮੁੱਲ ਨੂੰ ਪੜ੍ਹਦੇ ਹਨ, ਇੱਕ ਹਿੱਸਾ ਬਿਨਾਂ ਦੈਨਿਆ ਜਾਣਕਾਰੀ ਰੱਖਦੇ ਹੋਏ ਉਸੇ ਸਮੇਂ ਇਸਨੂੰ ਸੋਧ ਸਕਦਾ ਹੈ ਜਿਸ ਨਾਲ ਦੂਜਾ ਪੁਰਾਣੇ ਧਾਰਣਾ ਨਾਲ ਅੱਗੇ ਵੱਧਦਾ ਹੈ।
Mutable state ਡੀਬੱਗਿੰਗ ਨੂੰ ਪੁਰਾਤਤਵ ਵਿਗਿਆਨ ਬਣਾਉਂਦੀ ਹੈ। ਇੱਕ ਬੱਗ ਰਿਪੋਰਟ ਅਕਸਰ ਇਹ ਨਹੀਂ ਦੱਸਦੀ ਕਿ "ਡੇਟਾ 10:14:03 'ਤੇ ਗਲਤ ਤਰੀਕੇ ਨਾਲ ਸੋਧਿਆ ਗਿਆ"। ਤੁਸੀਂ ਸਿਰਫ ਅੰਤ ਦਾ ਨਤੀਜਾ ਵੇਖਦੇ ਹੋ: ਇੱਕ ਗਲਤ ਨੰਬਰ, ਅਣਉਮੀਦਿਤ ਦਰਜਾ, ਇੱਕ ਅਰਜ਼ੀ ਜੋ ਸਿਰਫ ਕਦੇ-ਕਦੇ ਫੇਲ ਹੁੰਦੀ ਹੈ।
ਕਿਉਂਕਿ ਸਟੇਟ ਸਮੇਂ ਦੇ ਨਾਲ ਬਦਲਦਾ ਹੈ, ਸਭ ਤੋਂ ਮਹੱਤਵਪੂਰਨ ਸਵਾਲ ਬਣਦਾ ਹੈ: ਇੱਥੇ ਪਹੁੰਚਣ ਲਈ ਕਿਹੜੀ ਸੋਧਾਂ ਦੀ ਲੜੀ ਸਨ? ਜੇ ਤੁਸੀਂ ਉਹ ਇਤਿਹਾਸ ਦੁਹਰਾਉਣ ਨਹੀਂ ਕਰ ਸਕਦੇ, ਤਦੇ ਵਰਤਾਰ ਅਣਪੇਛਾਣਯੋਗ ਬਣ ਜਾਂਦੀ ਹੈ:
ਇਸ ਲਈ Hickey ਸਟੇਟ ਨੂੰ ਇਕ ਜਟਿਲਤਾ ਗੁਣਾ ਮੰਨਦਾ ਹੈ: ਜਦ ਡੇਟਾ ਸਾਂਝਾ ਅਤੇ mutable ਦੋਹਾਂ ਹੁੰਦੀ ਹੈ, ਤਾਂ ਸੰਭਾਵਨਾਵਾਂ ਦੀ ਗਿਣਤੀ ਤੇਜ਼ੀ ਨਾਲ ਵੱਧਦੀ ਹੈ ਅਤੇ ਤੁਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ ਸੰਭਾਲਣ ਕਾਬਲ ਨਹੀਂ ਰਹਿੰਦੇ।
ਅਪਰਿਵਰਤਨੀਯਤਾ ਸਿਧਾ ਮਤਲਬ ਹੈ ਏਸਾ ਡੇਟਾ ਜੋ ਬਣਿਆ ਜਾ ਚੁੱਕਣ ਤੋਂ ਬਾਅਦ ਨਹੀਂ ਬਦਲਦਾ। ਇੱਕ ਮੌਜੂਦਾ piece of information ਨੂੰ ਉਸਦੀ ਥਾਂ 'ਤੇ ਸੋਧਨ ਦੀ ਬਜਾਏ, ਤੁਸੀਂ ਅਪਡੇਟ ਨੂੰ ਦਰਸਾਉਂਣ ਲਈ ਇੱਕ ਨਵਾਂ piece of information ਬਣਾਉਂਦੇ ਹੋ।
ਇੱਕ ਰਸੀਦ ਦੀ ਸੋਚੋ: ਇੱਕ ਵਾਰ ਪ੍ਰਿੰਟ ਹੋਣ 'ਤੇ ਤੁਸੀਂ ਲਾਈਨ ਆਈਟਮ ਮਿਟਾ ਕੇ ਟੋਟਲ ਮੁੜ ਨਹੀਂ ਲਿਖਦੇ। ਜੇ ਕੁਝ ਬਦਲਦਾ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਇੱਕ ਸੋਧੀ ਹੋਈ ਰਸੀਦ ਜਾਰੀ ਕਰਦੇ ਹੋ। ਪੁਰਾਣੀ ਰਸੀਦ ਅਜੇ ਵੀ ਮੌਜੂਦ ਹੈ, ਅਤੇ ਨਵੀਂ ਸਪੱਸ਼ਟ ਤੌਰ 'ਤੇ "ਤਾਜ਼ਾ ਵਰਜਨ" ਹੈ।
ਜਦ ਡੇਟਾ ਚੁਪਚਾਪ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ, ਤਾਂ ਤੁਸੀਂ ਪਿੱਛੇ-ਪਿੱਛੇ ਹੋ ਰਹੀਆਂ ਸੋਧਾਂ ਦੀ ਚਿੰਤਾ ਬੰਦ ਕਰ ਦਿੰਦੇ ਹੋ। ਇਹ ਰੋਜ਼ਾਨਾ reasoning ਨੂੰ ਕਾਫੀ ਆਸਾਨ ਬਣਾਉਂਦਾ ਹੈ:
ਇਹੀ ਕਾਰਨ ਹੈ ਕਿ Hickey ਸਰਲਤਾ ਬਾਰੇ ਗੱਲ ਕਰਦੇ ਹਨ: ਘੱਟ ਛੁਪੇ ਸਾਈਡ-ਇਫੈਕਟਸ ਦਾ ਮਤਲਬ ਘੱਟ ਮਾਨਸਕ ਸ਼ਾਖਾਂ ਨੂੰ ਟ੍ਰੈਕ ਕਰਨ।
ਨਵੀਆਂ ਵਰਜਨਾਂ ਬਣਾਉਣਾ ਵੇਖਣ ਵਿੱਚ ਬਰਬਾਦੀ ਲੱਗ ਸਕਦੀ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਵਿਕਲਪ ਨਾਲੋਂ ਬਦਲੇ ਹੋਏ ਨੂੰ ਤੁਲਨਾ ਨਹੀਂ ਕਰਦੇ। ਥਾਂ 'ਤੇ ਸੋਧਣ ਤੁਹਾਨੂੰ ਪੁੱਛਣ 'ਤੇ ਛੱਡ ਦਿੰਦਾ ਹੈ: "ਇਸਨੂੰ ਕੌਣ ਸੋਧਿਆ? ਕਦੋਂ? ਪਹਿਲਾਂ ਕੀ ਸੀ?" ਅਪਰਿਵਰਤਨੀਯ ਡੇਟਾ ਨਾਲ, ਸੋਧਾਂ ਸਪਸ਼ਟ ਹੁੰਦੀਆਂ ਹਨ: ਇੱਕ ਨਵੀਂ ਵਰਜਨ ਮੌਜੂਦ ਹੈ, ਅਤੇ ਪੁਰਾਣਾ ਡੀਬੱਗਿੰਗ, ਆਡਿਟਿੰਗ ਜਾਂ ਰੋਲਬੈਕ ਲਈ ਉਪਲਬਧ ਰਹਿੰਦਾ ਹੈ।
Clojure ਇਸ ਗੱਲ ਨੂੰ ਸੁਭਾਵਿਕ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਅਪਡੇਟ ਨਵੀਆਂ ਕੀਮਤਾਂ ਪੈਦਾ ਕਰਨ ਵੱਲ ਰੁਝਾੳ਼ ਕਰਨ, ਪੁਰਾਣੀਆਂ ਨੂੰ ਸੋਧਣ ਦੀ ਬਜਾਏ।
ਅਪਰਿਵਰਤਨੀਯਤਾ ਮੁਫ਼ਤ ਨਹੀਂ ਆਉਂਦੀ। ਤੁਸੀਂ ਹੋ ਸਕਦਾ ਹੈ ਹੋਰ ਆਬਜੈਕਟ allocate ਕਰੋ, ਅਤੇ ਉਹ ਟੀਮਾਂ ਜੋ "बस ਚੀਜ਼ ਨੂੰ ਅਪਡੇਟ ਕਰਦੇ ਹਨ" ਦੀ ਆਦਤ ਵਿੱਚ ਹਨ ਉਨ੍ਹਾਂ ਨੂੰ ਅਨੁਕੂਲ ਹੋਣ ਲਈ ਸਮਾਂ ਲੱਗ ਸਕਦਾ ਹੈ। ਚੰਗੀ ਖ਼ਬਰ ਇਹ ਹੈ ਕਿ ਆਧੁਨਿਕ ਇੰਪਲੀਮੇਂਟੇਸ਼ਨਾਂ ਅਕਸਰ ਹੇਠਾਂ ਸਾਂਝੇ ਸਟ੍ਰਕਚਰ ਵਰਤਦੀਆਂ ਹਨ ਤਾਂ ਜੋ ਮੈਮੋਰੀ ਦੀ ਲਾਗਤ ਘਟੇ, ਅਤੇ ਨਤੀਜਾ ਆਮ ਤੌਰ 'ਤੇ ਸ਼ਾਂਤ ਸਿਸਟਮ ਹੁੰਦੇ ਹਨ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਵੱਖ-ਵੱਖ ਅਤੇ ਸਮਝ ਤੋਂ ਬਾਹਰ ਘਟਨਾਵਾਂ ਘੱਟ ਹੁੰਦੀਆਂ ਹਨ।
Concurrency ਸਿਰਫ "ਕਈ ਚੀਜ਼ਾਂ ਇਕੱਠੇ ਹੋ ਰਹੀਆਂ ਹਨ" ਹੈ। ਇੱਕ ਵੈਬ ਐਪ ਹਜ਼ਾਰਾਂ ਬੇਨਤੀਆਂ ਸੰਭਾਲ ਰਿਹਾ ਹੋਵੇ, ਇੱਕ ਪੇਮੈਂਟ ਸਿਸਟਮ ਬੈਲੈਂਸ ਅਪਡੇਟ ਕਰਨ ਵੇਲੇ ਰਸੀਦਾਂ ਬਣਾਉਂਦਾ ਹੋਵੇ, ਜਾਂ ਇੱਕ ਮੋਬਾਈਲ ਐਪ ਪਿਛੋਂ-ਪਾਸੇ ਸਿੰਕ ਕਰ ਰਿਹਾ ਹੋਵੇ—ਇਹ ਸਾਰੀਆਂ concurrency ਉਦਾਹਰਣ ਹਨ।
ਮੁਸ਼ਕਲ ਗੱਲ ਇਹ ਨਹੀਂ ਕਿ ਕਈ ਚੀਜ਼ਾਂ ਹੁੰਦੀਆਂ ਹਨ, ਪਰ ਇਹ ਹੈ ਕਿ ਉਹ ਅਕਸਰ ਇੱਕੋ ਡੇਟਾ ਨੂੰ ਛੂਹਦੀਆਂ ਹਨ।
ਜਦ ਦੋ ਵਰਕਰ ਇੱਕੋ ਮੁੱਲ ਨੂੰ ਪੜ੍ਹਦੇ ਅਤੇ ਫਿਰ ਸੋਧਦੇ ਹਨ, ਤਾਂ ਅੰਤਿਮ ਨਤੀਜਾ timing 'ਤੇ ਨਿਰਭਰ ਹੋ ਸਕਦਾ ਹੈ। ਇਹ ਇੱਕ race condition ਹੈ: ਇੱਕ ਬੱਗ ਜੋ ਆਸਾਨੀ ਨਾਲ ਦੁਹਰਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ, ਪਰ ਸਿਸਟਮ ਬਹੁਤ ਦੇਸੀ ਹੋਣ 'ਤੇ ਆਉਂਦੀ ਹੈ।
ਉਦਾਹਰਨ: ਦੋ ਬੇਨਤੀਆਂ ਇੱਕ order total ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੀਆਂ ਹਨ।
ਕੋਈ "ਕ੍ਰੈਸ਼" ਨਹੀਂ ਹੋਇਆ, ਪਰ ਇੱਕ ਅਪਡੇਟ ਖੋ ਗਿਆ। ਲੋਡ ਹੇਠ ਇਹ timing windows ਵੱਧ ਆਮ ਹੋ ਜਾਂਦੇ ਹਨ।
ਰਵਾਇਤੀ ਸੁਧਾਰ—ਲੌਕਸ, synchronized blocks, ਧਿਆਨ ਨਾਲ ordering—ਕਾਮ ਕਰਦੇ ਹਨ, ਪਰ ਇਹ ਸਭ ਨੂੰ ਕੋਆਰਡੀਨੇਟ ਕਰਨ ਲਈ ਮਜ਼ਬੂਰ ਕਰਦੇ ਹਨ। ਕੋਆਰਡੀਨੇਸ਼ਨ ਮਹਿੰਗੀ ਹੈ: ਇਹ throughput ਘਟਾਉਂਦੀ ਹੈ ਅਤੇ ਜਿਵੇਂ ਕੋਡਬੇਸ ਵੱਡਾ ਹੁੰਦਾ ਹੈ ਐਹੋ ਨਾਜ਼ੁਕ ਹੋ ਜਾਂਦੀ ਹੈ।
ਅਪਰਿਵਰਤਨੀਯ ਡੇਟਾ ਨਾਲ, ਇੱਕ ਮੁੱਲ ਥਾਂ 'ਤੇ ਸੋਧੀ ਨਹੀਂ ਜਾਂਦੀ। ਇਸਦੀ ਥਾਂ, ਤੁਸੀਂ ਬਦਲਾਅ ਨੂੰ ਦਰਸਾਉਂਦੀ ਇੱਕ ਨਵੀਂ ਕੀਮਤ ਬਣਾਉਂਦੇ ਹੋ।
ਇਹ ਇੱਕ ਸਪਸ਼ਟ ਬਦਲਾਅ ਪੈਟਰਨ ਪੂਰੇ ਸਮੂਹ ਦੀਆਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਦੂਰ ਕਰ ਦਿੰਦਾ:
ਅਪਰਿਵਰਤਨੀਯਤਾ concurrency ਨੂੰ ਮੁਫ਼ਤ ਨਹੀਂ ਬਣਾਉਂਦੀ—ਤੁਹਾਨੂੰ ਫਿਰ ਵੀ ਇਹ ਨਿਰਧਾਰਤ ਕਰਨਾ ਪਵੇਗਾ ਕਿ ਕਿਹੜੀ ਵਰਜਨ current ਹੈ। ਪਰ ਇਹ concurrent ਪ੍ਰੋਗਰਾਮਾਂ ਨੂੰ ਕਾਫੀ ਭਵਿੱਖਵਾਣੀਯੋਗ ਬਣਾਉਂਦੀ ਹੈ, ਕਿਉਂਕਿ ਡੇਟਾ ਖੁਦ ਇੱਕ moving target ਨਹੀਂ ਹੁੰਦਾ। ਜਦ traffic spike ਕਰਦਾ ਹੈ ਜਾਂ background jobs ਢੇਰ ਹੋ ਜਾਂਦੀਆਂ ਹਨ, ਤੁਸੀਂ ਘੱਟ ਮਿਸਟੀਰੀਅਸ, timing-dependent ਫੇਲਯਾਨ ਦੇਖਦੇ ਹੋ।
"ਵਧੀਆ ਡਿਫਾਲਟ" ਮਤਲਬ ਹੈ: ਸੁਰੱਖਿਅਤ ਚੋਣ ਆਟੋਮੈਟਿਕ ਤੌਰ 'ਤੇ ਹੁੰਦੀ ਹੈ, ਅਤੇ ਤੁਸੀਂ ਸਿਰਫ਼ तब ਹੀ ਵਾਧੂ ਜੋਖਮ ਲੈਂਦੇ ਹੋ ਜਦੋਂ ਤੁਸੀਂ ਸੋਚ-ਸਮਝ ਕੇ ਉਸ ਨੂੰ ਅਨ-ਆਪਟ ਕਰੋ।
ਇਹ ਛੋਟਾ ਲੱਗ ਸਕਦਾ ਹੈ, ਪਰ ਡਿਫਾਲਟਸ ਚੁਪਚਾਪ ਇਹ ਗਾਈਡ ਕਰਦੀਆਂ ਹਨ ਕਿ ਲੋਕ ਸੋਮਵਾਰ ਸਵੇਰੇ ਕੀ ਲਿਖਣਗੇ, ਸਮੀਖਿਆਕਾਰ ਸ਼ੁੱਕਰਵਾਰ ਦੁਪਹਿਰ ਕਿਹੜਾ ਕੋਡ ਮੰਨ ਲੈਂਦੇ ਹਨ, ਅਤੇ ਨਵਾਂ teammate ਕੋਡਬੇਸ ਤੋਂ ਪਹਿਲਾਂ ਕੀ ਸਿੱਖਦਾ ਹੈ।
"ਵਧੀਆ ਡਿਫਾਲਟ" ਹਰ ਫੈਸਲੇ ਲਈ ਨਹੀਂ ਹੁੰਦਾ। ਇਹ ਆਮ ਰਾਹ ਨੂੰ ਘੱਟ ਗਲਤ-ਗਲਤੀ ਵਾਲਾ ਬਣਾਉਂਦਾ ਹੈ।
ਉਦਾਹਰਨ:
ਇਹਨਾਂ ਵਿਚੋਂ ਕੋਈ ਵੀ ਜਟਿਲਤਾ ਖਤਮ ਨਹੀਂ ਕਰਦੇ, ਪਰ ਇਹ ਉਸਦੇ ਫੈਲਾਅ ਤੋਂ ਰੋਕਦੇ ਹਨ।
ਟੀਮਾਂ ਸਿਰਫ ਡੌਕਯੂਮੈਂਟੇਸ਼ਨ ਦੀ ਪਾਲਣਾ ਨਹੀਂ ਕਰਦੀਆਂ—ਉਹ ਉਸ ਰਸਤੇ ਦੀ ਪਾਲਣਾ ਕਰਦੀਆਂ ਹਨ ਜੋ ਕੋਡ "ਚਾਹੁੰਦਾ" ਹੈ।
ਜਦ shared state mutate ਕਰਨਾ ਆਸਾਨ ਹੁੰਦਾ ਹੈ, ਇਹ ਇੱਕ ਸਧਾਰਨ shortcut ਬਣ ਜਾਂਦਾ ਹੈ, ਅਤੇ ਸਮੀਖਿਆਕਾਰ ਅਕਸਰ ਇਰਾਦੇ 'ਤੇ बहਸ ਕਰਨ ਲੱਗ ਪੈਂਦੇ ਹਨ: “ਕੀ ਇਹ ਇੱਥੇ ਸੁਰੱਖਿਅਤ ਹੈ?” ਜਦਕਿ ਅਪਰਿਵਰਤਨੀਯਤਾ ਅਤੇ pure functions ਡਿਫਾਲਟ ਹੋ ਜਾਣ, ਸਮੀਖਿਆਕਾਰ logic ਅਤੇ correctness 'ਤੇ ਧਿਆਨ ਕੇਂਦ੍ਰਿਤ ਕਰ ਸਕਦੇ ਹਨ ਕਿਉਂਕਿ ਰਿਸਕੀ moves ਸਾਫ਼ ਨਜਰ ਆਉਂਦੇ ਹਨ।
ਦੂਜੇ ਸ਼ਬਦਾਂ ਵਿੱਚ, ਵਧੀਆ ਡਿਫਾਲਟ ਇੱਕ ਸਿਹਤਮੰਦ baseline ਬਣਾਉਂਦੇ ਹਨ: ਜ਼ਿਆਦਾਤਰ ਬਦਲਾਵ consistent ਦਿੱਖਦੇ ਹਨ, ਅਤੇ ਅਸਧਾਰਣ ਪੈਟਰਨ ਉਨ੍ਹਾਂ ਨੂੰ ਸਵਾਲ ਉਠਾਉਣ ਯੋਗ ਬਣਾਉਂਦੇ ਹਨ।
ਲੰਬੇ ਸਮੇਂ ਲਈ ਰੱਖ-ਰਖਾਅ ਅਕਸਰ ਮੌਜੂਦਾ ਕੋਡ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ ਬਦਲਣ ਬਾਰੇ ਹੁੰਦਾ ਹੈ।
ਵਧੀਆ ਡਿਫਾਲਟ ਨਵੇਂ ਸਾਥੀਂਅਾ ਨੂੰ ਰੈਂਪ-ਅੱਪ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਦੇ ਹਨ ਕਿਉਂਕਿ ਘੱਟ ਛੁਪੇ ਨਿਯਮ ਹੁੰਦੇ ਹਨ ("ਧਿਆਨ ਰੱਖੋ, ਇਹ function ਗੋਪਨੀਅਤ ਤੌਰ 'ਤੇ ਉਸ global map ਨੂੰ ਅਪਡੇਟ ਕਰਦਾ ਹੈ")। ਸਿਸਟਮ ਸੋਚਣ ਵਿੱਚ ਆਸਾਨ ਬਣ ਜਾਂਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਭਵਿੱਖ ਦੇ ਹਰ ਫੀਚਰ, ਫਿਕਸ ਅਤੇ ਰੀਫੈਕਟਰ ਦਾ ਖ਼ਰਚ ਘਟਦਾ ਹੈ।
Hickey ਦੀਆਂ ਟੌਕਸ ਵਿੱਚ ਇੱਕ ਉਪਯੋਗੀ ਮਾਨਸਿਕ ਬਦਲਾਅ ਇਹ ਹੈ ਕਿ ਤੱਥ (ਹੁਣ ਕੀ ਹੋਇਆ) ਨੂੰ ਵਿਊਜ਼ (ਅਸੀਂ ਹੁਣ ਕਿਹੜੀ ਜਾਣਕਾਰੀ ਮੰਨਦੇ ਹਾਂ) ਤੋਂ ਵੱਖ ਰੱਖੋ। ਜ਼ਿਆਦਾਤਰ ਪ੍ਰਣਾਲੀਆਂ ਇਹ ਦੋਹਾਂ ਨੂੰ ਮਿਲਾ ਦਿੰਦੀਆਂ ਹਨ ਕੇਵਲ ਮੌਜੂਦਾ ਮੁੱਲ ਸਟੋਰ ਕਰਕੇ—ਅੱਜ ਨੂੰ ਕੱਲ ਨੂੰ overwrite ਕਰਕੇ—ਜੋ ਸਮਾਂ ਨੂੰ ਲੰਘਾ ਦਿੰਦਾ ਹੈ।
ਇੱਕ ਤੱਥ ਇੱਕ ਅਪਰਿਵਰਤਨੀਯ ਰਿਕਾਰਡ ਹੈ: “Order #4821 10:14 'ਤੇ ਰੱਖਿਆ ਗਿਆ”, “Payment ਸਫਲ ਹੋਈ”, “Address ਬਦਲੀ ਗਈ।” ਇਹ ਸੋਧੇ ਨਹੀਂ ਜਾਂਦੇ; ਜਦ ਹਕੀਕੀਤਾ ਬਦਲਦੀ ਹੈ, ਤੁਸੀਂ ਨਵੀਆਂ ਤੱਥਾਂ ਜੋੜਦੇ ਹੋ।
ਇੱਕ ਵਿਊ ਉਹ ਹੈ ਜੋ ਤੁਹਾਡੀ ਐਪ ਨੂੰ ਹੁਣ ਚਾਹੀਦਾ ਹੈ: “ਮੌਜੂਦਾ shipping address ਕੀ ਹੈ?” ਜਾਂ “ਕਿਸ ਗਾਹਕ ਦਾ ਮੌਜੂਦਾ ਬੈਲੈਂਸ ਕੀ ਹੈ?” ਵਿਊਜ਼ ਤੱਥਾਂ ਤੋਂ ਮੁਕੰਮਲ ਕੀਤੀ ਜਾਂ ਸਕਦੀ ਹੈ, cache ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ, index ਕੀਤੀ ਜਾਂ ਸਕਦੀ ਹੈ, ਜਾਂ ਗਤੀਵਿਧੀ ਲਈ materialize ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।
ਜਦ ਤੁਸੀਂ ਤੱਥ ਰੱਖਦੇ ਹੋ, ਤੁਸੀਂ ਪ੍ਰਾਪਤ ਕਰਦੇ ਹੋ:
ਰਿਕਾਰਡਾਂ ਨੂੰ overwrite ਕਰਨਾ ਇੱਕ spreadsheet ਸੈੱਲ ਨੂੰ ਅਪਡੇਟ ਕਰਨ ਵਰਗਾ ਹੈ: ਤੁਸੀਂ ਸਿਰਫ਼ ਨਵਾਂ ਨੰਬਰ ਵੇਖਦੇ ਹੋ।
ਇੱਕ append-only ਲੌਗ ਇੱਕ ਚੈੱਕਬੁੱਕ ਰਜਿਸਟਰ ਵਰਗਾ ਹੈ: ਹਰ ਐਂਟਰੀ ਇੱਕ ਤੱਥ ਹੈ, ਅਤੇ "ਮੌਜੂਦਾ ਬੈਲੈਂਸ" ਉਹ entries ਤੋਂ ਵਿਖਿਆ ਗਿਆ ਵਿਊ ਹੈ।
ਤੁਹਾਨੂੰ ਪੂਰੇ event-sourced ਆਰਕੀਟੈਕਚਰ ਨੂੰ ਅਪਣਾਉਣ ਦੀ ਲੋੜ ਨਹੀਂ। ਬਹੁਤ ਸਾਰੀਆਂ ਟੀਮਾਂ ਛੋਟੇ ਕਦਮ ਨਾਲ ਸ਼ੁਰੂ ਕਰਦੀਆਂ ਹਨ: ਮਹੱਤਵਪੂਰਨ ਬਦਲਾਅ ਲਈ ਇੱਕ append-only audit table ਰੱਖੋ, ਕੁਝ high-risk ਵਰਕਫਲੋਜ਼ ਲਈ immutable "ਚੇਂਜ ਇਵੈਂਟ" ਸਟੋਰ ਕਰੋ, ਜਾਂ replay/ਡੀਬੱਗਿੰਗ ਲਈ snapshots ਅਤੇ ਇੱਕ ਛੋਟਾ ਇਤਿਹਾਸ ਵਿੰਡੋ ਰੱਖੋ। ਮੁੱਖ ਗੱਲ ਹੈ ਆਦਤ: ਤੱਥਾਂ ਨੂੰ ਟਿਕਾਊ ਸਮਝੋ, ਅਤੇ ਮੌਜੂਦਾ ਸਟੇਟ ਨੂੰ ਇੱਕ ਆਸਾਨ ਪ੍ਰੋਜੈਕਸ਼ਨ ਮੰਨੋ।
Hickey ਦੀ ਇੱਕ ਸਭ ਤੋਂ ਪ੍ਰਯੋਗਿਕ ਵਿਚਾਰ ਡੇਟਾ ਪਹਿਲਾਂ ਹੈ: ਆਪਣੀ ਸਿਸਟਮ ਦੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਧਾਰਨ ਮੁੱਲ (ਤੱਥ) ਸਮਝੋ, ਅਤੇ ਵਿਹਾਰ ਨੂੰ ਉਹਨਾਂ ਮੁੱਲਾਂ 'ਤੇ ਚਲਾਓ।
ਡੇਟਾ ਟਿਕਾਊ ਹੈ। ਜੇ ਤੁਸੀਂ ਸਾਫ, ਖੁਦ-ਮੁਕੰਮਲ ਜਾਣਕਾਰੀ ਸਟੋਰ ਕਰਦੇ ਹੋ, ਤੁਸੀਂ ਉਸਨੂੰ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਵਰਤ ਸਕਦੇ ਹੋ, ਸਰਵਿਸਾਂ ਵਿਚ ਭੇਜ ਸਕਦੇ ਹੋ, reindex ਕਰ ਸਕਦੇ ਹੋ, audit ਕਰ ਸਕਦੇ ਹੋ, ਜਾਂ ਨਵੀਆਂ ਫੀਚਰਾਂ ਵਾਸਤੇ ਖੁਰਾਕ ਦੇ ਸਕਦੇ ਹੋ। ਵਿਹਾਰ ਘੱਟ ਟਿਕਾਊ ਹੈ—ਕੋਡ ਬਦਲਦਾ ਹੈ, assumptions ਬਦਲਦੀਆਂ ਹਨ, ਡਿਪੈਂਡੇਨਸੀਸ ਬਦਲਦੀਆਂ ਹਨ।
ਜਦ ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ ਮਿਲਾ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਸਿਸਟਮ sticky ਹੋ ਜਾਂਦੇ ਹਨ: ਤੁਸੀਂ ਡੇਟਾ ਨੂੰ reuse ਕਰਨ ਲਈ ਉਸਦੇ ਨਾਲ ਜੁੜੇ ਵਿਹਾਰ ਨੂੰ ਵੀ ਘਸੀਟਕੇ ਲੈ ਕੇ ਜਾਣਾ ਪੈਂਦਾ ਹੈ।
ਤੱਥਾਂ ਨੂੰ ਕਾਰਵਾਈ ਤੋਂ ਵੱਖ ਕਰਨਾ coupling ਘਟਾਉਂਦਾ ਹੈ ਕਿਉਂਕਿ ਕੰਪੋਨੈਂਟ ਇੱਕ ਡੇਟਾ ਆਕਾਰ 'ਤੇ ਸਹਿਮਤ ਹੋ ਸਕਦੇ ਹਨ ਬਿਨਾਂ ਇਕੱਠੇ ਕੋਡਪਾਥ 'ਤੇ ਸਹਿਮਤ ਹੋਏ।
ਇੱਕ ਰਿਪੋਰਟਿੰਗ ਨੌਕਰੀ, ਸਪੋਰਟ ਟੂਲ ਅਤੇ ਬਿਲਿੰਗ ਸਰਵਿਸ ਇੱਕੋ ਆਰਡਰ ਡੇਟਾ ਨੂੰ ਖਪਤ ਕਰ ਸਕਦੇ ਹਨ, ਹਰ ਇੱਕ ਆਪਣਾ ਲਾਜਿਕ ਲਗਾਉਂਦਾ ਹੈ। ਜੇ ਤੁਸੀਂ logic ਨੂੰ ਸਟੋਰ ਕੀਤੇ ਪ੍ਰਤੀਨਿਧੀ ਵਿਚ embed ਕਰਦੇ ਹੋ, ਤਾਂ ਹਰ consumer ਉਸ embedded logic 'ਤੇ ਨਿਰਭਰ ਹੋ ਜਾਂਦਾ ਹੈ—ਅਤੇ ਦੁਬਾਰਾ ਤਬਦੀਲ ਕਰਨਾ ਖਤਰਨਾਕ ਹੋ ਜਾਂਦਾ ਹੈ।
ਸਾਫ ਡੇਟਾ (ਅਸਾਨੀ ਨਾਲ ਵਿਕਸਤ ਕਰਨ ਯੋਗ):
{
"type": "discount",
"code": "WELCOME10",
"percent": 10,
"valid_until": "2026-01-31"
}
ਸਟੋਰੇਜ ਵਿੱਚ ਛੋਟੇ-ਕਾਰਜ (ਵਿਕਸਤ ਕਰਨ ਲਈ ਔਖਾ):
{
"type": "discount",
"rule": "if (customer.orders == 0) return total * 0.9; else return total;"
}
ਦੂਜੀ ਵਰਜਨ ਲਚਕੀਲਾਪੂਰਕ ਲੱਗਦੀ ਹੈ, ਪਰ ਇਹ complexity ਨੂੰ ਡੇਟਾ ਲੇਅਰ ਵਿੱਚ ਧੱਕ ਦਿੰਦੀ: ਹੁਣ ਤੁਹਾਨੂੰ ਇੱਕ ਸੁਰੱਖਿਅਤ evaluator, ਵਰਜਨਿੰਗ ਨਿਯਮ, ਸੁਰੱਖਿਆ ਸਰਹੱਦਾਂ, ਡੀਬੱਗਿੰਗ ਟੂਲ, ਅਤੇ ਜਦ rule ਭਾਸ਼ਾ ਬਦਲੇ ਤਾਂ migration ਯੋਜਨਾ ਦੀ ਲੋੜ ਹੋਵੇਗੀ।
ਜਦ ਤੁਸੀਂ ਸਟୋਰ ਕੀਤੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਧਾਰਨ ਅਤੇ ਸਪਸ਼ਟ ਰੱਖਦੇ ਹੋ, ਤੁਸੀਂ ਸਮੇਂ ਦੇ ਨਾਲ ਵਿਹਾਰ ਬਦਲ ਸਕਦੇ ਹੋ ਬਿਨਾਂ ਇਤਿਹਾਸ ਨੂੰ ਦੁਬਾਰਾ ਲਿਖੇ। ਪੁਰਾਣੇ ਰਿਕਾਰਡ ਪੜ੍ਹਨ ਯੋਗ ਰਹਿੰਦੇ ਹਨ। ਨਵੇਂ ਸਰਵਿਸਿਜ਼ ਇੱਕੋ ਡੇਟਾ ਆਕਾਰ ਨੂੰ ਬਿਨਾਂ legacy execution rules ਸਮਝਣ ਦੇ ਵਰਤ ਸਕਦੇ ਹਨ। ਅਤੇ ਤੁਸੀਂ ਨਵੇਂ تفسيرਾਂ—ਨਵੀਆਂ UI ਵਿਉਜ਼, ਨਵੀਆਂ ਪ੍ਰਾਈਸਿੰਗ ਰਣਨੀਤੀਆਂ, ਨਵੀਆਂ ਐਨਾਲਿਟਿਕਸ—ਨਵਾਂ ਕੋਡ ਲਿਖ ਕੇ ਲਿਆ ਸਕਦੇ ਹੋ, ਡੇਟਾ ਦੇ ਅਰਥ ਨੂੰ mutate ਕਰਕੇ ਨਹੀਂ।
ਜ਼ਿਆਦਾਤਰ ਏੰਟਰਪ੍ਰਾਈਜ਼ ਸਿਸਟਮ ਇਸ ਲਈ fail ਨਹੀਂ ਹੁੰਦੇ ਕਿ ਕੋਈ ਇੱਕ ਮਾਡਿਊਲ "ਖਰਾਬ" ਹੈ। ਉਹ ਇਸ ਲਈ fail ਹੁੰਦੇ ਹਨ ਕਿ ਹਰ ਚੀਜ਼ ਹਰ ਚੀਜ਼ ਨਾਲ जुੜੀ ਹੋਈ ਹੈ।
ਟਾਈਟ coupling ਨਿੱਘੀ ਸੋਧਾਂ ਦੀ ਵਜ੍ਹਾ ਬਣਦਾ ਹੈ ਜੋ ਹਫ਼ਤਿਆਂ ਦੀ retesting ਟਰਿੱਗਰ ਕਰਦੀਆਂ ਹਨ। ਇੱਕ ਫੀਲਡ ਜੋ ਇੱਕ ਸਰਵਿਸ ਵਿੱਚ ਜੋੜੀ ਜਾਂਦੀ ਹੈ, ਤਿੰਨ downstream consumers ਨੂੰ ਤੋੜ ਸਕਦੀ ਹੈ। ਇੱਕ ਸਾਂਝਾ ਡੇਟਾਬੇਸ ਸਕੀਮਾ ਕੋਆਰਡੀਨੇਸ਼ਨ ਬੋਤਲਨੈਕ ਬਣ ਜਾਂਦਾ ਹੈ। ਇੱਕ ਇੱਕਲਾ mutable cache ਜਾਂ singleton "config" ਆਬਜੈਕਟ ਚੁਪਚਾਪ ਅੱਧੇ ਕੋਡਬੇਸ ਦਾ ਨਿਰਭਰ ਬਣ ਜਾਂਦਾ ਹੈ।
cascading change ਕੁਦਰਤੀ ਨਤੀਜਾ ਹੈ: ਜਦ ਬਹੁਤ ਸਾਰੇ ਹਿੱਸੇ ਇੱਕੋ ਬਦਲਦੇ ਚੀਜ਼ ਨੂੰ ਸਾਂਝਾ ਕਰਦੇ ਹਨ, ਤਦ blast radius ਵੱਡਾ ਹੁੰਦਾ ਹੈ। ਟੀਮਾਂ ਵਧੇਰੇ ਪ੍ਰਕਿਰਿਆ, ਵਧੇਰੇ ਨਿਯਮ, ਅਤੇ ਵਧੇਰੇ ਹਥਾਫ਼ੜੀ ਜੋੜ ਕੇ ਜਵਾਬ ਦਿੰਦੇ ਹਨ—ਅਕਸਰ delivery ਨੂੰ ਹੋਰ ਧੀਮਾ ਕਰਦੀਆਂ।
ਤੁਸੀੰ Hickey ਦੇ ਵਿਚਾਰ ਬਿਨਾਂ ਭਾਸ਼ਾ ਬਦਲੇ ਜਾਂ ਸਾਰੀ ਸਿਸਟਮ ਰੀ-ਰਾਈਟ ਕੀਤੇ ਲਾਗੂ ਕਰ ਸਕਦੇ ਹੋ:
ਜਦ ਡੇਟਾ ਤੁਹਾਡੇ ਪੈਰਾਂ ਹੇਠਾਂ ਨਹੀਂ ਬਦਲਦਾ, ਤੁਸੀਂ "ਇਸ ਸਟੇਟ ਵਿੱਚ ਕਿਵੇਂ ਆਇਆ" ਦੀ ਡੀਬੱਗਿੰਗ ਵਿੱਚ ਘੱਟ ਸਮਾਂ ਲਗਾਉਂਦੇ ਹੋ ਅਤੇ ਵੱਧ ਸਮਾਂ ਕੋਡ ਦੇ ਕੀ ਕਰਦਾ ਹੈ ਨੂੰ ਸੋਚਣ ਵਿੱਚ ਲਗਾਉਂਦੇ ਹੋ।
ਡਿਫਾਲਟਸ ਥੀਕ ਥਾਂ ਤੇ ਅਸਮਾਨਤਾ ਦਾਖਲ ਕਰਾਉਂਦੀਆਂ ਹਨ: ਹਰ ਟੀਮ ਆਪਣਾ timestamp ਫਾਰਮੈਟ, error shape, retry policy, ਅਤੇ concurrency approach ਬਣਾਉਂਦੀ ਹੈ।
ਵਧੀਆ ਡਿਫਾਲਟ ਐਸੇ ਹੋ ਸਕਦੇ ਹਨ: ਵਰਜਨ ਕੀਤਾ ਹੋਇਆ event schema, standard immutable DTOs, ਲਿਖਣ ਦੀ ਸਪੱਸ਼ਟ ਮਲਕੀਅਤ, ਅਤੇ serialization/validation/tracing ਲਈ ਇਕ ਛੋਟੀ ਜਿਹੀ ਮਨਜ਼ੂਰ ਕੀਤੀ ਲਾਇਬ੍ਰੇਰੀ ਸੈਟ। ਨਤੀਜਾ ਘੱਟ surprise integrations ਅਤੇ ਘੱਟ one-off fixes ਹੁੰਦਾ ਹੈ।
ਇਸ ਤਰੀਕੇ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ ਜਿੱਥੇ ਬਦਲਾਅ ਪਹਿਲਾਂ ਹੀ ਹੋ ਰਿਹਾ ਹੈ:
ਇਹ ਤਰੀਕਾ ਭਰੋਸੇਯੋਗਤਾ ਅਤੇ ਟੀਮ ਕੋਆਰਡੀਨੇਸ਼ਨ ਵਿੱਚ ਸੁਧਾਰ ਲਿਆਉਂਦਾ ਹੈ, ਸਿਸਟਮ ਨੂੰ ਚਲਦਾ ਰੱਖਦਿਆਂ ਅਤੇ ਸਕੋਪ ਇਤਨਾ ਛੋਟਾ ਰੱਖਦਿਆਂ ਕਿ ਕੰਮ ਮੁਕੰਮਲ ਕੀਤਾ ਜਾ ਸਕੇ।
ਜਦੋਂ ਤੁਹਾਡਾ ਵਰਕਫਲੋ ਤੇਜ਼, ਘੱਟ-ਖਤਰਾ iteration ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ, ਤਾਂ ਇਹ ਵਿਚਾਰ ਲਾਗੂ ਕਰਨਾ ਆਸਾਨ ਹੁੰਦਾ ਹੈ। ਉਦਾਹਰਨ ਵਜੋਂ, ਜੇ ਤੁਸੀਂ ਨਵੀਆਂ ਫੀਚਰਾਂ Koder.ai (ਇੱਕ chat-based vibe-coding ਪਲੇਟਫਾਰਮ ਵੈਬ, ਬੈਕਐਂਡ, ਅਤੇ ਮੋਬਾਈਲ ਐਪਸ ਲਈ) ਵਿੱਚ ਬਣਾ ਰਹੇ ਹੋ, ਤਾਂ ਦੋ ਫੀਚਰ ਸਿੱਧੇ "ਵਧੀਆ ਡਿਫਾਲਟ" ਮਾਈਂਡਸੈੱਟ ਨਾਲ ਮੇਲ ਖਾਂਦੇ ਹਨ:
ਭਾਵੇਂ ਤੁਹਾਡਾ ਸਟੈਕ React + Go + PostgreSQL (ਜਾਂ Flutter) ਹੋਵੇ, ਮੂਲ ਗੱਲ ਇਹੀ ਰਹਿੰਦੀ ਹੈ: ਜੋ ਟੂਲ ਤੁਸੀਂ ਹਰ ਰੋਜ਼ ਵਰਤਦੇ ਹੋ ਉਹ ਚੁਪਚਾਪ ਇੱਕ ਡਿਫਾਲਟ ਤਰੀਕਾ ਸਿਖਾਉਂਦੇ ਹਨ। ਉਹ ਟੂਲ ਚੁਣੋ ਜੋ traceability, rollback, ਅਤੇ explicit planning ਨੂੰ ਰੋਜ਼ਾਨਾ ਦੀਆ ਰੁਟੀਨਾਂ ਬਣਾਉਂਦੇ ਹਨ—ਇਸ ਨਾਲ ਓਹ ਮੁਕਾਬਲਾ "ਸਿਰਫ਼ patch" ਕਰਨ ਦੀ ਦਬਾਅ ਘਟ ਜਾਂਦੀ ਹੈ।
ਸਰਲਤਾ ਅਤੇ ਅਪਰਿਵਰਤਨੀਯਤਾ ਪ੍ਰਭਾਵਸ਼ਾਲੀ ਡਿਫਾਲਟ ਹਨ, ਪਰ ਇਹ ਨੈਤਿਕ ਨਿਯਮ ਨਹੀਂ। ਇਹ ਉਹਨਾਂ ਚੀਜ਼ਾਂ ਦੀ ਗਿਣਤੀ ਘਟਾਉਂਦੇ ਹਨ ਜੋ ਅਣ-ਉਮੀਦਿਤ ਤੌਰ 'ਤੇ ਬਦਲ ਸਕਦੀਆਂ ਹਨ, ਜੋ ਸਿਸਟਮ ਵਧਣ 'ਤੇ ਮਦਦਗਾਰ ਹੁੰਦਾ ਹੈ। ਪਰ ਅਸਲੀ ਪ੍ਰਾਜੈਕਟਾਂ ਦੇ ਆਪਣੇ ਬਜਟ, ਡੈਡਲਾਈਨ ਅਤੇ ਸੀਮਾਵਾਂ ਹੁੰਦੀਆਂ ਹਨ—ਅਤੇ ਕਈ ਵਾਰ mutability ਸਹੀ ਚੋਣ ਹੁੰਦੀ ਹੈ।
mutability ਪ੍ਰਦਰਸ਼ਨ-ਹੋਟਸਪਾਟਾਂ ਵਿੱਚ (tight loops, high-throughput parsing, graphics, numeric work) ਇੱਕ ਵਿਅਵਹਾਰਿਕ ਚੋਣ ਹੋ ਸਕਦੀ ਹੈ ਜਿੱਥੇ allocations ਮਹੱਤਵਪੂਰਨ ਹਨ। ਇਹ ਠੀਕ ਹੋ ਸਕਦਾ ਹੈ ਜਦ ਵਿਕਾਸ ਦੀ ਸੀਮਾ ਨਿਯੰਤਰਿਤ ਹੋਵੇ: ਇੱਕ ਫੰਕਸ਼ਨ ਦੇ ਅੰਦਰ ਲੋਕਲ ਵੇਰੀਏਬਲ, ਇੱਕ ਪ੍ਰਾਈਵੇਟ cache ਜੋ ਇੱਕ ਇੰਟਰਫੇਸ ਦੇ ਪਿੱਛੇ ਲੁਕਿਆ ਹੋਇਆ ਹੈ, ਜਾਂ ਇੱਕ single-threaded component ਜਿਸ ਦੀਆਂ ਸੀਮਾਵਾਂ ਸਪਸ਼ਟ ਹਨ।
ਮੁੱਖ ਗੱਲ containment ਹੈ। ਜੇ "mutable ਚੀਜ਼" ਕਦੇ ਲੀਕ ਨਹੀਂ ਹੁੰਦੀ, ਤਾਂ ਇਹ complexity ਨੂੰ ਪੂਰੇ ਕੋਡਬੇਸ 'ਚ ਫੈਲਾਉਣ ਨਹੀਂ ਪਾ ਸਕਦੀ।
ਇੱਕ ਜ਼ਿਆਦਾਤਰ functional ਅੰਦਾਜ਼ ਵਿੱਚ ਵੀ, ਟੀਮਾਂ ਨੂੰ ਸਪਸ਼ਟ ਮਲਕੀਅਤ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ:
ਇਹ ਥਾਂ Clojure ਦਾ ਡੇਟਾ-ਪੱਖੀ bias ਮਦਦਗਾਰ ਹੈ, ਪਰ ਇਹ ਅਨੁਸ਼ਾਸਨ ਆਰਕੀਟੈਕਚਰਲ ਹੈ, ਭਾਸ਼ਾ-ਨਿਰਪੇਕ ਨਹੀਂ।
ਕੋਈ ਭਾਸ਼ਾ ਖਰਾਬ requirements, ਅਨਸਪਸ਼ਟ domain model, ਜਾਂ ਇੱਕ ਟੀਮ ਜੋ "done" ਦਾ ਅਰਥ ਨਹੀਂ ਸਮਝਦੀ, ਨਹੀਂ ਠੀਕ ਕਰ ਸਕਦੀ। ਅਪਰਿਵਰਤਨੀਯਤਾ ਇੱਕ ਅਸਪਸ਼ਟ workflow ਨੂੰ ਸਮਝਦਾਰ ਨਹੀਂ ਬਣਾਏਗੀ, ਅਤੇ "ਫੰਕਸ਼ਨਲ" ਕੋਡ ਵੀ ਗਲਤ ਬਿਜ਼ਨੇਸ ਨਿਯਮ encode ਕਰ ਸਕਦਾ ਹੈ—ਸਿਰਫ਼ ਵਿਚਾਰਧਾਰਾ ਵਿੱਚ ਵੱਧ ਸਾਜ਼-ਸੰਜਮ ਨਾਲ।
ਜੇ ਤੁਹਾਡੀ ਸਿਸਟਮ ਪਹਿਲਾਂ ਹੀ ਪ੍ਰੋਡਕਸ਼ਨ ਵਿਚ ਹੈ, ਤਾਂ ਇਨ੍ਹਾਂ ਵਿਚਾਰਾਂ ਨੂੰ ਇੱਕ ਸਫੈਦ-ਕਾਲੇ ਰੀ-ਰਾਈਟ ਵਜੋਂ ਵੇਖੋ ਨਾ ਕਰੋ। ਸਭ ਤੋਂ ਛੋਟਾ ਬਦਲਾਅ ਲੱਭੋ ਜੋ ਜੋਖਮ ਘਟਾਏ:
ਮਕਸਦ ਪਵਿੱਤਰਤਾ ਨਹੀਂ—ਬਲਕਿ ਹਰ ਬਦਲਾਅ ਤੇ ਘੱਟ ਅਣਪੇਛਾਣੀਆਂ ਹਨ।
ਇਹ ਇੱਕ ਸਪ੍ਰਿੰਟ-ਸਾਈਜ਼ ਚੈਕਲਿਸਟ ਹੈ ਜੋ ਤੁਸੀਂ ਭਾਸ਼ਾਵਾਂ, ਫਰੇਮਵਰਕ, ਜਾਂ ਟੀਮ ਸੰਰਚਨਾ ਬਦਲੇ ਬਿਨਾਂ ਲਾਗੂ ਕਰ ਸਕਦੇ ਹੋ।
ਸਰਲਤਾ ਬਨਾਮ ਆਸਾਨ, ਸਟੇਟ ਦਾ ਪ੍ਰਬੰਧ, value-oriented ਡਿਜ਼ਾਈਨ, ਅਪਰਿਵਰਤਨੀਯਤਾ, ਅਤੇ ਕਿਵੇਂ "ਇਤਿਹਾਸ" (ਸਮਾਂ 'ਤੇ ਤੱਥ) ਡੀਬੱਗਿੰਗ ਅਤੇ operations ਵਿੱਚ ਮਦਦ ਕਰਦਾ ਹੈ।
ਸਰਲਤਾ ਉਹ ਫੀਚਰ ਨਹੀਂ ਜੋ ਤੁਸੀਂ ਸਿਰਫ ਜੋੜ ਦਿੰਦੇ ਹੋ—ਇਹ ਇੱਕ ਰਣਨੀਤੀ ਹੈ ਜੋ ਤੁਸੀਂ ਛੋਟੇ, ਦੁਹਰਾਏ ਜਾ ਸਕਣ ਵਾਲੇ ਫੈਸਲਿਆਂ ਵਿੱਚ ਅਭਿਆਸ ਕਰਦੇ ਹੋ।
ਜਟਿਲਤਾ ਛੋਟੇ, ਲੋਕਲ ਤੌਰ 'ਤੇ ਤਰਕਯੋਗ ਫੈਸਲਿਆਂ ਰਾਹੀਂ ਇਕੱਠੀ ਹੁੰਦੀ ਹੈ (ਵਧੂ ਫਲੈਗ, caches, ਛੋਟੇ ਵਿਸ਼ੇਸ਼-ਕੇਸ, ਸਾਂਝੇ ਹੇਲਪਰ)।
ਇੱਕ ਚੰਗਾ ਇਸ਼ਾਰਾ ਉਹ ਹੈ ਜਦੋਂ ਇੱਕ “ਛੋਟੇ ਬਦਲਾਅ” ਲਈ ਕਈ ਮਾਡਿਊਲਾਂ ਜਾਂ ਸਰਵਿਸਾਂ ਵਿੱਚ ਸਹਿਯੋਗੀ ਸੋਧਾਂ ਦੀ ਲੋੜ ਪੈਂਦੀ ਹੈ, ਜਾਂ ਜਦੋਂ ਸਮੀਖਿਆਕਾਰ ਸੁਰੱਖਿਆ ਦਾ ਮੂਲ ਨਿਰਣਾ ਕਰਨ ਲਈ tribal knowledge 'ਤੇ ਨਿਰਭਰ ਰਹਿੰਦੇ ਹਨ।
ਕਿਉਂਕਿ ਛੋਟੇ ਰਸਤੇ ਅੱਜ ਦੀ ਰੁਕਾਵਟ ਤੇ ਧਿਆਨ ਦੇਂਦੇ ਹਨ (ship ਕਰਨ ਦਾ ਸਮਾਂ ਘਟਾਉਂਦੇ ਹਨ) ਪਰ ਲੰਬੇ ਸਮੇਂ ਦੇ ਖਰਚੇ ਵਧਾਉਂਦੇ ਹਨ: ਡੀਬੱਗਿੰਗ ਸਮਾਂ, ਸਹਯੋਗ ਦਾ ਓਵਰਹੈੱਡ, ਅਤੇ ਬਦਲਾਅ ਦਾ ਜੋਖਮ।
ਇੱਕ ਉਪਯੋਗੀ ਆਦਤ ਡਿਜ਼ਾਈਨ/PR ਸਮੀਖਿਆ ਵਿੱਚ ਇਹ ਪੁੱਛਣਾ ਹੈ: “ਇਸ ਨਾਲ ਕਿਹੜੇ ਨਵੇਂ moving parts ਜਾਂ ਖਾਸ ਕੇਸ ਆਉਂਦੇ ਹਨ, ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਕੌਣ ਰੱਖ ਰੱਖਾਵੇਗਾ?”
ਡਿਫਾਲਟਸ ਉਸ ਤਰੀਕੇ ਨੂੰ ਆਕਾਰ ਦਿੰਦੇ ਹਨ ਜੋ ਇੰਜੀਨੀਅਰ ਪ੍ਰੈਸ਼ਰ ਹੇਠ ਲਿਖਦੇ ਹਨ। ਜੇ mutation ਡਿਫਾਲਟ ਹੈ, ਤਾਂ ਸਾਂਝਾ ਸਟੇਟ ਫੈਲ ਜਾਵੇਗਾ। ਜੇ in-memory is fine ਡਿਫਾਲਟ ਹੈ, ਤਾਂ traceability ਲੁਕ ਜਾਏਗੀ।
ਡਿਫਾਲਟਸ ਨੂੰ ਸੁਧਾਰੋ ਤਾਂ ਜੋ ਸੁਰੱਖਿਅਤ ਰਸਤਾ ਸਭ ਤੋਂ ਘੱਟ ਰੋੜੀਲੀ ਬਣ ਜਾਵੇ: ਬਾਊਂਡਰੀਜ਼ 'ਤੇ ਅਪਰਿਵਰਤਨੀਯ ਡੇਟਾ, ਸਮੇਂ-ਜ਼ੋਨ/nullable/ਰੀਟ੍ਰਾਈਜ਼ ਦੀ ਸਪਸ਼ਟ ਹੈਂਡਲਿੰਗ, ਅਤੇ ਸਪਸ਼ਟ ਸਟੇਟ ਮਲਕੀਅਤ।
ਸਟੇਟ ਉਹ ਸਭ ਕੁਝ ਹੈ ਜੋ ਤੁਸੀਂ ਆਪਣੀ ਸਿਸਟਮ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ: ਸ਼ੌਪਿੰਗ ਕਾਰਟ, ਖਾਤਾ ਬੈਲੈਂਸ, ਸੰਰਚਨਾ, ਵਰਕਫਲੋ ਕਦਮ। ਮੁਸ਼ਕਲ ਗੱਲ ਇਹ ਨਹੀਂ ਕਿ ਬਦਲਾਅ ਹੈ, ਪਰ ਇਹ ਹੈ ਕਿ ਹਰ ਬਦਲਾਅ ਇਕ ਨਵਾਂ ਮੌਕਾ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਚੀਜ਼ਾਂ ਅਸਮਝਦਾਰ ਹੋ ਸਕਦੀਆਂ ਹਨ।
ਦੋ ਕੰਪੋਨੈਂਟ ਵੱਖ-ਵੱਖ “ਮੌਜੂਦਾ” ਮੁੱਲ ਰੱਖ ਸਕਦੇ ਹਨ ਅਤੇ ਤਦੋਂ ਬੱਗ timing-dependent ਵਰਗੇ ਲੱਗਦੇ ਹਨ।
ਅਪਰਿਵਰਤਨੀਯਤਾ ਦਾ ਸਧਾਰਣ ਅਰਥ ਹੈ: ਇੱਕ ਵਾਰ ਬਣੀ ਡੇਟਾ ਬਦਲਦੀ ਨਹੀਂ।
ਅਮਲ ਵਿੱਚ, ਇਹ ਇਸ ਲਈ ਫਾਇਦੇਮੰਦ ਹੈ:
ਮੁਟੇਬਿਲਟੀ ਨੂੰ ਉਹਨਾਂ ਸਥਿਤੀਆਂ ਵਿੱਚ ਠੀਕ ਮੰਨਿਆ ਜਾ ਸਕਦਾ ਹੈ ਜਿੱਥੇ ਇਹ ਕੱਚੀ ਤਰ੍ਹਾਂ 'contained' ਹੋਵੇ:
ਮੁੱਖ ਨਿਯਮ: mutable ਸਰਚਨਾਂ ਨੂੰ ਬਾਊਂਡਰੀਜ਼ ਤੋਂ ਬਾਹਰ ਨੀਕਲਣ ਨਾ ਦੇਵੋ।
ਰੇਸ ਕਾਂਡੀਸ਼ਨ ਆਮ ਤੌਰ 'ਤੇ ਸਾਂਝੇ, ਮੁਟੇਬਲ ਡੇਟਾ ਦੇ ਪੜ੍ਹਨ ਅਤੇ ਫਿਰ ਲਿਖਣ ਨਾਲ ਹੁੰਦੇ ਹਨ।
ਅਪਰਿਵਰਤਨੀਯਤਾ coordination ਦੀ ਜ਼ਰੂਰਤ ਘਟਾ ਦਿੰਦੀ ਹੈ ਕਿਉਂਕਿ ਲੇਖਕ ਨਵੀਆਂ ਵਰਜਨਾਂ ਬਣਾਉਂਦੇ ਹਨ ਬਜਾਏ ਕਿ ਸਾਂਝੀ ਚੀਜ਼ ਨੂੰ ਸੋਧਣ ਦੇ। ਤੁਸੀਂ ਫਿਰ ਵੀ ਇਹ ਫੈਸਲਾ ਕਰਨਾ ਪਵੇਗਾ ਕਿ ਕਿਹੜੀ ਵਰਜਨ ਨੂੰ current ਘੋਸ਼ਿਤ ਕਰਨਾ ਹੈ, ਪਰ ਡੇਟਾ ਸਵਭਾਵਕ ਤੌਰ 'ਤੇ ਹਿਲਣ-ਡੁੱਲਣ ਵਾਲਾ ਨਹੀਂ ਰਹਿੰਦਾ।
ਫੈਕਟ ਇੱਕ ਅਪੈਂਡ-ਓਨਲੀ ਰਿਕਾਰਡ ਹੁੰਦੇ ਹਨ: “Order #4821 10:14 'ਤੇ ਰਖਿਆ ਗਿਆ”, “Payment ਸਫਲ ਹੋਈ”, “Address ਬਦਲੀ ਗਈ” — ਇਨ੍ਹਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾਂਦਾ; ਨਵੀਆਂ ਫੈਕਟਾਂ ਜੋੜੀਆਂ ਜਾਂਦੀਆਂ ਹਨ।
ਵਿਊ ਇੱਕ ਪ੍ਰਸਥਿਤੀ ਹੈ ਜੋ ਫੈਕਟਾਂ ਤੋਂ ਨਿਕਾਲੀ ਜਾਂਦੀ ਹੈ: “ਹੁਣ ਕਿਹੜਾ shipping address ਹੈ?” ਜਾਂ “ਗਾਹਕ ਦਾ ਮੌਜੂਦਾ ਬੈਲੈਂਸ?”।
ਹਿਸਟਰੀ ਰਖਣ ਨਾਲ ਤੁਹਾਨੂੰ auditability, debugging ਅਤੇ traceability ਮਿਲਦੀ ਹੈ—ਕਿਹੜੇ ਬਦਲਾਅ ਨੇ ਮੌਜੂਦਾ ਮੁੱਲ ਬਣਾਇਆ, ਇਹ ਪੁੱਛਣਾ ਡੇਟਾ ਪ੍ਰਸ਼ਨ ਬਣ ਜਾਂਦਾ ਹੈ।
ਡੇਟਾ-ਫਰਸਟ ਦਾ ਮਤਲਬ ਹੈ: ਸਿਸਟਮ ਦੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਾਫ਼, ਦੂਸਰੇ ਵਰਤੋਂ ਲਈ ਯੋਗ ਕੀਮਤਾਂ ਵਜੋਂ ਸਟੋਰ ਕਰੋ, ਅਤੇ ਵਿਹਾਰ ਕਦੇ ਵੀ ਉਹਨਾਂ 'ਤੇ ਚਲਾਇਆ ਜਾਵੇ। ਵਿਹਾਰ ਘੱਟ ਮਿਆਦੀ ਹੁੰਦਾ ਹੈ—ਕੋਡ, assumptions ਅਤੇ ਡਿਪੈਂਡੇਨਸੀਸ ਬਦਲਦੀਆਂ ਰਹਿ ਸਕਦੀਆਂ ਹਨ।
ਇਸ ਨਾਲ coupling ਘਟਦਾ ਹੈ ਕਿਉਂਕਿ consumers ਇੱਕ ਸਾਫ ਡੇਟਾ ਆਕਾਰ 'ਤੇ ਸਹਿਮਤ ਹੋ ਸਕਦੇ ਹਨ ਬਿਨਾਂ ਇੱਕੋ ਹੀ ਕੋਡਪਾਥ ਦੀ ਲੋੜ ਦੇ।
ਟਾਈਟ coupling ਨਿੱਕੇ ਬਦਲਾਵਾਂ ਨੂੰ ਹਫ਼ਤਿਆਂ ਦੀ re-testing 'ਚ ਤਬਦੀਲ ਕਰ ਦੇਂਦਾ ਹੈ। ਇੱਕ ਫੀਲਡ ਜੋ ਇੱਕ ਸਰਵਿਸ ਵਿੱਚ ਜੋੜੀ ਜਾਂਦੀ ਹੈ, ਤਿੰਨੇ downstream consumers ਨੂੰ ਤੋੜ ਸਕਦੀ ਹੈ।
blast radius ਘਟਾਉਣ ਲਈ ਸਧਾਰਨ ਬਾਊਂਡਰੀਜ਼ ਰੱਖੋ:
ਟੂਲਿੰਗ ਅਤੇ ਪਲੇਟਫਾਰਮ ਜਦੋਂ ਤੁਹਾਡੇ ਵਰਕਫਲੋ ਨੂੰ ਤੇਜ਼, ਘੱਟ-ਖਤਰਾ iteration ਦੇਣ, ਤਾਂ ਇਹ ਵਿਚਾਰ ਲਾਗੂ ਕਰਨਾ ਆਸਾਨ ਹੁੰਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ Koder.ai ਵਰਗੇ ਪਲੇਟਫਾਰਮ ਵਿੱਚ:
ਭਾਵੇਂ ਤੁਸੀਂ React + Go + PostgreSQL (ਜਾਂ Flutter) ਵਰਤੇ ਹੋ, ਅਹਮ ਗੱਲ ਇਹ ਹੈ ਕਿ ਰੋਜ਼ਾਨਾ ਵਾਲੇ ਟੂਲਜ਼ ਇੱਕ ਡਿਫਾਲਟ ਕੰਮ ਕਰਨ ਦਾ ਤਰੀਕਾ ਸਿਖਾਉਂਦੇ ਹਨ।
ਸਰਲਤਾ ਅਤੇ ਅਪਰਿਵਰਤਨੀਯਤਾ ਸ਼ਕਤਿਸ਼ਾਲੀ ਡਿਫਾਲਟ ਹਨ, ਪਰ ਇਹ ਧਾਰਮਿਕ ਨਿਯਮ ਨਹੀਂ। ਹਕੀਕੀ ਪ੍ਰਾਜੈਕਟਾਂ ਦੇ ਬਜਟ, ਡੈਡਲਾਈਨ ਅਤੇ ਰੋਕ-ਟੋਕ ਹੁੰਦੀ ਹੈ—ਕਦੇ-ਕਦੇ ਮੁਟੇਬਿਲਟੀ ਠੀਕ ਚੋ이스 ਹੁੰਦੀ ਹੈ।
ਮੰਜ਼ੂਰ ਕਰਨ ਵਾਲੀ ਚੀਜ਼ ਇਹ ਹੈ ਕਿ ਇਹ ਹਲਕੇ-ਫੁਲਕੇ ਤਰੀਕੇ ਹਨ: ਛੋਟੇ, ਘੁਮਾਓਯੋਗ ਬਦਲਾਅ ਜੋ ਜੋਖਮ ਘਟਾਉਣ।
ਛੋਟੇ ਕਦਮ ਲਵੋ: ਸਾਂਝੇ mutable structures ਨੂੰ immutable ਡੇਟਾ ਨਾਲ ਬਦਲੋ, ਅਤੇ ਜ਼ਰੂਰੀ ਹੋਣ 'ਤੇ ਹੀ event logs ਸ਼ੁਰੂ ਕਰੋ।
ਇਹ ਇਕ ਸਪ੍ਰਿੰਟ-ਸਾਇਜ਼ ਚੈਕਲਿਸਟ ਹੈ ਜੋ ਤੁਸੀਂ ਭਾਸ਼ਾਵਾਂ, ਫਰੇਮਵਰਕ ਜਾਂ ਟੀਮ ਸਟ੍ਰਕਚਰ ਬਦਲੇ ਬਿਨਾਂ ਲਾਗੂ ਕਰ ਸਕਦੇ ਹੋ।
ਮਾਪੋ ਸਫਲਤਾ ਨੂੰ: ਘੱਟ flaky bugs, ਹਰ ਬਦਲਾਅ ਦਾ ਛੋਟਾ blast radius, ਤੇ ਰਿਲੀਜ਼ਜ਼ ਵਿੱਚ ਘੱਟ “ਸਾਹਮਣੇ-ਸਹਿਯੋਗ” ਦੀ ਲੋੜ।