ต่อต้านรูปแบบที่คุณควรหลีกเลี่ยงในจรรยาบรรณของคุณ

นักพัฒนาทุกคนต้องการเขียนโค้ดที่มีโครงสร้างวางแผนอย่างง่ายและแสดงความคิดเห็นเป็นอย่างดี มีแม้แต่รูปแบบการออกแบบมากมายที่ทำให้เราปฏิบัติตามกฎที่ชัดเจนและเป็นกรอบที่ควรคำนึงถึง

แต่เรายังสามารถพบรูปแบบการต่อต้านในซอฟต์แวร์ที่เขียนไปบ้างหรือเขียนเร็วเกินไป

การแฮ็กขั้นพื้นฐานที่ไม่เป็นอันตรายเพื่อแก้ไขปัญหาอย่างรวดเร็วสามารถตั้งค่าแบบอย่างใน codebase ของคุณได้ สามารถคัดลอกได้ในหลาย ๆ ที่และเปลี่ยนเป็นรูปแบบการต่อต้านที่คุณต้องการแก้ไข

รูปแบบการต่อต้านคืออะไร?

ในซอฟต์แวร์การต่อต้านรูปแบบเป็นคำที่อธิบายถึงวิธีไม่แก้ปัญหาที่เกิดซ้ำในโค้ดของคุณ รูปแบบการต่อต้านถือเป็นการออกแบบซอฟต์แวร์ที่ไม่ดีและมักจะไม่มีประสิทธิภาพหรือการแก้ไขที่คลุมเครือ  

พวกเขาโดยทั่วไปยังเพิ่ม "หนี้ทางเทคนิค" - ซึ่งเป็นรหัสที่คุณต้องกลับมาและแก้ไขปัญหาได้อย่างถูกต้องในภายหลัง

หกต่อต้านรูปแบบ-ผมจะหารือในบทความนี้เป็นปาเก็ตตี้รหัส , โกลเด้นค้อน , เรือ Anchor , รหัส Dead , แพร่ขยายของรหัสและวัตถุพระเจ้า

รหัสสปาเก็ตตี้

Spaghetti Codeเป็นรูปแบบการต่อต้านที่รู้จักกันดีที่สุด เป็นรหัสที่มีโครงสร้างน้อยถึงศูนย์

ไม่มีอะไรเป็นโมดูลาร์ มีไฟล์สุ่มเกลื่อนในไดเรกทอรีแบบสุ่ม การไหลทั้งหมดเป็นเรื่องยากที่จะติดตามและพันกันอย่างเต็มที่ (เช่นสปาเก็ตตี้)

โดยปกติปัญหานี้เป็นปัญหาที่ใครบางคนไม่ได้ไตร่ตรองขั้นตอนการทำงานของโปรแกรมมาก่อนและเพิ่งเริ่มเขียนโค้ด

มันทำอะไร?! ฉันทำตามนี้ไม่ได้

image.png

นี่ไม่ใช่แค่ฝันร้ายในการซ่อมบำรุงเท่านั้น แต่ยังทำให้ไม่สามารถเพิ่มฟังก์ชันใหม่ ๆ ได้อีก

คุณจะทำลายสิ่งต่างๆอยู่ตลอดเวลาไม่เข้าใจขอบเขตของการเปลี่ยนแปลงของคุณหรือให้ค่าประมาณที่ถูกต้องสำหรับงานของคุณเนื่องจากเป็นไปไม่ได้ที่จะคาดการณ์ปัญหามากมายที่เกิดขึ้นเมื่อทำโบราณคดี / การคาดเดาดังกล่าว

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการต่อต้านรูปแบบSpaghetti Codeได้ที่นี่

ค้อนทองคำ

"ฉันคิดว่ามันน่าดึงดูดถ้าเครื่องมือเดียวที่คุณมีคือค้อนเพื่อรักษาทุกอย่างราวกับว่ามันเป็นตะปู" อับราฮัมมาสโลว์

ลองนึกภาพสถานการณ์กับฉัน: ทีมนักพัฒนาของคุณมีความสามารถมากในสถาปัตยกรรม Hammer แบบใหม่ล่าสุด มันทำงานได้อย่างยอดเยี่ยมสำหรับชุดปัญหาที่ผ่านมาทั้งหมดของคุณ คุณคือทีมสถาปัตยกรรม Hammer ชั้นนำของโลก

แต่ตอนนี้ทุกอย่างมักจะจบลงด้วยการใช้สถาปัตยกรรมนี้ สกรูหัวแบน? ค้อน. สกรูหัวแฉก? ค้อน. คุณต้องการประแจอัลเลนหรือไม่? ไม่ต้องใช้ค้อนทุบ

