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

PHP เป็นภาษาที่ไม่ดีใช่หรือไม่

ไม่แน่นอน PHP รุ่นล่าสุด (8.0, 8.1) นำเสนอสิ่งดีๆ มากมาย เช่น คุณลักษณะ การกำหนดคุณสมบัติในตัวสร้าง นิพจน์การจับคู่ ตัวดำเนินการที่ปลอดภัยแบบ null การแจงนับ และประเภทการส่งคืน "ไม่" เมื่อฉันเปลี่ยนมาใช้ Kotlin สิ่งเหล่านี้หายไปทั้งหมด

ปัญหาหลักสำหรับฉันเกี่ยวกับ PHP ไม่ใช่รูปแบบโค้ดและโครงสร้างโค้ด — สิ่งเหล่านี้ค่อนข้างคล้ายกันมากในตอนนี้:

อย่างที่คุณเห็น นักพัฒนา PHP อาจได้รับแรงบันดาลใจจากภาษาที่ใช้ JVM การเปลี่ยนไปใช้ Kotlin/JVM มีประโยชน์อย่างไร

ไวยากรณ์ที่กระชับ

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

ตอนนี้ มาเปรียบเทียบกับโค้ดใน Kotlin แล้วตัดสินว่าอันไหนอ่านง่ายกว่ากัน

Kotlin/JVM ยังรองรับสิ่งที่ไม่มีใน PHP เช่น "generics" และ "extensions" ทั้งสองมีประโยชน์มากและสามารถทำให้โค้ดสะอาดและนำมาใช้ซ้ำได้

ความแตกต่างในองค์ประกอบการทำงาน

ก่อนอื่นเรามาดูฟังก์ชันการพับที่เขียนด้วย PHP และ Kotlin กันก่อน

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

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

สิ่งสุดท้ายคือ PHP ไม่รองรับฟังก์ชันส่วนขยาย มันบังคับให้คุณเขียนฟังก์ชันแบบสแตนด์อโลนที่ไม่สามารถเชื่อมต่อกับคลาสหรืออินเทอร์เฟซเฉพาะได้เสมอ

โครงการหลายโมดูล

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

จากมุมมองของเครื่องมือ Gradle และ Maven ให้การสนับสนุนนอกกรอบสำหรับโครงการหลายโมดูล คุณสามารถเปิดใช้งานปลั๊กอินที่แตกต่างกันและต้องการการขึ้นต่อกันต่อโมดูล ฉันจำความเป็นไปได้ประเภทนี้ไม่ได้ในขณะที่ใช้ PHP Composer

ประสิทธิภาพ

บริการที่ฉันดูแลอยู่ในปัจจุบันมีเวลาตอบสนอง 99 เปอร์เซ็นต์ไทล์ประมาณ 6 มิลลิวินาที (ทำงานบน Spring Boot 2.6.x) การบรรลุประสิทธิภาพประเภทนี้ด้วยเฟรมเวิร์ก PHP และ Symfony เป็นเรื่องยากมากและในกรณีส่วนใหญ่แทบจะเป็นไปไม่ได้เลย สิ่งที่ดีที่สุดของฉันใน PHP คือเฉลี่ย 30 มิลลิวินาทีต่อคำขอสำหรับโปรเจ็กต์ที่มีขนาดใกล้เคียงกัน

PHP เป็นภาษาที่ตีความ นั่นหมายความว่าจำเป็นต้องสร้างการสร้างอินสแตนซ์ของแอปพลิเคชันสำหรับทุกคำขอ นั่นก็หมายความว่าคำขอไม่สามารถประมวลผลแบบอะซิงโครนัสได้ — ไม่มีวิธีใดที่จะทำให้เซิร์ฟเวอร์ Nginx สามารถระงับได้เนื่องจากต้องรอผลลัพธ์ ขณะนี้ PHP มี JIT และการโหลดล่วงหน้า แต่ผลลัพธ์นั้นเทียบไม่ได้กับสแต็ก JVM