คุณเริ่มใช้แนวทางสถาปัตยกรรมที่ไม่ค่อยเหมาะกับสิ่งที่คุณต้องการ แต่ทำให้งานสำเร็จลุล่วง คุณพึ่งพารูปแบบเดียวมากเกินไปและจำเป็นต้องเรียนรู้เครื่องมือที่ดีที่สุดเพื่องานที่ดีที่สุด

โปรแกรมทั้งหมดของคุณอาจได้รับความนิยมอย่างมากเนื่องจากคุณพยายามแกะสี่เหลี่ยมเป็นรูปวงกลม คุณรู้ว่าต้องใช้เวลานานกว่าสองเท่าในการเขียนโค้ดและในการรันโปรแกรมโดยใช้สถาปัตยกรรมค้อนสำหรับปัญหานี้ แต่มันง่ายกว่าและเป็นสิ่งที่คุณพอใจ

นอกจากนี้ยังไม่สามารถคาดเดาได้มากนัก ภาษาที่แตกต่างกันมีการแก้ไขปัญหาทั่วไปสำหรับปัญหาที่พวกเขาเผชิญและมาตรฐานของตนเอง คุณไม่สามารถใช้กฎข้อเดียวที่ใช้ได้ดีกับคุณในภาษาเดียวกับภาษาถัดไปโดยไม่มีปัญหา

อย่าละเลยการเรียนรู้ในอาชีพของคุณอย่างสม่ำเสมอ เลือกภาษาที่เหมาะกับปัญหาของคุณ ลองนึกถึงสถาปัตยกรรมและผลักดันเขตความสะดวกสบายของคุณออกไป ค้นคว้าและตรวจสอบเครื่องมือใหม่ ๆ และวิธีใหม่ ๆ ในการแก้ไขปัญหาที่คุณเผชิญ

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับรูปแบบการต่อต้านค้อนทองคำได้ที่นี่

สมอเรือ

เรือ Anchorต่อต้านรูปแบบคือที่โปรแกรมเมอร์ออกรหัสใน codebase เพราะพวกเขาอาจจำเป็นต้องได้ในภายหลัง

พวกเขาเขียนโค้ดบางอย่างที่ไม่ตรงตามข้อกำหนดเล็กน้อยและยังไม่จำเป็น แต่พวกเขาแน่ใจว่าจะใช้ในเดือนหน้า ดังนั้นพวกเขาจึงไม่ต้องการลบมัน ส่งไปยังการผลิตและในภายหลังเมื่อพวกเขาต้องการพวกเขาสามารถทำงานได้อย่างรวดเร็ว

แต่สิ่งนี้ทำให้เกิดฝันร้ายในการซ่อมบำรุงใน codebase ที่มีโค้ดที่ล้าสมัยทั้งหมด ปัญหาใหญ่คือเพื่อนร่วมงานของพวกเขาจะมีช่วงเวลาที่ยากลำบากในการหารหัสที่ล้าสมัยและไม่เปลี่ยนแปลงขั้นตอนเทียบกับรหัสที่ทำ

ลองนึกภาพว่าคุณกำลังประสบปัญหาร้อนแรงและพยายามหาสิ่งที่รับผิดชอบในการส่งรายละเอียดบัตรของลูกค้าไปยัง API เพื่อถอนเงินจากธนาคารของพวกเขา คุณอาจเสียเวลาในการอ่านและแก้ไขข้อบกพร่องของโค้ดที่ล้าสมัยโดยไม่ทราบว่าคุณไม่ได้อยู่ในตำแหน่งที่ถูกต้องใน codebase

ปัญหาสุดท้ายคือโค้ดที่ล้าสมัยทำให้เวลาในการสร้างของคุณนานขึ้นและคุณอาจผสมโค้ดที่ใช้งานได้กับโค้ดที่ล้าสมัย คุณสามารถเริ่ม "เปิดเครื่อง" ในการผลิตโดยไม่ได้ตั้งใจ

ตอนนี้คุณอาจจะเห็นแล้วว่าทำไมถึงเรียกว่ารูปแบบการต่อต้านการยึดเรือ - มันหนักที่จะพกพา (เพิ่มหนี้ทางเทคนิค) แต่ไม่ได้ทำอะไรเลย (ตามตัวอักษรรหัสไม่มีจุดประสงค์มันใช้งานไม่ได้)

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับรูปแบบการต่อต้านสมอเรือได้ที่นี่

รหัสตาย

คุณเคยต้องดูรหัสที่เขียนโดยคนที่ไม่ได้ทำงานที่ บริษัท ของคุณอีกต่อไปหรือไม่? มีฟังก์ชั่นที่ดูเหมือนไม่ได้ทำอะไรเลย แต่มันถูกเรียกมาจากทุกที่! คุณถามไปรอบ ๆ และไม่มีใครค่อนข้างแน่ใจว่ามันกำลังทำอะไรอยู่ แต่ทุกคนกังวลเกินกว่าที่จะลบมัน

บางครั้งคุณสามารถเห็นสิ่งที่กำลังทำอยู่ แต่บริบทหายไป คุณสามารถอ่านและเข้าใจโฟลว์ได้ แต่ทำไม? ดูเหมือนว่าเราไม่จำเป็นต้องไปถึงจุดสิ้นสุดนั้นอีกต่อไป การตอบสนองจะเป็นการตอบสนองเดียวกันสำหรับผู้ใช้ทุกคน

This is commonly described as the Dead code anti-pattern. When you can't see what is "actual" code necessary to the flow and successful execution of your program, versus what was only needed 3 years ago, and not now.

This particular anti-pattern is more common in proof on concept or research code that ended up in production.

One time at a tech meet up I met a guy who had this exact problem. He had tons of dead code, which he knew was dead, and lots he suspected was dead. But he could not get permission from management to ever remove all the dead code.

He referred to his approach as Monkey testing, where he started to comment out and turn off things to see what blew up in production. Maybe a little too risky!

If you don't fancy Monkey testing your production app, try to frame technical debt to management as "technical risk" to better explain why you think it's so important to tidy up.

Or even write down everything your particular module/section does you want to re-write, and take an iterative approach to remove piece by piece the dead code. Checking every time you haven't broken anything.

You don't have to drop a huge rewrite with thousands of changes. But you will either understand why it's so crucial and document why it's needed, or delete the dead code as you desired.

You can read more here about the Dead code anti-pattern.

Proliferation of Code

Objects or modules regularly communicate with others. If you have a clean, modularised codebase you often will need to call into other separate modules and call new functions.

The Proliferation of Code anti-pattern is when you have objects in your codebase that only exist to invoke another more important object. Its purpose is only as a middleman.

This adds an unnecessary level of abstraction (adds something that you have to remember) and serves no purpose, other than to confuse people who need to understand the flow and execution of your codebase.

A simple fix here is to just remove it. Move the responsibility of invoking the object you really want to the calling object.

You can read more here about the Proliferation of Code anti-pattern.

God Object

If everywhere in your codebase needs access to one object, it might be a God object.

God objects do too much. They are responsible for the user id, the transaction id, the customer's first and last name, the total sum of the transaction, the item/s the user is purchasing...you get the picture.

It is sometimes called the Swiss Army Knife anti-pattern because you only really need it to cut some twine, but it also can be a nail file, saw, pair of tweezers, scissors, bottle opener and a cork screw too.

In this instance you need to separate out and modularise your code better.

Programmers often compare this problem to asking for a banana, but receiving a gorilla holding a banana. You got what you asked for, but more than what you need.

The SOLID principles explicitly discuss this in object orientated languages, to help us model our software better (if you don't know what the SOLID principles are, you can read this article).

The S in the acronym stands for Single Responsibility - every class/module/function should have responsibility over one part of the system, not multiple.

You can see this problem over and over again, how about the below interface?

interface Animal { numOfLegs: string; weight: number; engine: string; model: string; sound: string; claws: boolean; wingspan: string; customerId: string; } 

Can you see by even just briefly scanning this interface that the responsibility of this is far too broad, and needs refactoring? Whatever implements this has the potential to be a God object.

How about this?

 interface Animal { numOfLegs: string; weight: number; sound: string; claws: boolean; } interface Car { engine: string; model: string; } interface Bird { wingspan: string; } interface Transaction { customerId: string; } 

Interface segregation will keep your code clear about where the responsibilities lie, and stop forcing classes that only need wingspan to also implement the engine, customerId and model  and so on.

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับรูปแบบการต่อต้านวัตถุพระเจ้าได้ที่นี่

สรุป

ในโค้ดเบสขนาดใหญ่ใด ๆ จะมีความสมดุลที่คงที่ระหว่างการจัดการหนี้ทางเทคนิคการเริ่มการพัฒนาใหม่และการจัดการคิวของจุดบกพร่องสำหรับผลิตภัณฑ์ของคุณ

ฉันหวังว่าบทความนี้จะช่วยให้คุณสังเกตเห็นว่าคุณอาจจะลงไปในโพรงกระต่ายของการต่อต้านรูปแบบและเครื่องมือบางอย่างในการแก้ไขปัญหานี้อย่างหมดจด

ฉันแบ่งปันงานเขียนของฉันบน Twitter หากคุณชอบบทความนี้และต้องการดูเพิ่มเติม