Kotlin นำเสนอการจัดการคำขอแบบอะซิงก์ที่ทำได้ง่ายโดยใช้ coroutines พูดตรงๆ โดยไม่ต้องปรับแต่งใดๆ เลย มันสามารถให้ผลลัพธ์ที่เห็นได้ชัดเจนและเพิ่มจำนวนคำขอที่สามารถจัดการได้โดยใช้ทรัพยากรจำนวนเท่ากัน

สำหรับ JVM มีความเป็นไปได้อีกอย่างหนึ่งที่จะเพิ่มประสิทธิภาพ — GraalVM ซึ่งเป็นคอมไพเลอร์ JIT ประสิทธิภาพสูง เป็นสิ่งที่สามารถใช้ได้โดยใช้ความพยายามค่อนข้างน้อยและ "ให้ประโยชน์มหาศาล" นอกจากนี้ Spring ยังทำงานเพื่อสนับสนุน GraalVM อย่างเป็นทางการ — Spring Native

ความพร้อมใช้งานของห้องสมุดอย่างเป็นทางการ

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

Kotlin สามารถใช้ไลบรารี Java ได้ Java ได้รับการรองรับอย่างดี — บริษัท/โครงการเกือบทั้งหมดที่ฉันรู้จักออก SDK/ไลบรารีอย่างเป็นทางการสำหรับ JVM ยิ่งไปกว่านั้น ห้องสมุดหลายแห่งยังรองรับ Kotlin โดยตรงอีกด้วย มันนำมาซึ่งความเสถียรอย่างมากและทำให้โครงการสามารถบำรุงรักษาได้มากขึ้นโดยไม่ต้องกลัวว่าจะสูญเสียการพึ่งพาใด ๆ ในทันที

รองรับโปรโตคอลการสื่อสาร

เมื่อคุณทำงานกับไมโครเซอร์วิส แง่มุมการสื่อสารถือเป็นสิ่งสำคัญ การใช้โปรโตคอลที่ผิดและช้าอาจทำให้เกิดปัญหามากมาย การมีปัญหาคอขวดเพียงจุดเดียวก็เพียงพอที่จะทำให้สถาปัตยกรรมทั้งหมดช้าลง ฉันชอบใช้ gRPC เป็นโปรโตคอลการสื่อสารระหว่างบริการ (ไมโคร) มันให้ประสิทธิภาพที่ดี การใช้โมเดล Protobuf ทำให้คุณสามารถกำหนดสัญญา API สำหรับไมโครเซอร์วิสแต่ละรายการได้อย่างง่ายดาย มีตัวเลือกอื่นๆ เช่น SOAP หรือ Java RMI แต่ในปัจจุบันนี้ไม่มีการใช้งานทั่วไป นั่นคือเหตุผลที่ฉันจะไม่เจาะลึกตัวเลือกเหล่านั้น

น่าเสียดายที่ PHP ให้การสนับสนุน gRPC ที่ไม่ดีนัก คุณสามารถสร้างไคลเอ็นต์ได้ แต่การเรียกใช้เซิร์ฟเวอร์ gRPC นั้นทำได้ยาก (หรือเป็นไปไม่ได้) นอกจากนี้ ตัวสร้าง PHP ไม่รองรับไวยากรณ์ Protobuf ทั้งหมด มีคนบอกว่าเรายังใช้ OpenAPI ได้ น่าเสียดายที่นี่เป็นโซลูชันที่มีประสิทธิภาพน้อยกว่า gRPC ที่มี Protobuf มากและยากต่อการทำงานในระยะยาว มีการเปรียบเทียบที่ดีระหว่าง 2 โปรโตคอลดังกล่าว ที่นี่

การสนับสนุนนายหน้าข้อความ

ใน PHP พร้อม Symfony หากต้องการใช้ข้อความจากนายหน้าเช่น RabbitMQ หรือ Kafka จำเป็นต้องเรียกใช้คำสั่งที่ดำเนินการแยกจากโฟลว์แอปพลิเคชันหลัก ยิ่งไปกว่านั้น คุณยังต้องตั้งค่าหัวหน้างานที่เหมาะสมเพื่อให้มันทำงานตลอดไป ตอนนี้คูณด้วยจำนวนคิว/หัวข้อที่จะใช้ข้อความ ใน JVM สามารถดำเนินการได้อย่างง่ายดายด้วยมัลติเธรด แอปพลิเคชันทำงานเป็นกระบวนการและมีสิทธิ์เข้าถึงคอร์ CPU และเธรด คุณสามารถจัดสรรหนึ่งในเธรด (หรือมากกว่า) และเรียกใช้คอนซูเมอร์ภายในอินสแตนซ์แอปเดียวกันได้ การเขียนการสื่อสารตามเหตุการณ์นั้นง่ายต่อการนำไปใช้และทดสอบ คุณยังสามารถนึกถึงการสร้างโมดูลที่ดำเนินการเฉพาะการใช้ข้อความเท่านั้น

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

การสร้างโมดูล/ไลบรารีที่แยกจากกัน

PHP มี Composer, JVM มี Maven/Gradle การสร้างและจัดการไลบรารีในตัวแต่งเพลง ไม่ได้ตรงไปตรงมานัก ฉันคิดว่ามันง่ายกว่ามากในโลก JVM โดยเฉพาะอย่างยิ่งเมื่อใช้ "GitHub Actions" กับ "แพ็คเกจ GitHub" สิ่งที่คุณต้องทำคือใช้ขั้นตอนเดียวในเวิร์กโฟลว์

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

สิ่งสำคัญอีกประการหนึ่งคือการพัฒนาท้องถิ่น การใช้พื้นที่เก็บข้อมูล mavenLocal() และงาน publishToLocalMaven คุณสามารถทดสอบการเปลี่ยนแปลงของคุณได้ทันที ในโลกของ PHP คุณต้องเพิ่มพื้นที่เก็บข้อมูลเฉพาะที่ชี้ไปยังไดเร็กทอรีในเครื่อง และเรียกใช้การดำเนินการ "อัปเดตผู้แต่ง" ทุกครั้งที่คุณเปลี่ยนแปลงบางสิ่ง

ความสามารถในการสังเกต

ในงานของฉัน เราใช้ความพยายามอย่างมากกับ "ความสามารถในการสังเกต" บริการที่ใช้ JVM/NodeJS/Ruby ของเราใช้มาตรฐาน OpenTelemetry เพื่อรวบรวมข้อมูลและเผยแพร่ไปยัง HoneyComb การสนับสนุน PHP สำหรับสิ่งนั้นในปัจจุบันอยู่ในช่วงพรีอัลฟาเท่านั้น และไม่ควรใช้ในสภาพแวดล้อมการใช้งานจริง ถือเป็นข้อเสียอย่างมากในโลกของการติดตามแบบกระจาย เนื่องจากไม่มีความเป็นไปได้ที่จะใช้การวัดและส่งข้อมูลทางไกลอย่างเหมาะสม เราจึงถูกจำกัดโดยบริการ PHP โดยพิจารณาว่าเราสามารถสังเกตได้ไกลแค่ไหน เรายังคงสามารถใช้เครื่องมือเช่น NewRelic ได้ แม้ว่าเราจะเปรียบเทียบราคาก็จะมากกว่าสองถึงสามเท่าและฟังก์ชันการทำงานก็ไม่เหมือนกันนัก

การสนับสนุน IDE/การดีบัก

Kotlin และ IntelliJ ได้รับการพัฒนาโดย JetBrains ไม่น่าแปลกใจเลยที่การรองรับ IDE สำหรับ Kotlin นั้นเกือบจะสมบูรณ์แบบ ไม่เพียงแต่รองรับไวยากรณ์ล่าสุดเสมอ แต่ยังให้การบูรณาการที่ยอดเยี่ยมกับเครื่องมือ/เฟรมเวิร์ก JVM เช่น Gradle, JUnit และ Spring Boot

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

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

โค้ดหลายแพลตฟอร์ม

จุดแข็งที่ยอดเยี่ยมของ Kotlin คือ Kotlin Multiplatform

คุณสามารถสร้างไลบรารีหลายแพลตฟอร์มด้วยโค้ดทั่วไปและการใช้งานเฉพาะแพลตฟอร์มสำหรับแพลตฟอร์ม JVM, JS และ Native เมื่อเผยแพร่แล้ว ไลบรารีหลายแพลตฟอร์มสามารถใช้ในโปรเจ็กต์ข้ามแพลตฟอร์มอื่นๆ เป็นการพึ่งพาได้ (https://kotlinlang.org/docs/multiplatform.html)

ในบริษัทของฉัน มีการใช้ห้องสมุดหลายแห่งบนแพลตฟอร์มมือถือทั้งสองแบบ ไม่มีอะไรทดแทนในโลก PHP

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

การสนับสนุนเฟรมเวิร์ก/ไลบรารี

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

หากคุณสนใจเกี่ยวกับการแยกโมเดลโดเมนและโครงสร้างพื้นฐานออกจากกันอย่างชัดเจน คุณอาจพบว่าเป็นการยากที่จะกำหนดการแมปฐานข้อมูลในไฟล์ XML/YAML ที่แยกจากกัน เช่น Doctrine ใน PHP คำอธิบายประกอบมักเป็นวิธีเดียวที่จะดำเนินการได้ ในทำนองเดียวกัน สิ่งนี้ใช้กับการตรวจสอบความถูกต้องด้วย — การเขียนลงในไฟล์แยกต่างหากนั้นไม่ใช่เรื่องง่าย

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

คุณควรลองใช้ Kotlin ในฐานะนักพัฒนา PHP หรือไม่

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

แล้วคำตอบทั่วไปของฉันสำหรับคำถามนี้คืออะไร? ฉันคิดว่ามันขึ้นอยู่กับ

คุณต้องรู้ว่าช่วงการเรียนรู้นั้นสูง การเปลี่ยนจาก PHP เป็น Kotlin ทำให้คุณเริ่มคิดถึงแอปพลิเคชันและการพัฒนาของคุณแตกต่างออกไป สิ่งต่างๆ เช่น การเห็นพ้องต้องกัน ความเท่าเทียม การเก็บขยะ คุณจำเป็นต้องเรียนรู้และดูแลสิ่งเหล่านั้น คุณต้องค้นพบ Gradle/Maven เพื่อกำหนดค่าโปรเจ็กต์ของคุณ คุณต้องค้นหาและทำความคุ้นเคยกับเฟรมเวิร์ก Kotlin/Java ใหม่ คุณต้องระวังว่าบางครั้งคุณจำเป็นต้องสัมผัส Java สักหน่อย โดยเฉพาะอย่างยิ่งเมื่อใช้ไลบรารี่ที่ยังไม่มีเวอร์ชัน Kotlin

หากสิ่งที่กล่าวมาข้างต้นไม่ทำให้คุณกลัว คุณก็พร้อมที่จะไป ฉันขอแนะนำเป็นอย่างยิ่งให้เริ่มต้นจาก JetBrains Academy Kotlin Basics Course โปรเจ็กต์ต่างๆ ที่นั่นมีการจัดระเบียบอย่างดี และคุณสามารถเรียนรู้พื้นฐานของภาษาได้โดยการทำโปรเจ็กต์เหล่านั้น ขั้นตอนต่อไปมักจะลองเลือกหนึ่งในเฟรมเวิร์ก เช่น Spring Boot และสร้างโปรเจ็กต์แบ็กเอนด์ขนาดเล็ก หลังจากนั้นก็ขึ้นอยู่กับคุณเท่านั้นว่าจะดำเนินการต่ออย่างไร จะเป็นการดีที่สุดหากบริษัทของคุณสนับสนุนคุณในการเปลี่ยนแปลง แต่ฉันเชื่อว่าใครๆ ก็สามารถเปลี่ยนแปลงได้ด้วยความหลงใหลและการเสียสละเวลาส่วนตัว