Cùng tìm hiểu về Kotlin

1. Giới thiệu về Kotlin

Kotlin là một ngôn ngữ ngữ dụng kiểu tĩnh dành cho Java Virtual Machine đã chính thức phát hành phiên bản 1.0. Nó được tạo ra bởi JetBrains, Kotlin cũng giống như nhiều ngôn ngữ lập trình không phải Java khác, tức là cũng sẽ chạy trên JVM và sử dụng các công cụ và thư viện hiện có của Java. Và ngược lại Java cũng có thể sử dụng các item được xây dựng trong Kotlin.

Theo website JetBrains, mục tiêu quan trọng của Kotlin là tính hữu dụng. Từ lúc giới thiệu vào năm 2011 cho đến khi phát hành phiên bản 1.0, JetBrains đã luôn chú trọng đến tính tương hợp với Java..Mặc dù Kotlin có một số tính năng hoàn toàn mới chẳng hạn như một type system được thiết kế để ngăn chặn các bug như các null pointer reference, nhưng quan trọng là nó làm việc cùng với code và cơ sở hạ tầng hiện có của Java. Cuối cùng, Kotlin không có trình quản lý gói và build system của riêng nó, do Java đã có sẵn.

2. Kotlin và Android

Lập trình Android là một trong những lĩnh vực quan trọng mà JetBrains hướng đến với Kotlin. Ngôn ngữ mang đến tính tương thích ngược với Java 6 và 7, các phiên bản của Java hầu hết đều tương thích chặt chẽ với Android. JetBrains cũng hy vọng Kotlin sẽ được sử dụng trong các lĩnh vực khác chẳng hạn như các ứng dụng lớn và phức tạp, đề cao hiệu suất.

Các nhà phát triển không có lựa chọn thay thế cho việc phát triển ứng dụng Android bằng ngôn ngữ Java. Mặc dù được sử dụng rộng rãi, nhưng trong quá trình hoạt động ngôn ngữ Java sinh ra rất nhiều file rác. Java 8 đã giải quyết một số vấn đề ngôn ngữ và đặc biệt hơn là với Java 10. Để có được nhiều lợi ích từ việc chỉnh sửa trong hai phiên bản này, bạn phải đặt SDK tối thiểu sang Android 24 chỉ để sử dụng Java 8. Kotlin nhắm đến việc lấp đầy khoảng trống đó của một ngôn ngữ hiện đại đang thiếu cho nền tảng Android.

Có một vài nguyên lý cốt lõi mà giúp Kotlin tồn tại đó là:

Nhỏ gọn để giảm số lượng mã boilerplate cần viết. Mã code dễ đọc và dễ hiểu hơn. An toàn, tránh toàn bộ các lớp lỗi như các null pointer exceptions. Linh hoạt cho việc xây dựng ứng dụng phía máy chủ, ứng dụng Android hoặc mã lối vào đang chạy trong trình duyệt. Khả năng tương tác để tận dụng các khuôn khổ và thư viện hiện có của JVM với khả năng tương tác Java 100%.

3. Ưu và nhược điểm của Kotlin

3.1. Ưu điểm

Dù không thiếu các ngôn ngữ biên dịch sang Java bytecode, nhưng có một vài yếu tố làm cho Kotlin nổi bật hơn cả:

Có thể thay thế cho Java

Một trong những thế mạnh lớn nhất của Kotlin như là một ứng viên để thay thế cho Java là khả năng tương tác rất tốt giữa Java và Kotlin—bạn có thể thậm chí có code Java và Kotlin tồn tại song song trong cùng dự án, và tất cả mọi thứ vẫn sẽ được biên dịch một cách hoàn hảo. Dưới đây, bạn có thể thấy một ví dụ về một dự án bao gồm một Activity Java và một Actitivy Kotlin.

Trong thực tế, một khi dự án kết hợp Kotlin và Java được biên dịch, người dùng sẽ không thể biết những phần nào của dự án của bạn được viết bằng Java, và những phần nào được viết bằng Kotlin. Bởi vì các lớp Kotlin và Java có thể tồn tại song song trong cùng một dự án, nên có thể bắt đầu sử dụng Kotlin mà không cần phải làm bất cứ điều gì to tát cả giống như chuyển đổi toàn bộ dự án sang Kotlin hoặc bắt đầu một dự án mới để bạn có thể thử Kotlin.

Vì Kotlin là hoàn toàn tương thích với Java, nên cũng có thể sử dụng phần lớn các thư viện Java và các framework trong dự án Kotlin của bạn—thậm chí nâng cao các framework dựa vào chú thích xử lý.

Dễ học

Kotlin nhằm mục đích là nâng cao hơn so vớiJava, chứ không phải hoàn toàn viết lại, rất nhiều các kỹ năng đã có trong việc code Java của bạn vẫn được áp dụng đối với dự án Kotlin.

Kotlin cũng được thiết kế để có thể dễ học cho các nhà phát triển Java. Những nhà phát triển Java sẽ cảm thấy rằng hầu hết cú pháp của Kotlin đều quen thuộc; ví dụ, các code được sử dụng để tạo ra một lớp mới trong Kotlin là rất giống với Java:

class MainActivity : AppCompatActivity() {

Kotlin cũng được thiết kế trực quan và dễ đọc, do đó, ngay cả khi bạn gặp một số code khác biệt, thì bạn vẫn có thể để biết được ý nghĩa về những gì code này làm.

Kết hợp những gì tốt nhất của lập trình hàm và thủ tục

Hiện đang có một số lý thuyết lập trình được sử dụng rộng rãi, nhưng khi nói đến các câu hỏi về “phương pháp nào là tốt nhất”, thì không dễ để có câu trả lời. Mỗi kiểu lập trình có tập hợp điểm mạnh và điểm yếu của nó, do đó, mặc dù không thiếu các kịch bản mà lập trình hàm có một lợi thế, thì cũng có rất nhiều vấn đề nơi mà một cách tiếp cận lập trình thủ tục sẽ hiệu quả hơn.

Vậy tại sao bạn cần phải lựa chọn giữa hàm và thủ tục? Giống như nhiều ngôn ngữ lập trình hiện đại khác, Kotlin nhằm mục đích mang lại cho bạn những gì tốt nhất của cả hai bằng cách kết hợp các khái niệm và các yếu tố của lập trình thủ tục và hàm.

Android Studio hỗ trợ

Kotlin được phát triển bởi JetBrains, công ty đứng sau IntelliJ—IDE mà Android Studio dựa trên nó. Không có gì bất ngờ, rằng Android Studio hỗ trợ tốt cho Kotlin. Một khi bạn đã cài đặt plugin Kotlin, Android Studio làm cho việc cấu hình Kotlin trong dự án của bạn trở nên đơn giản giống như mở một vài menu.

Một khi bạn đã thiết lập plugin Kotlin cho Android Studio, IDE của bạn sẽ không gặp vấn đề gì việc hiểu, biên dịch và chạy code Kotlin. Android Studio cũng cung cấp việc gỡ lỗi, tự động hoàn tác, điều hướng code, unit testing, và tái cấu trúc cho Kotlin.

Một khi dự án Android Studio của bạn đã được cấu hình để hỗ trợ cho Kotlin, bạn thậm chí có thể chuyển đổi toàn bộ một tập tin mã nguồn Java thành một tập tin Kotlin, với chỉ một vài cú nhấp chuột.

Code ngắn gọn hơn

Nếu bạn so sánh một lớp Java và một lớp Kotlin cho ra cùng một kết quả, thì cái được viết trong Kotlin thường sẽ gọn gàng hơn nhiều và nhỏ gọn hơn so với những gì được viết bằng Java. Và như mọi nhà phát triển đều biết, code ít hơn có nghĩa là ít lỗi hơn!

Ví dụ, các code Java sau tạo ra một Activity bao gồm một floating action button (FAB), mà khi chạm vào, hiển thị một snackbar có chứa các thông báo hữu ích This is a snackbar.

public class MainActivity extends AppCompatActivity {
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
       setSupportActionBar(toolbar);
 
       FloatingActionButton myfab = (FloatingActionButton) findViewById(R.id.myfab);
       myfab.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               Snackbar.make(view, "This is a snackbar", Snackbar.LENGTH_LONG)
                       .setAction("Action", null).show();
           }
       });
   }
}

Kotlin đạt được điều tương tự bằng lượng code ít hơn, đặc biệt là khi nói đến việc tạo FAB và thiết lập onClickListener:

class MainActivity : AppCompatActivity() {
 
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)
       val toolbar = findViewById(R.id.toolbar) as Toolbar
       setSupportActionBar(toolbar)
 
       val myfab = findViewById(R.id.myfab) as FloatingActionButton
       myfab.setOnClickListener { view ->
           Snackbar.make(view, "This is a snackbar", Snackbar.LENGTH_LONG)
                   .setAction("Action", null).show()
       }
   }
}

Cả hai đoạn code cho ra kết quả giống nhau:

Kotlin đặc biệt tốt trong việc giảm số lượng code mà bạn cần phải viết, làm cho việc viết code trong Kotlin trở thành một trải nghiệm thú vị hơn nhiều, so với việc viết code trong nhiều ngôn ngữ khác như Java.

Đặc biệt, các extension của Kotlin Android (mà chúng ta sẽ khám phá trong phần hai) cho phép bạn nhập tham chiếu đến một View vào một tập tin Activity, từ đó, bạn có thể làm việc với giao diện như thể nó là một phần của Activity đó. Điều này có nghĩa là bạn không còn phải xác định mỗi View bằng cách sử dụng findViewById, mà có thể chuyển đổi code chẳng hạn như:

TextView text = (TextView) findViewById(R.id.myTextView); text.setText("Hello World");

Thành gọn gàng hơn nhiều:

myTextView.setText("Hello World")

3.2. Nhược điểm

Không có ngôn ngữ lập trình nào là hoàn hảo cả, do đó, mặc dù Kotlin có rất nhiều thứ để cung cấp cho các nhà phát triển Android, nó vẫn có một số nhược điểm mà bạn cần lưu ý:

Thêm thời gian chạy Runtime

Thư viện tiêu chuẩn của Kotlin và runtime sẽ làm tăng kích thước tập tin .apk của bạn. Mặc dù nó chỉ tương đương với khoảng 800KB, nhưng nếu ứng dụng của bạn đã lớn sẵn rồi thì 800KB phụ có thể làm nó phình to và khiến người dùng nghĩ lại trước khi tải về ứng dụng của bạn.

Không hẳn là code dễ đọc đối với beginer

Mặc dù cú pháp ngắn gọn của Kotlin là một trong những thế mạnh lớn nhất của ngôn ngữ, nhưng bạn có thể thấy một số khó khăn ban đầu, đơn giản bởi vì có rất nhiều thứ đang được thực hiện trong một số lượng nhỏ code đó. Java có thể dài dòng hơn, nhưng ngược lại tất cả mọi thứ đều rõ ràng, có nghĩa là những người không quen code Java có xu hướng dễ dàng hơn để hiểu so Kotlin.

Ngoài ra, nếu sử dụng không hợp lý, quá tải toán tử của Kotlin có thể dẫn đến số code đó có thể khó khăn để đọc.

Thiếu hỗ trợ chính thức

Kotlin có thể được trợ tốt trong Android Studio, nhưng cần ghi nhớ rằng Kotlin không được xác nhận chính thức là của Google.

Ngoài ra, tính năng tự động hoàn tác và biên dịch trong Android Studio có xu hướng chạy hơi chậm khi bạn làm việc với Kotlin so với một dự án thuần Java.

Cộng đồng nhỏ hơn và ít có sẵn trợ giúp

Vì Kotlin là một ngôn ngữ tương đối mới, nên cộng đồng Kotlin vẫn còn khá nhỏ, đặc biệt là so với cộng đồng của ngôn ngữ khác như Java. Nếu bạn chuyển đổi sang Kotlin, thì bạn có thể không có được truy cập vào cùng một số hướng dẫn, bài đăng trên blog, và tài liệu hướng dẫn sử dụng, và có thể gặp ít hỗ trợ từ cộng đồng về những nơi như các diễn đàn và Stack Overflow. Tại thời điểm bài viết, tìm kiếm cho Kotlin trong Stack Overflow trả về các bài viết chỉ hơn 4.600 được dán nhãn Kotlin—so với hơn 1.000.000 bài viết có chứa các từ khóa Java.

4. Đặc điểm

4.1. Khai báo biến

  • Có 2 từ khóa khai báo biến trong Kotlin là var và val
val a: Int = 1
val b = 1   // `Int` type is inferred
val c: Int  // Type required when no initializer is provided
c = 1       // definite assignment
var x = 5 // `Int` type is inferred
x += 1
  • Từ khóa var sử dụng khi giá trị của biến thay đổi, val sử dụng khi giá trị của biến không thay đổi
  • Từ khóa val giống như readonly trong C# hoặc final trong Java
  • Biến val phải được khởi tạo lúc khai báo
  • Từ khóa Void trong java hay C# sẽ được thay thế bằng Unit trong Kotlin

4.2. Null Safety

Một trong những cạm bẫy phổ biến trong các ngôn ngữ lập trình, bao gồm cả Java là cho phép 1 thành phần nào đó được Null. Nếu không chắc chắn thành phần đó được phép Null hay không sẽ rất dễ xảy ra lỗi không lường trước được, gây nguy hiểm cho hệ thống của bạn. Cụ thể, trong java sẽ gây ra 1 exception là NullPoiterException hoặc viết ngắn gọi là NPE.

Kotlin nhằm mục đích xóa bỏ NullPoiterException trong code của chúng ta. Ngay khi khai báo biến với Kotlin, bạn đã phải chỉ rõ biến đó có được phép Null hay không. Có 2 trường hợp được phép đó là : không thể Null và có thể Null

  • Khai báo 1 biến cho phép Null
var b: String? = "abc" // có thêm dấu ? sau kiểu của biến
b = null // compilation ok
val l = b.length // not safe
  • Khai báo 1 biến không được phép Null
var a: String = "abc"
a = null // compilation error
val l = a.length // safe

Chúng ta có thể thấy Kotlin đã khắc phục được expcetion NPE trong Java. Các biến cho phép Null hay không được phép Null đã được xác định ngay trong quá trình khai báo biến, các IDE sẽ giúp chúng ta phát hiện ra lỗi ngay khi compile. Việc phát hiện ra lỗi sớm khi compile sẽ tốt hơn so với khi runtime. Nó giúp hệ thống của chúng ta an toàn hơn.

4.3. String template

String trong kotlin có thể chứa các biểu thức template, tức là những kết quả trả về hoặc biến có thể được nối vào trong 1 String. Một biểu thức template bắt đầu với ($) và tên :

val apples = 4
valbananas = 3
println(“I have $apples apples.”)
println(“I have $apples apples and ” + (apples + bananas) + “ fruits.”)

println(“I have $apples apples and ${apples + bananas} “ fruits.”)

4.4. Kế thừa và Override

  • Mặc định class trong Kotlin đều là final (tức là không được phép kế thừa)
open class Base {
    open fun v() {}
    fun nv() {}
}
class Derived() : Base() {
   override fun v() {}
}
  • Trong class final (tức là không có từ khóa “open”) thì việc khai báo các hàm, thuộc tính open bị cấm
  • Ở 1 lớp con khác, hàm được đánh dấu là override thì chính nó là open (lại được kế thừa từ lớp khác), nếu muốn chống override thì lại sử dụng từ khóa final
open class AnotherDerived() : Base() {
    final override fun v() {}
}
  • Trong interface, các member mặc định là “open”
interface B {
    fun f() { print("B") } // interface members are 'open' by default
    fun b() { print("b") }
}
  • Kotlin implement interface :
class C() : A(), B {
     // The compiler requires f() to be overridden:
     override fun f() {
	super<A>.f() // call to A.f()
	super<B>.f() // call to B.f()
     }
}

4.5. Chỉ định truy cập (Visibility Modifiers)

  • Có 4 loại Visivility Modifiers trong Kotlin : private, protected, internal, và public
  • Nếu không chỉ rõ thì mặc định là public
  • Các chỉ định truy cập : private, protected và public giống cách sử dụng trọng java
  • Riêng internal ta có thể sử dụng trong cùng module

4.6. Truyền tham số trong hàm

  • Kotlin cho phép thay đổi vị trí tham số trong hàm
fun main(args : Array<String>) { 
    greet(firstName = "Frasensco", lastName = "Merini") 
    greet(lastName = "John", firstName = "Stamos") 
    greet("Borat", "Ismail") 
    greet("Crystal", lastName = "Stamos") 
    call("Xavier", age = 20, location = "Portugal") 
} 

fun greet(firstName : String, lastName : String){
    println("Good morning $firstName $lastName") 
} 

fun call(name : String, location : String, age : Int){ 
    println("Call $name who lives at $location and he is $age old") 
}

Out put :

Good morning Frasensco Merini
Good morning Stamos John
Good morning Borat Ismail
Good morning Crystal Stamos
Call Xavier who lives at Portugal and he is 20 old

Cùng đón xem phần tiếp theo trong bài viết tháng sau nhé

Chi tiết

Object và Class

Mỗi đối tượng tượng ghi nhớ class của nó bởi việc lưu một con trỏ đến cấu trúc RClass. Thông tin mà mỗi RClass chứa là gì? Chúng ta sẽ thấy gì nếu chúng ta có thể nhìn vào bên trong một class Ruby? Hãy xây dựng mô hình thông tin đại diện cho RClass. Mô hình này sẽ cho chúng ta một định nghĩa kỹ thuật class Ruby là gì, dựa trên

những gì chúng ta biết các lớp class có thể làm. 

Mọi Ruby developer biết làm thế nào để viết một class: Bạn gõ từ khóa class, định nghĩa tên của một class mới và sau đó gõ vào các phương thức của class. Hãy nhìn ví dụ tương tự sau đây:

class Mathematician
  attr_accessor :first_name
  attr_accessor :last_name
end

attr_accessor là 1 cách viết tắt để định nghĩa phương thức get và set của một thuộc tính. Các phương thức attr_accessor cũng kiểm tra những giá trị nil. Ví dụ sau sẽ cho chúng ta thấy một cách lòng vòng để định nghĩa cùng một class Mathematician

class Mathematician
  def first_name
    @first_name
  end
  
  def first_name=(value)
    @first_name = value
  end
  
  def last_name
    @last_name
  end

  def last_name=(value)
    @last_name = value
  end
end

Có vẻ như lớp trên và mọi lớp Ruby chỉ là một nhóm các định nghĩa phương thức. Bạn có thể gán hành vi cho một đối tượng bằng cách thêm các phương thức vào class của nó và khi bạn gọi một phương thức trên một đối tượng, Ruby tìm kiếm phương thức trong class của đối tượng. Điều này dẫn đến định nghĩa đầu tiên của chúng ta về một class Ruby:

Một class Ruby là một nhóm các định nghĩa phương thức.

Vì vậy cấu trúc RClass cho Mathematician phải lưu một danh sách tất cả các phương thức được định nghĩa trong class giống như trong hình sau  Chú ý ở đoạn code trên chúng ta đã tạo ra hai biến instance: @first_name và @last_name. Chúng ta đã thấy cách Ruby lưu các giá trị này vào mỗi cấu trúc RObject, nhưng bạn có thể nhận thấy rằng chỉ có các giá trị của các biến này được lưu trữ trong RObject chứ không phải tên của chúng (Ruby 1.8 lưu trữ các tên trong RObject). Ruby phải lưu trữ các thuộc tính trong RClass, điều này có ý nghĩa bởi vì các tên là giống nhau đối với mỗi instance Mathematician.

Hãy vẽ lại RClass lần nữa và bao gồm một bảng tên các thuộc tính, thể hiện trong hình dướiBây giờ định nghĩa của chúng ta về một lớp Ruby như sau

Một lớp Ruby là một nhóm các định nghĩa phương thức và một bảng tên các thuộc tính

Ở đầu chương này, tôi đã đề cập rằng mọi giá trị trong Ruby đều là đối tượng. Điều này cũng đúng với các class. Hãy chứng minh điều này bằng cách sử dụng IRB.

> p Mathematician.class
=> Class

Như bạn có thể thấy, các lớp Ruby là tất cả các instance của lớp Class. Do đó, các lớp cũng là các đối tượng. Bây giờ hãy cập nhật định nghĩa của chúng ta về lớp Ruby một lần nữa

Một lớp Ruby là một đối tượng Ruby mà cũng chứa các định nghĩa phương thức và tên các thuộc tính

Bởi vì các lớp Ruby là những đối tượng, chúng ta biết rằng cấu trúc RClass cũng phải chứa một con trỏ lớp và một mảng các biến instance, những giá trị mà chúng ta biết đều được chứa trong đối tượng Ruby.

Như bạn thấy, tôi đã thêm một con trỏ vào lớp Class (là lớp của mọi đối tượng Ruby), tôi cũng đã thêm một bảng các biến instance. Đây là những biến instance thuộc cấp độ lớp. Đừng nhầm lẫn điều này với bảng tên các thuộc tính của biến instance cấp đối tượng. Điều này có vẻ làm chúng ta khó hiểu. Cấu trúc RClass có vẻ khó hiểu hơn cấu trúc RObject. Nhưng đừng lo chúng ta đã nhận được cấu trúc RClass. Tiếp theo, chúng ta cần xem xét hai thông tin quan trọng chứa trong lớp Ruby.

Kế thừa Kế thừa là một tính năng không thể thiếu của lập trình hướng đối tượng. Ruby thực hiện đơn kế thừa bằng cách tùy chỉnh chỉ định một supperclass khi chúng ta tạo ra một lớp. Nếu chúng ta không chỉ định một superclass, Ruby chỉ định lớp Object là supperclass. Ví dụ chúng ta có thể viết lại lớp Mathematician sử dụng superclass giống như sau:

class Mathematician < Person

Bây giờ mỗi instance của Mathematician sẽ bao gồm những phương thức tương tự mà Person có. Trong ví dụ này, chúng ta có thể muốn di chuyển các phương thức accessor first_name và last_name vào Person. Chúng ta cũng có thể di chuyển thuộc tính @first_name và @last_name vào lớp Person. Mọi instance của Mathematician đều chứa Mathematician những phương thức và thuộc tính này, mặc dù đã được di chuyển hết vào lớp Person. Lớp Mathematician phải có tham chiếu đến lớp Person (superclass của nó) để Ruby có thể tìm thấy bất kỳ phương thức hoặc thuộc tính được định nghĩa trong superclass. Chúng ta hãy cập nhật định nghĩa của chúng ta một lần nữa, giả sử rằng Ruby theo dõi các superclass bằng cách sử dụng con trỏ khác tương tự klass:

Một lớp Ruby là một đối tượng Ruby mà có chứa các định nghĩa phương thức, tên thuộc tính và một con trỏ superclass.

Chúng ta sẻ vẽ lại cấu trúc RClass bao gồm con trỏ superclass

Biến Instance Class và biến Class Một chút khó hiểu về cú pháp của Ruby là về các biến class. Bạn có thể nghĩ rằng đây chỉ đơn giản là các biến instance của một class, nhưng biến instance class và biến class khác biệt rõ rệt. Để tạo một biến instance class, đơn giản bạn chỉ tạo một biến instance sử dụng ký hiệu @, nhưng trong ngữ cảnh của một class chứ không phải một đối tượng. Ví dụ sau, chúng ta có thể sử dụng một biến instance của Mathematician để chỉ ra một nhánh của lớp Mathematician. Chúng ta tạo biến @type

class Mathematician
  @type = "General"
  def self.type
    @type
  end
end

puts Mathematician.type
=> General

Ngược lại, để tạo một biến class, bạn sử dụng ký hiệu @@, ví dụ biến @@type dưới đây

class Mathematician
  @@type = "General"
  def self.type
    @@type
  end
end

puts Mathematician.type
=> General

Có gì khác biệt? Khi bạn tạo ra một biến class, Ruby tạo ra một giá trị duy nhất cho bạn sử dụng trong lớp đo và trong bất kỳ lớp con nào bạn có thể định nghĩa. Mặt khác, sử dụng biến instance class, Ruby sẽ tạo ra giá trị riêng cho mỗi lớp hoặc lớp con. Hãy xem ví dụ sau, để xem cách Ruby xử lý hai loại biến khác nhau. Trước tiên chúng ta định nghĩa một biến class instance gọi là @type trong lớp Mathematician và gán giá trị string là General. Tiếp theo, chúng ta tạo ra 1 lớp thứ hai gọi là Statistician, là một lớp con của Mathematician và thay đổi giá trị của @type thành Statistics.

class Mathematician
  @type = "General"
  def self.type
    @type
  end
end

class Statistician < Mathematician
  @type = "Statistics"
end

puts Statistician.type
=> Statistics
puts Mathematician.type
=> General

Chú ý rằng, giá trị của @type trong Statistician và Mathematician là khác nhau. Mỗi lớp có một bản sao @type riêng. Tuy nhiên, nếu chúng ta sử dụng một biến class, Ruby sẽ chia sẻ giá trị giữa Mathematician và Statistician

class Mathematician
  @@type = "General"
  def self.type
    @@type
  end
end

class Statistician < Mathematician
  @@type = "Statistics"
end

puts Statistician.type
=> Statistics

puts Mathematician.type
=> Statistics

Ở đây, Ruby hiển thị cùng một giá trị @@type trong Statistician và Mathematician. Tuy nhiên, Ruby thực sự lưu cả biến class và instance class trong cùng một bảng bên trong cấu trúc RClass. Biểu tượng mở rộng @ trong tên cho phép Ruby phân biệt 2 loại biến.

Kết luận

Bài viết này chỉ là dịch lại phần Class trong chương 5: Object and Class của của cuốn sách Ruby Under a Microscope Mình đã dịch lại phần Object của chương này trong bài viblo trước đó. Rất mong nhận được những lời đóng góp ý kiến của mọi người.

Chi tiết

Lớp và kế thừa trong Kotlin

Lớp

Lớp trong kotlin được khai báo sử dụng từ khóa class

class Invoice {
}

Khai báo lớp bao gồm tên lớp, tiêu đề của lớp(định nghĩa kiểu của tham số, constructor chính,…) và thân lớp bao quanh bởi dấu ngoặc nhọn. Cả tiêu đề và thân của lớp đều không bắt buộc, nếu lớp không có thân thì có thể bỏ ngoặc nhọn

class Empty

Những constructor

Một lớp trong kotlin có thể có một contructor chính và một hoặc nhiều constructor phụ. Contructor chính là một phần của tiêu đề lớp: nó đứng phía sau tên lớp (và kiểu các tham số tùy chọn)

class Person constructor(firstName: String){
}

Nếu constructor chính không có bất kỳ annotations hoặc định nghĩa quyền truy cập (public, private, protected, internal), từ khóa constructor có thể bỏ qua

class Person(firstName: String){
}

Các constructor chính có thể không chứa bất kỳ đoạn mã nào. Mã khởi tạo có thể đặt trong các khối khởi tạo cùng với từ khóa init. Trong quá trình khởi tạo instance, các khối khởi tạo được thực hiện theo thứ tự như chúng xuất hiện trong thân lớp, được xen kẽ với sự khởi tạo thuộc tính

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)

    init {
        println("First initializer block that prints ${name}")
    }

    val secondProperty = "Second property: ${name.length}".also(::println)

    init {
        println("Second initializer block that prints ${name.length}")
    }
}

fun main(args: Array<String>) {
    InitOrderDemo("hello")
}
// Kết quả chạy là 
//First property: hello
//First initializer block that prints hello
//Second property: 5
//Second initializer block that prints 5

Chú ý rằng, tham số của constructor chính có thể được sử dụng trong khối khởi tạo. Nó cũng có thể sử dụng trong khai báo khởi tạo thuộc tính trong thân lớp:

class Customer(name: String) {
    val customerKey = name.toUpperCase()
}

Trên thực tế, để khai báo các thuộc tính và khởi tạo từ constructor chính, chúng ta sử dụng cú pháp ngắn gọn:

class Person(val firstName: String, val lastName: String, var age: Int) {
    // ...
}

Cũng giống như các thuộc tính thông thường, các thuộc tính được khai báo trong constructor chính có thể bị biến đổi(var) hoặc chỉ đọc(val). Nếu constructor có các annotation hoặc định nghĩa quyền truy cập thì cần phải có từ khóa constructor và định nghĩa quyền truy cập phải đứng trước

class Customer public @Inject constructor(name: String) { ... }

 

Những constructor phụ

Lớp cũng có thể khai báo các constructor phụ, có tiền tố là constructor:

class Person {
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

Nếu một lớp có một constructor chính, mỗi constructor phụ cần phải đại diện cho các constructor chính, trực tiếp hoặc gián tiếp thông qua những constructor khác. Đại diện cho những constructor khác của cùng một lớp bằng cách sử dụng từ khóa this

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

Chú ý rằng mã trong các khối khởi tạo sẽ hiệu quả khi thành một phần của constructor chính. Đại diện cho constructor chính xảy ra như là câu lệnh đầu tiên của một constructor phụ, do đó mã trong khối khởi tạo được thực hiện trước trong thân constructor phụ. Thậm chí lớp không có constructor chính, đại diện vẫn chạy ngầm và các khối khởi tạo vẫn thực thi:

class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor")
    }
}

fun main(args: Array<String>) {
    Constructors(1)
}
//Init block
//Constructor

Nếu một lớp không trừu tượng không khai báo bất kỳ constructor nào (chính hoặc phụ), sẽ có một constructor chính không đối số được tạo ra. Quyền truy cập của constructor sẽ là public. Nếu bạn không muốn lớp của bạn có một public constructor, bạn cần phải khai báo một private constructor rỗng.

class DontCreateMe private constructor() {
}

Trên JVM, nếu tất cả các tham số của constructor chính có giá trị mặc định, trình biên dịch sẽ tạo thêm một parammeterless constructor, nó sẽ sử dụng các giá trị mặc định. Điều này làm cho việc sử dụng Kotlin trở nên dễ dàng hơn với các thư viện như Jackson hoặc JPA tạo instance lớp thông qua parammeterless constructor.

class Customer(val customerName: String = "")

Tạo các instance của các lớp

Để tạo một instance của một lớp, ta gọi constructor như thể nó là một hàm thông thường:

val invoice = Invoice()
val customer = Customer("Joe Smith")

Chú ý rằng kotlin không có từ khóa new

Các thành phần của lớp

Các lớp có thể chứa:

  • constructor và initializer block
  • Hàm
  • Thuộc tính
  • Nested and Inner Classes
  • Đối tượng

Kế thừa

Tất cả các lớp trong kotlin đều có chung lớp cha Any, đó là super mặc định cho một lớp mà không khai báo supertype nào:

class Example // Kế thừa từ Any

Để khai báo một lớp cha rõ ràng, chúng ta đặt type sau dấu hai chấm trong tiêu đề của lớp:

open class Base(p: Int)

class Derived(p: Int) : Base(p)

Nếu một lớp có một constructor chính, base type có thể (và phải) được khởi tạo ngay tại đấy, sử dụng các tham số của constructor chính. Nếu lớp không có constructor chính thì mỗi constructor phụ phải khởi tạo base type bằng cách sử dụng từ khóa super hoặc ủy thác cho một constructor khác làm điều này. Chú ý rằng trong trường hợp này, các constructor phụ khác nhau có thể gọi các constructor khác nhau của một loại base type:

class MyView : View {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

Phương thức ghi đè

Như chúng ta đã đề cập trước đây, chúng ta luôn làm rõ mọi thứ trong Kotlin. Và khác với Java, Kotlin yêu cầu các annotation phải rõ ràng (chúng ta gọi là open) cho các overridable member và để có thể ghi đè.

open class Base {
    open fun v() {}
    fun nv() {}
}
class Derived() : Base() {
    override fun v() {}
}

override annotation là yêu cầu bắt buộc đối với Derived.v(). Nếu nó bị thiếu, trình biên dịch sẽ báo lỗi. Nếu không có open annotation trên một hàm, giống như Base.nv(), khai báo một phương thức với cùng tên trong lớp con là bất hợp pháp dù là có ghi đè hoặc không ghi đè. Trong một final class (ví dụ một lớp không có open annotation), các thành viên open đều bị cấm.

Một thành viên được đánh dấu là ghi đè bản thân nó là open, tức là nó có thể được ghi đè trong các lớp con. Nếu bạn muốn ngăn cấm việc ghi đè, hãy sử dụng final:

open class AnotherDerived() : Base() {
    final override fun v() {}
}

Thuộc tính ghi đè

Ghi đè thuộc tính hoạt động tương tự như ghi đè phương thức; các thuộc tính được khai báo trên lớp cha và được khai báo lại trên một lớp con và có từ khóa overridephía trước. Mỗi một thuộc tính được khai báo có thể được ghi đè bởi một thuộc tính cùng với một initializer hoặc bởi một thuộc tính cùng với phương thức getter.

open class Foo {
    open val x: Int get() { ... }
}

class Bar1 : Foo() {
    override val x: Int = ...
}

Bạn có thể ghi đè một thuộc tính val với một thuộc tính var, nhưng không thể làm ngược lại. Có thể làm được vậy bởi vì thuộc tính var cơ bản khai báo một phương thức getter và ghi đè nó bằng var giống như là khai báo bổ sung một phương thức setter trong lớp con. Lưu ý, bạn có thể sử dụng từ khóa override như là một phần của khai báo thuộc tính trong constructor chính

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}

Lời gọi cài đặt lớp cha

Mã trong một lớp con có thể gọi các hàm lớp cha và có thể truy cập thuộc tính bằng từ khóa super

open class Foo {
    open fun f() { println("Foo.f()") }
    open val x: Int get() = 1
}

class Bar : Foo() {
    override fun f() { 
        super.f()
        println("Bar.f()") 
    }
    
    override val x: Int get() = super.x + 1
}

Bên trong một lớp inner, việc truy cập lớp cha của lớp outer được thực hiện cùng với từ khóa super cùng với tên của lớp outer super@Outer

class Bar : Foo() {
    override fun f() { /* ... */ }
    override val x: Int get() = 0
    
    inner class Baz {
        fun g() {
            super@Bar.f() // Calls Foo's implementation of f()
            println(super@Bar.x) // Uses Foo's implementation of x's getter
        }
    }
}

Quy tắc ghi đè

Trong kotlin, việc áp dụng kế thừa được áp dụng bởi các quy tắc sau: Nếu một lớp kế thừa nhiều implementation của cùng một member từ các lớp cha trực tiếp, nó phải ghi đè lên member này và cung cấp việc cài đặt của nó (có lẽ bằng cách thực hiện một trong những lớp kế thừa). Để hiển thị supertype mà từ đó việc kế thừa được thực hiện, chúng ta sử dụng super cùng với tên supertype trong dấu ngoặc nhọn super<Base>

open class A {
    open fun f() { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } // interface members are 'open' by default
    fun b() { print("b") }
}

class C() : A(), B {
    // The compiler requires f() to be overridden:
    override fun f() {
        super<A>.f() // call to A.f()
        super<B>.f() // call to B.f()
    }
}

Không có vấn đề gì khi kế thừa cả A và B, cũng không có vấn đề gì với hàm a(), b() khi mà C kế thừa chỉ một implementation với mỗi một hàm này. Nhưng đối với f(), chúng ta có 2 implementation được thực hiện kế thừa bời C, do đó chúng ta phải ghi đè f() trong C và cung cấp own implementation để tránh sự mơ hồ.

Lớp trừu tượng

Một lớp và một số member của nó có thể được khai báo là trừu tượng. Một member trừu tượng không có một implementation trong lớp của nó. Chú ý rằng chúng ta không cần phải annotate một lớp hoặc một hàm trừu tượng với open – điều này sẽ tự động được thực hiện Chúng ta có thể ghi đè một open member không trừu tượng với một member trừu tượng

open class Base {
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

So sánh với các ngôn ngữ khác

Trong kotlin, không giống với java hay C#, các lớp không có phương thức static. Trong hầu hết các trường hợp, bạn chỉ nên sử dụng hàm ở mức package. Nếu bạn phải viết một hàm mà có thể được gọi mà không cần class instance nhưng cần truy cập vào các thành phần nội tại của một lớp (ví dụ như phương thức factory), bạn có thể viết nó như một member của một đối tượng declaration bên trong lớp đó. Cụ thể hơn, nếu bạn khai báo một đối tượng companion bên trong lớp của bạn, bạn có thể gọi các member của nó với các cú pháp giống như phương thức static trong Java/C#

Kết luận

Bài viết này mình dịch lại từ nguồn https://kotlinlang.org/docs/reference/classes.html Rất mong nhận được sự đóng ghóp của các bạn

Chi tiết

Gửi Email trong ứng dụng Rails

Giới thiệu

Ở bài viết này chúng ta sẽ làm một ứng dụng đơn giản để trình diễn việc gửi email với ActionMailer, ActionMailer Preview và thông qua một nhà cung cấp dịch vụ bên thứ ba như Gmail hoặc Mailgun. Chúng ta sẽ demo cách sử dụng Active job để gửi email cùng với background processor (tiến trình chạy ngầm).

 

 

Gửi mail sử dụng ActionMailer và Gmail

Bây giờ chúng ta sẽ xây dựng một ứng dụng rails để gửi email đến user khi một user mới được tạo

$ rails new new_app_name
$ rails g scaffold user name:string email:string
$ rake db:migrate

Bây giờ chúng ta đã có một ứng dụng cơ bản, chúng ta sẽ sử dụng ActionMailer. Việc tạo mới Mailer cũng tương tự như bất kỳ tạo mới nào trên rails.

$ rails g mailer example_mailer
create  app/mailers/example_mailer.rb
invoke  erb
create    app/views/example_mailer
invoke  test_unit
create    test/mailers/example_mailer_test.rb
create    test/mailers/previews/example_mailer_preview.rb

Ứng dụng mà chúng ta đang sử dụng là bản Rails 4.2.0.beta4 do đó khi tạo mailer thì ứng dụng có tự động tạo ra một file test là example_mailer_preview.rb đặt trong thư mục previews, để sau này có thể được sử dụng

Trong file app/mailers/example_mailer.rb

class ExampleMailer < ActionMailer::Base
  default from: "from@example.com"
end

Bây giờ chúng ta sẽ viết ra một phương thức và customized email. Trước tiên, bạn nên thay đổi địa chỉ gửi mail mặc định từ from@example.com thành địa chỉ mail mà bạn muốn gửi đi (hay còn gọi là sender’s address).

class ExampleMailer < ActionMailer::Base
  default from: "from@example.com"

  def sample_email user
    @user = user
    mail to: @user.email, subject: "Sample Email"
  end
end

Phương thức sample_email lấy các parameter của user và gửi email sử dụng phương thức mail để gửi đến địa chỉ email của user. Trong trường hợp bạn muốn biết thêm về các tính năng như tập tin đính kèm hay là gửi cho nhiều email, bạn có thể xem hướng dẫn trong tài liệu tham khảo ở link bên dưới. Bây giờ chúng ta sẽ viết nội dung mail mà bạn muốn gửi đến cho user, tất cả đều được lưu trong thư mục app/views/example_mailer. Bạn tạo ra một file tên là sample_email.html.erb có định dạng chuẩn HTML

Trong file app/views/example_mailer/sample_email.html.erb

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h1>Hi <%= @user.name %></h1>
    <p>
      Sample mail sent using smtp.
    </p>
  </body>
</html>

Nếu chúng ta cần tạo ra dạng văn bản(cách dòng hoặc thụt vào đầu dòng) cho email thì bạn phải tạo ra file sample_email.text.erb thay cho file sample_email.html.erb trong thư mục app/views/example_mailer

Trong file app/views/example_mailer/sample_email.text.erb

Hi <%= @user.name %>
Sample mail sent using smtp.

Trong môi trường test, chúng ta sử dụng ActionMailer Preview để test ứng dụng của chúng ta. Chúng ta sẽ sử dụng test/mailers/previews/example_mailer_preview.rb để tạo ra các mailer. Chúng ta có thể gọi đến bất kỳ user nào (trong trường hợp này chỉ gọi đến user đầu tiên) để test các email.

# Test tất cả các email tại http://localhost:3000/rails/mailers/example_mailer
class ExampleMailerPreview < ActionMailer::Preview
  def sample_mail_preview
    ExampleMailer.sample_email(User.first)
  end
end

Khi bạn truy cập địa chỉ http://localhost:3000/rails/mailers/example_mailer/sample_mail_preview bạn sẽ nhìn thấy preview của email. Theo mặc định email previews sẽ được đặt trong test/mailers/previews. Bạn có thể thay đổi điều này bằng cách thiết lập một đường dẫn khác trong /config/environments/development.rb. Chỉ cần thiết lập config.action_mailer.preview_path đến đường dẫn mong muốn và thêm file preview vào vị trí tương ứng.

Gửi mail sử dụng ActionMailer và Gmail

Theo mặc định rails sẽ gửi email thông qua SMTP. Do đó chúng ta sẽ cấu hình SMTP trong cài đặ môi trường /config/environments/production.rb. Đầu tiên chúng ta sẽ nhìn thấy cấu hình này là để chạy gửi email của Gmail. Trước khi chúng ta lưu các thông tin nhạy cảm này như username và password trong biến mội trường. Chúng ta cần sử dụng gem figaro.

Trong file /config/application.yml

gmail_username: 'username@gmail.com'
gmail_password: 'Gmail password'

Trong file /config/environments/production.rb

config.action_mailer.delivery_method = :smtp
# SMTP settings for gmail
config.action_mailer.smtp_settings = {
 :address              => "smtp.gmail.com",
 :port                 => 587,
 :user_name            => ENV['gmail_username'],
 :password             => ENV['gmail_password'],
 :authentication       => "plain",
:enable_starttls_auto => true
}

Bây giờ chúng ta sẽ chỉnh sửa UsersController để gọi đến sự kiện gửi email cho user. Chúng ta cần thêm vào ExampleMailer.sample_email(@user).deliver cho phương thức tạo mới trong app/controllers/users_controller.rb. Phương thức tạo mới trong users_controller.rb như sau:

def create
  @user = User.new(user_params)

  respond_to do |format|
    if @user.save

      # Sends email to user when user is created.
      ExampleMailer.sample_email(@user).deliver

      format.html { redirect_to @user, notice: 'User was successfully created.' }
      format.json { render :show, status: :created, location: @user }
    else
      format.html { render :new }
      format.json { render json: @user.errors, status: :unprocessable_entity }
    end
  end
end

Khi một user mới được tạo ra, chúng ta sẽ gửi một email thông qua phương thức sample_email trong mailer ExampleMailer.

Gửi email cùng với Background Processor thông qua Active Job

Khi bạn kiểm tra các ứng dụng, bạn sẽ thấy rằng sẽ mất rất nhiều thời gian (lâu hơn so với bình thường) để tạo ra một user mới. Chuyện này xảy ra bởi vì chúng ta phải gọi đến một API bên ngoài để gửi email. Việc này sẽ trở thành vấn đề lớn nếu cùng một lúc bạn gửi đi nhiều email hoặc gửi email đến nhiều người dùng. Vấn đề này sẽ được dễ dàng giải quyết nếu bạn bỏ các email gửi đi vào background jobs. Trong ứng dụng của chúng ta, chúng ta sẽ sử dụng Active Jobs và Delayed Job để gửi những email trong background.

Active Jobs là một bộ chuyển đổi cung cấp giao diện tổng quát cho các xử lý background như Resque, Delayed Job, Sidekiq,..vv. Chú ý rằng sử dụng Active Job bạn sẽ cần phiên bản Rails 4.2 trở lên.

$ rails g job send_email
  invoke  test_unit
  create    test/jobs/send_email_job_test.rb
  create  app/jobs/send_email_job.rb

Bây giờ chúng ta sẽ viết ra job để thực hiện bởi workers. Active Job được tích hợp với ActionMailer do đó dễ dàng để gửi các email bất đồng bộ. Đối với việc gửi email qua Active Job chúng ta sử dụng phương thức deliver_later.

Trong file /app/jobs/send_email_job.rb

class SendEmailJob < ActiveJob::Base
  queue_as :default

  def perform user
    @user = user
    ExampleMailer.sample_email(@user).deliver_later
  end
end

Bây giờ chúng ta sẽ sửa đổi trong phương thức create khi tạo mới user. Thay vì việc gửi email luôn khi tạo user, chúng ta sẽ đưa email vào hàng đợi(enqueue) và gọi đến hàm perform sau đó.

Trong file app/controllers/users_controller.rb


def create
  ...
  SendEmailJob.set(wait: 20.seconds).perform_later(@user)
  ....
end

Bây giờ chúng ta cần cấu hình backend cho tiến trình background của chúng ta. Chúng ta lựa chọn delayed_jobs để quản lý backend nhưng bạn cũng có thể lựa chọn backend của bạn nếu bạn muốn. Active Job có nhiều built-in adapter cho nhiều hàng đợi của backend.

Trong file Gemfile

gem 'delayed_job_active_record'
$ bundle
$ rails generate delayed_job:active_record
$ rake db:migrate

Thiết lập hàng đợi backend cho môi trường production

Trong file /config/environments/production.rb

config.active_job.queue_adapter = :delayed_job

Bây giờ tất cả mọi thứ đã được cấu hình, để test cho ứng dụng bạn vào tạo mới user. Một job mới sẽ được thêm vào hàng đợi và bạn sẽ nhận thấy thời gian cần thiết để tạo mới một user đã giảm đáng kể. Bạn bắt đầu chạy các job trong hàng đợi bằng lệnh sau:

$ bundle exec rake jobs:work
Chi tiết

Các khái niệm cơ bản về Active Job

Bài viết chủ yếu giúp cho các bạn hiểu một cách đơn giản active job là gì?. Cách tạo, thực thi các công việc(jobs) chạy nền trong Ruby On Rails(RoR). Sau bài viết này bạn sẽ có thể:

1. Làm thế nào để tạo jobs.

2. Làm thế nào để sắp xếp các jobs.

3. Làm thế nào để chạy jobs ở backgound (chạy nền, chạy ngầm).

4. Làm thế nào gửi mail từ ứng dụng sử dụng active job.

I. Giới thiệu

Active Jobs là một framework cho việc thiết lập các jobs và làm chúng có thể chạy trên nhiều backends. Hiểu đơn giản hơn là nó sẽ tạo ra 1 luồng riêng giống trong Java để thực hiện một công việc khác mà không ảnh hưởng đến luồng chính. Điều đó làm tăng trải nghiệm người dùng. Những jobs chủ yếu ở đây là việc đặt lịch dọn dẹp rác, hay việc tính toán phí hoặc gửi mail. Mọi thứ có thể được chia thành các phần nhỏ hơn của công việc để chạy song song. Điều đó có thể giúp tăng tốc độ hệ thống lên rất nhiều thay vì chạy theo cách truyền thống.

II. Mục đích của Active Jobs

Mục đích chính là để đảm bảo rằng tất cả các ứng ụng Rails sẽ có một cơ sở hạ tầng thích hợp. Chúng ta có thể sau đó có các đặc điểm framework và các gem khác được xây trên nền tảng đó mà không phải lo lắng về sự khác nhau API giữa các job chạy ví dụ như Delayed Job và Resque.

III. Việc tạo một job

Trong phần này sẽ cung cấp một hướng dẫn chi tiết để tạo một job và sắp xếp nó trong hàng đợi.

1. Tạo job

Active Job cung cấp một Rails generator để tạo các jobs. Đoạn code dưới đây sẽ tạo một job trong thư mục app/jobs:

bin/rails generate job guests_cleanup
invoke  test_unit
create    test/jobs/guests_cleanup_job_test.rb
create  app/jobs/guests_cleanup_job.rb

Bạn cũng có thể tạo một job mà sẽ chạy trên một hàng cụ thể qua câu lệnh:

bin/rails generate job guests_cleanup --queue urgent

Nếu bạ không muốn sử dụng một generator, bạn có thể tạo tự tạo file của mình trong thư mục app/jobs, và đảm bảo rằng class bạn tạo kế thừa từ ApplicationJob

Đây là đoạn code một job trông thế nào:

class GuestsCleanupJob < ApplicationJob
  queue_as :default

  def perform(*guests)
    # Do something later
  end
end

Lưu ý rằng bạn có thể định nghĩa perform với bao nhiêu arguments mà bạn muốn.

2. Đặt thứ tự Job

Đặt thứ tự một job giống như:

# Đặt thứ tự một job được thi hành ngay khi hệ thống hàng đợi trống.

GuestsCleanupJob.perform_later guest
# Đặt thứ tự một job được thi hành vào buổi chiều hôm sau.

GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest)
# Đặt thứ tự một job đucojw thi hành sau 1 tuần kể từ bây giờ.

GuestsCleanupJob.set(wait: 1.week).perform_later(guest)
# `perform_now` và `perform_later` sẽ gọi `perform` nên bạn có thể truyền các arguments mà được định nghĩa sau đó.

GuestsCleanupJob.perform_later(guest1, guest2, filter: 'some_filter')

Tất cả đơn giản chỉ có vậy thôi.

IV. Thực thi Job

Cho việc đặt tứ tự và thực thi các job trong production bạn cần cài đặt một backend queuing. Rails chỉ cung cấp một tiến trình hệ thống hàng đợi mà chỉ giữ các jobs trong RAM. nếu mà tiến trình mà bị lỗi hoặc hệ thống sẽ bị reset thì tất cả các jobs sẽ bị mất với sự mặc định không đồng bộ với back-end. Điều này có lẽ là ổn đối với những app nhỏ hoặc với các jobs không quan trọng nhưng phần lớn các app production sẽ cần một backend ổn định.

1. Backends

Active Job có các adapter tích hợp cho đa dạng các queuing backend như(Sidekiq, Resque, Delayed Job, …). Để có một danh sách cập nhật của các adapters bạn có thể xem tài liệu API bên dưới ActiveJob::QueueAdapters.

2. Cài đặt Backend

Bạn có thể dễ dàng cài đặt queing backend như sau:

# config/application.rb
module YourApp
  class Application < Rails::Application
    # Be sure to have the adapter's gem in your Gemfile
    # and follow the adapter's specific installation
    # and deployment instructions.
    config.active_job.queue_adapter = :sidekiq
  end
end

Bạn cũng có thể cấu hình backend của bạn trên một nền tảng job.

class GuestsCleanupJob < ApplicationJob
  self.queue_adapter = :resque
  #....
end

# Now your job will use `resque` as it's backend queue adapter overriding what
# was configured in `config.active_job.queue_adapter`.

3. Start Backend

Khi các jobs chạy song song với ứng dụng Rails, phần lớn các thư việc cần bạn start một queing service cụ thể cho tiến trình job để họat động. Tham khảo các tài liệu thư viện chó sự hướng dẫn để start queue backend.

Dưới đây là một danh sách các tài liệu

V. Queues

Phầnlonws các adapter hỗ trợ cho đa dạng các queues. Với Active Job bạn có thể đặt lịch job để chạy trên một queue cụ thể.

class GuestsCleanupJob < ApplicationJob
  queue_as :low_priority
  #....
end

Bạn có thể thêm vào đầu tên queue cho tất các jobs của bạn mà sử dụng config.active_job.quêu_name_prefix in application.rb:

# config/application.rb
module YourApp
  class Application < Rails::Application
    config.active_job.queue_name_prefix = Rails.env
  end
end

# app/jobs/guests_cleanup_job.rb
class GuestsCleanupJob < ApplicationJob
  queue_as :low_priority
  #....
end

# Now your job will run on queue production_low_priority on your
# production environment and on staging_low_priority
# on your staging environment

Tiền tố tên mặc định dầu trước là ‘_’. Điều này có thể được thay đổi bằng việc cài đặt config.active_job.queue_name_delimiter trong application.rb

# config/application.rb
module YourApp
  class Application < Rails::Application
    config.active_job.queue_name_prefix = Rails.env
    config.active_job.queue_name_delimiter = '.'
  end
end

# app/jobs/guests_cleanup_job.rb
class GuestsCleanupJob < ApplicationJob
  queue_as :low_priority
  #....
end

# Now your job will run on queue production.low_priority on your
# production environment and on staging.low_priority
# on your staging environment

Nếu bạn muốn điều khiển queue nào một job được chạy thì ban có thể truyền một :queue với lựa chọn #set:

MyJob.set(queue: :another_queue).perform_later(record)

Để control queue từ vị trí job bạn có thẻ truyền một block #queue_as. Block sẽ được thực thi:

class ProcessVideoJob < ApplicationJob
  queue_as do
    video = self.arguments.first
    if video.owner.premium?
      :premium_videojobs
    else
      :videojobs
    end
  end

  def perform(video)
    # Do process video
  end
end

ProcessVideoJob.perform_later(Video.last)

VI. Kết luận

Bài này chủ yếu nhằm mục đích giới thiệu và hướng dẫn cách sử dụng cơ bản nhất về Active Job trong các ứng dụng Ruby On Rails để giúp tăng tốc độ thực thi của ứng dụng và nâng cao trải nghiệm người dùng.

Chi tiết

Xây dựng bản đồ Wifi thành phố với Raspi 3

Bài viết này sẽ đi sâu vào việc setup các thiết bị phần cứng để phục vụ cho mục đích xây dựng bản đồ Wi-fi thành phố.

Trước khi bắt tay vào làm việc, hãy check qua kết quả của project này – chính là bản đồ Wi-Fi của tác giả xây dựng.

wardriving 1
Các Access Point hiển thị trên Google Maps

 

wardriving 2
… và trên Google Earth

#1 Chuẩn bị

Có 3 thiết bị chính: Raspi 3, card wifi và ăng-ten GPS

 

Đầu tiên, chúng ta cần Raspi 3.

raspi 3

Raspi 3 làm một máy tính Mini, thiết kế và chế tạo ở nước Anh thần thánh. Pi 3 có vi xử lý lõi tứ 1.2 Ghz, 1Gb RAM, tích hợp Wifi, bluetooth BLE, 4 cổng USB và ngõ Ethernet, kèm theo đó là 40 chân GPIO. Pi3 đủ sức chạy Linux hoặc Window IoT core hay thậm chí là Kali Linux.

Nếu bạn chưa biết Raspi 3 là gì, bạn đang lạc hậu đó! Hãy cập nhật ngay lập tức.

 

Tiếp theo ta cần chuẩn bị là một card wifi kết nối USB.

Ta có thể dùng card wifi tích hợp trên Pi3, tuy nhiên để thoải mái hơn trong việc sắp đặt vị trí và bắt được tín hiệu ổn định hơn, ta nên dùng một card wifi rời có ăng-ten (râu). Tác giả Scott sử dụng mẫu Alfa Network AWUS036NHA.

wifi card

Một thiết bị nữa cần quan tâm, đó là ăng-ten GPS. Pi3 không tích hợp linh kiện phục vụ cho GPS, do đó, ta cần một ăng-ten GPS kết nối USB.

Ăng-ten GPS này giúp ta xác định vị trí chính xác của mạng Wi-fi tìm được, nhờ đó, ta mới có thể xây dựng bản đồ Wi-fi có độ chính xác cao và đồng bộ danh sách các Access point chúng ta dò quét được với Google Map.

Scott sử dụng mẫu ăng-ten GlobalSat BU-353-S4

GPS

 

#2 Setup

Sau khi đã thu thập đủ các thiết bị phù hợp, đầu tiên hãy đảm bảo rằng Raspi 3 của bạn đã có hệ điều hành.

Cách đơn giản nhất để cài hệ điều hành cho Pi3 là làm theo hướng dẫn trên raspberrypi.org. Project lần này của chúng ta không quá phức tạp, do đó hệ điều hành Raspbian hoàn toàn có thể đáp ứng được.

Sau khi cài Raspbian cho Pi3, nhớ update nó.

sudo apt-get update
sudo apt-get upgrade -y

Sau khi update, chúng ta bắt đầu cài các package phục vụ cho dự án này, có tất cả 8 package:

sudo apt-get install -y screen gpsd libncurses5-dev libpcap-dev tcpdump libnl-dev gpsd-clients python-gps

Tiếp theo, chúng ta config gpsd. Hãy dùng một text editor để mở file gpsd theo đường dẫn /etc/default/gpsd

START_DAEMON="true"
GPSD_OPTIONS="-n"
DEVICES="/dev/ttyUSB0" 
USBAUTO="true"
GPSD_SOCKET="/var/run/gpsd.sock"

Để ý dòng DEVICES=”/dev/ttyUSB0″ nhé, chắc gì cái ăng-ten GPS ở trên kia đã cắm đúng vào cổng usb mang số hiệu USB0? Để kiểm tra xem ăng-ten GPS được cắm vào cổng USB nào, hãy tải đoạn script sau:

wget https://gist.githubusercontent.com/ScottHelme/e793516d2b322ed3a4c795a429eb5d04/raw/5829f33d29182aa92b79bcb7e76e71ab51c8fe1b/find.sh

…và chạy nó:

chmod +x find.sh


./find.sh

Sau khi chạy, đoạn script sẽ đưa ra một output có dạng:

pi@raspberrypi:~ $ ./find.sh
/dev/ttyUSB0 - Prolific_Technology_Inc._USB-Serial_Controller_D

Ở ví dụ này, ăng-ten GPS được cắm vào cổng USB số hiệu USB0. Như vậy, tôi không phải sửa file gpsd ở trên. Nếu của bạn có output khác, hãy sửa giá trị DEVICES giống như output bạn nhận được.

 

Mọi thứ đã sẵn sàng chưa? Chưa đâu. Còn một thứ quan trọng nhất, đó là Kismet. Hãy cài Kismet trước khi bước ra khỏi cửa:

wget http://www.kismetwireless.net/code/kismet-2016-07-R1.tar.xz
tar -xvf kismet-2016-07-R1.tar.xz
cd kismet-2016-07-R1/
./configure
make dep
make
sudo make install

Sau khi cài Kismat, chúng ta config nó thông qua file kismet.conf nằm ở đường dẫn /usr/local/etc/kismet.confNhư thường lệ, hãy mở nó bằng một text editor.

sudo gedit /usr/local/etc/kismet.conf

hoặc

sudo leafpad /usr/local/etc/kismet.conf

Bước đầu tiên khi config Kismet là lựa chọn card wifi làm việc với Kismet.

Tìm dòng # ncsource=wlan0…

Bỏ dấu hashtag – dấu #, và thay tên wlan0 bằng tên của interface đại diện cho card wifi USB ở trên. Để biết được interface nào đại diện cho card wifi USB, interface nào đại diện cho cạc wifi on-board, hãy dùng lệnh ifconfig

Sau khi config interface sẽ làm việc với Kismet, ta config tiếp phần đầu ra cho log file. Thông thường Kismet sẽ log ra khá nhiều thông tin “thừa”. Như vậy, chúng ta cần hạn chế bớt đầu ra như sau:

Ban đầu là như này:

logtypes=pcapdump,gpsxml,netxml,nettxt,alert

Chúng ta sẽ rút gọn còn như này:

logtypes=gpsxml,netxml

Như vậy, đầu ra của kismet chỉ gói gọn trong 2 định dạng là *.gspxml và *.netxml

Okay, vậy là chúng ta đã hoàn thành việc setup.

 

#3 Kiểm tra tín hiệu GPS

Với tín hiệu GPS, hãy chắc chắn rằng ăng-ten GPS của bạn không bị che khuất bởi … trần nhà.

gps

gps 2

Tác giả ốp Pi3 với ăng-ten GPS thành 1 khối và gắn nó lên cửa sổ xe hơi, nhờ vậy, ăng-ten GPS không bị che khuất.

Bây giờ, hãy kiểm tra ăng-ten GPS này trên Terminal của Pi3 bằng một lệnh đơn giản:

cgps

Lệnh này sẽ khởi động một test client của gpsd (ta đã cài gpsd ở bước #2). Có thể bạn sẽ mất vài phút để nhận được kết quả.

gps 3
Kết quả của tác giả – đã bị che mất phần Latitude và Longitude

Nếu bạn không thể nhận được kết quả test, hãy thử restart lại gpsd và đứng im trong 1 phút.

 

#4 Thiết lập IP tĩnh

Hiện tại thì Pi3 sẽ nhận được địa chỉ IP từ DHCP server của bất kỳ mạng nào mà nó đang kết nối tới. Tuy nhiên khi bạn cần kết nối Pi3 với Laptop để remote access thì sao?

Hãy mở dhcpd.conf và paste đoạn config sau vào cuối file.

interface eth0
static ip_address=192.168.1.5/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

Sau khi config xong, reboot lại Pi3.

 

#5 Chạy thử

Kismet sẽ xuất toàn bộ dữ liệu thu được ra một các files. ta có thể chọn vị trí để lưu chúng.

mkdir ~/testrun
cd ~/testrun

Thư mục testrun bây giờ sẽ lưu toàn bộ file output của Kismet, bây giờ, ta khởi chạy nó.

sudo kismet

Hãy tích vào ô “auto start Kismet Server” và bỏ tích ở ô “Show Console on the second prompt”, sau đó ấn Start.

kismet 1

kismet 2

Khi Kismet khởi động, sau một vài giây, bạn sẽ thấy giao diện sau:

kismet 3

Như vậy, kismet đang capture. Ở trung tâm màn hình, bạn có thể thấy thông tin về tọa độ GPS (tác giả đã che đi tọa độ của mình). Trong cột bên phải, bạn thấy được số lượng các mạng Wi-Fi đang bao quanh mình, hãy đợi thêm một vài phút và Kismet sẽ thu thập dữ liệu đủ nhiều để phân tích.

kismet 4

Sau vài phút, ta tắt Kismet và Kill server.

kismet 5

Một khi Kismet đã thoát, dữ liệu được lưu vào các file output nằm ngay tại folder lúc nãy ta khởi chạy Kismet. Bạn sẽ thấy có 2 file XML. Đây chính là 2 output được chúng ta giới hạn trong phần #2.

ls

Kismet-20160808-21-40-31-1.gpsxml
Kismet-20160808-21-40-31-1.netxml

Đây chỉ là dữ liệu thô, hãy xào nấu chúng thành những món ăn hoàn chỉnh.

 

#6 Export ra Google Maps

Để biến 2 nguyên liệu thô ở trên thành các món ăn hoàn chỉnh, chúng ta cần sự trợ giúp của một đoạn script mang tên netxml2kml.

wget https://gist.githubusercontent.com/ScottHelme/5c6869e17c3e9c8b2034dc8fc13e180b/raw/31c2d34f66748b6bd26415fd7d120c06b3d92eaf/netxml2kml.py -O netxml2kml.py

Đoạn script này được viết bằng python. Chúng ta sẽ chạy nó để convert từ xml ra kml và upload các file kml lên Google Maps.

python netxml2kml.py --kml -o output *xml

kết quả: 

Parser: Kismet-20160808-21-40-31-1.gpsxml, 0 new, 0 old
Parser: Kismet-20160808-21-40-31-1.netxml, 38 new, 0 old
Outputfile: output.*

KML export...
WPA     24
WEP     0
None    8
Other   6
Done. 38 networks

Kết quả đã được convert sang file output.kml. Ta có thể upload file này lên Google Maps.

Như vậy chúng ta đã hoàn thành việc cấu hình cũng như kiểm tra khả năng hoạt động của các thiết bị. Tuy nhiên, cuộc vui mới chỉ bắt đầu…

 

#7 Wardriving

Có lẽ vấn đề lớn nhất của giai đoạn này là NĂNG LƯỢNG. Chúng ta cần năng lượng để duy trì Raspi 3 đồng thời gánh thêm 2 thiết bị ngoại vi là card wifi và ăng-ten GPS. Có 2 cách để duy trì năng lượng là sử dụng pin và sử dụng đầu châm thuốc trên xe hơi.

pi 3

Tác giả gắn một cục pin 50.000mAh. Cục pin này đủ dùng cho Pi 3 trong 1 ngày đi bộ.

Khi bạn sử dụng xe hơi, hãy dùng adapter và cắm thẳng vào đầu châm thuốc trên xe.

Một vấn đề nho nhỏ, khi bạn remote access Pi 3 từ laptop thông qua SSH và chạy Kismet, nếu bạn ngắt kết nối SSH, Kismet sẽ bị đóng lại. Và chúng ta cần một công cụ hỗ trợ là Screen.

Screen là một công cụ cho phép mở nhiều shell, mỗi shell chạy một chương trình. Và quan trọng hơn hết, với Screen, khi bạn ngắt SSH, Screen session vẫn tiếp tục duy trì, nhờ đó, Kismet vẫn tiếp tục hoạt động.

Với Screen, ta khởi động một session lấy tên là kismet.

screen -S kismet

Trong session này, ta khởi chạy Kismet

sudo kismet

 

Khi kismet đã chạy, ta có thể nhảy ra khỏi session này bằng cách nhấn Ctrl+A, sau đó chọn D. D là viết tắc của detach.

Để kiểm tra session kismet vẫn chạy bình thường, ta gõ lệnh:

screen -ls

kết quả:
There is a screen on:
4121.kismet (Detached)
1 Socket in /var/folders/6m/xpnz0lp176n2mn/T/.screen.

Sau khi nhảy ra khỏi session kismet, ta hoàn toàn có thể quay lại nó bằng cách:

screen -r kismet

 

Như vậy, với screen, ta có thể chạy kismet, sau đó ngắt kết nối giữa Pi3 và Laptop rồi mang Pi 3 cùng với 2 phụ kiện còn lại đi dạo quanh thành phố….

 

Hãy chia sẻ kết quả của các bạn ở phần comment. Xin cảm ơn!

Tác giả: https://scotthelme.co.uk/wifi-wardriving/

Chi tiết

Lập trình iOS trên Cross-PlatForm Framework Xamarin

Khi tạo ứng dụng iOS, lập trình viên thường sử dụng ngôn ngữ Objective-C hoặc Swift cùng với IDE do apple cung cấp. Tuy nhiên nó không phải là lựa chọn duy nhất, bạn có thể tạo các ứng dụng iOS sử dụng nhiều công cụ cũng như ngôn ngữ khác.

Một trong những sự lựa chọn được nhiều người biết đến là Xamarin, nó một framework đa nền tảng, nó cho phép bạn phát phiển ứng dụng iOS, Android, OS X và Windows sử dụng C# và Visual Studio. Lợi ích lớn nhất mà Xamarin đem lại là nó có thể cho phép bạn chia sẻ code giữa iOS và Android app.

Với Xamarin, ứng dụng của bạn biên dịch sang mã native. Có nghĩa là một app Xamarin nên được phân biệt với một app khác được lập trình bằng Xcode.

Nhập môn

Để phát triển một iOS app với Xamarin and Visual Studio, bạn có cần:

1)Một máy cài Windows để chạy Visual Studio.

2)Một máy Mac và cài đặt Xcode để thực hiện một số thao tác như xây dụng một host, để khi lập trình thì nó cho phép truy cập để phát triển và test từ máy cài windows.

 

Cài đặt Xcode và Xamarin

Đây là link download trên Mac. Sau khi cài Xcode, download Xamarin Studio và cài đặt. Bạn nhớ chọn Xamarin.iOS.

Cài đặt Visual Studio và Xamarin

Bài thường dẫn này sử dụng bất kỳ version nào của Visual Studio, download visual studio và cài đặt. Bạn cần chú ý khi cài đặt ở danh sách các chức năng, phần mở rồng Coss Playform Mobile Development nhớ chọn C#/.NET(Xamarin v4.0.3).

Chọn Next và chờ cho nó cài xong. Nếu đã cài đặt xong Visual Studio nhưng chưa có Xamarin, vào Programs and Features/ Change/Modify.

Chọn C#/.NET(Xamarin v4.0.3)  ở dưới Cross Playform Mobile Development là chọn nó rồi sau đó ấn Update để bắt đầu cài đặt.

Tạo ứng dụng

Mở Visual Studio và chọn File\New\Project, chú ý là phần mở rộng chọn iOS/iPhone và chọn Single View App. Nó sẽ tạo một view controller để có thể viết các đoạn mã.

Với Name và Solution Name, đặt tên ImageLocation. Chọn một đường dẫn trên máy của bạn để lưu app và chọn OK.

Visual Studio sẽ thông báo cho bạn để chuẩn bị cho việc Xamarin cài đặt host:

  1. Bât Mac, mở System Preferences và chọn Sharing.
  2. Bật Remote Login.
  3. Thay đổi Allow access thành Only these users.
  4. Sau đó tắt đi và quay lại Windows.

Quay lại với Visual Studio, bạn sẽ được yêu cầu chọn Mac như host. Chọn máy Mac của bạn sau đó ấn Connect. Điền tài khoản và mật khẩu sau đó click Login.

Để chắc chắn bạn cho thể xem trên thanh toolbar, iPhoneSimulator mặc định được chọn nhưng bạn cũng có thể thay đổi thiết bị giả lập.

Ấn vào nút xanh như dưới đây để chạy.

Ứng dụng sẽ chạy nhưng bạn sẽ không thấy nó chạy trên Windows đấy cũng là lý do tại sao phải sử dụng 2 thiết bị. Trong đó Mac đóng vai trò như là host máy windows sẽ kết nối đến nếu bạn thấy similator chạy và hiển thị lên như sau thì đã thành công rồi đó.

Tạo Collection View

Ví dụ này sẽ hiển thị các ảnh để người dùng có thể chọn vậy chúng ta sẽ sử dụng Collection View, nó là một đối tượng của iOS để hiển thị nhiều đối tượng dưới dạng lưới.

Để chỉnh sửa storyboard(nó chưa các màn hình của app), open Main.storyboard ở Solution Explorer.

Mở Toolbox và gõ collection vào đó để tìm kiếm danh sách của đối tượng. Ở dưới Data Views, kéo Collection View từ toolbox vào giữa của view như sau:

Chọn collection view, khi chọn đúng thì bạn sẽ thấy cái đường viền của đối tượng.

Tiếp theo chúng ta layout cho collection view để khi thay đổi kich cớ màn hình thì nó cũng sẽ tự động thay đổi. Ở phía trên có thanh toolbar bạn ấn vào cái dấu cộng màu xanh để có thể tự động tạo ràng buộc cho đối tượng.

Thông thường thì các ràng buộc thường đúng, nhưng bạn cần chỉnh sử lại một chút. Ở cửa xổ các thuộc tính, đổi sang mục Layout và kéo xuống dưới đến mục Constraints.

Ở đây có 2 contraints ở trên cùng là xác định toạ độ X, Y là đúng nhưng 2 contraints về Width và Height thì chưa chuẩn. Để xoá thì ấn vào nút X.

Chú ý: Bạn sẽ thấy quanh đối tượng collectionview có viền màu cam. Đây chỉ là một thông báo cần phải sửa.

Chọn collectionview, nếu bạn thấy các vòng tròn như trước đấy, ấn lại vào nó để thay đổi các icons để thành T shapes màu xanh, tiếp theo các bạn tạo ràng buộc top, left,… để có thể có rành buộc về width, height bài này có nhiều cách. Sau khi hoàn thành phần constraint thì nó sẽ như sau, nếu bàn nào đã biết về lập trình iOS thì phần này cũng không khác nhiều khi làm trên Xcode.

 

Làm việc với CollectionView Cell

Để cấu hình kích thước cho cell, properties/Collection View Size ở đây các bạn có thể thay đổi chiều dài và cao bài này tôi để 100, 100.

Tiếp theo, chọn vòng tròn đỏ ở collection view, một pop-up sẽ thông báo bạn chưa gán định danh cho cell, bạn chọn vào cell và đặt identifier cho nó như sau.

Để thay đôi màu nền thì kéo xuống dưới và chọn màu muốn thay đổi.

Sau khi thay đổi thì nó sẽ như sau:

Ở bên mục Widget bạn kéo lên trên và gán class là PhotoCollectionImageCell

Visual Studio sẽ tự động tạo một class với tên đó và được kết thừa từ UICollectionviewCell, và tạo PhotoCollectionImageCell.cs.

Tạo dữ liệu cho CollectionView

Bạn cần tạo bằng tay class được kế thừa từ UICollectionViewDataSource để cung cấp dữ liệu cho collection view.

Ấn chuột phải vào ImageLocation ở Solution Explorer -> Add\Class đặt tên là: PhotoCollectionDataSource.cs và ấn Add.

Mở file vừa tạo và thêm đoạn mã sau:

using UIKit;

Cho phép sử dụng framework UIKit

Định nghĩa lại class như sau:

public class PhotoCollectionDataSource : UICollectionViewDataSource
{
}

Hãy nhớ cái định danh bạn đặt cho cell ở trên vì dưới đây phải sử dụng để nó để có thể tạo cell. Thêm các đoạn mã sau:

private static readonly string photoCellIdentifier = "ImageCellIdentifier";

Lớp UIColectionViewDataSource chứa 2 phương thức phải khai báo đó là:

public override UICollectionViewCell GetCell(UICollectionView collectionView, 
    NSIndexPath indexPath)
{
    var imageCell = collectionView.DequeueReusableCell(photoCellIdentifier, indexPath)
       as PhotoCollectionImageCell;
 
    return imageCell;
}
 
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
    return 7;
}

GetCell() cũng giống như cellforrowAtIndexPath bên obj-c, swift.

Tương tư như các phương thực khác cũng có thể suy ra như trên.

Tiếp theo bạn cần tạo ãnh xạ từ ViewController đến CollectionView(cũng tương tự như Xcode). Chọn Main.storyboard -> Widget điền tên collectionView vào phần định danh

Visuak Studio sẽ tự động một biến đại diện cho ViewController

Chú ý: Bạn sẽ không thấy biết đó cở ViewController.cs. Để thấy biến này, ấn vào bện trái của thánh điều hướng để có thể thấy ViewController.designer.cs. Nó chứa biến collectionView(visual studio tự động tạo ra).

Mở ViewController.cs ở tab Solution Explorer và thêm các trường sau:

private PhotoCollectionDataSource photoDataSource;

Cuối cùng thêm các đoạn mã sau vào ViewDidLoad()

photoDataSource = new PhotoCollectionDataSource();
collectionView.DataSource = photoDataSource;

Đoạn mã trên để tạo một biến có kiểu PhotoCollectionDataSource rồi sau đó gán biến đó cho DataSource của collectionView.

Bằng cách này photoDataSource sẽ cung cấp dữ liệu cho coleltionView.

Chạy xem thì bạn sẽ thấy nó hiển thị 7 hình vuông màu xanh.

Hiển thị các ảnh

Tiếp theo chúng ta sẽ sẽ hiển thị các ảnh lên CollectionView. Để bắt đầu bạn thêm một view để hiển thị một ảnh trên collection view. Ở mục Widget, kéo xuống và thay đổi màu nền thành mặc định.

Mở Toolbox, tìm Image View sau đó kéo một Image View lên collection view Cell.

Tối tượng image view sẽ khởi tạo to hơn cell, để chỉnh lại nó thì chọn nó, Properties\ Layout ở đây các bạn có thể chỉnh size cho nó.

Chuyển sang mục Widget ở phần identity đặt tên cellImageView. Visual Studio sẽ tự động tạo một trường tên cellImageView cho bạn.

Kéo lên phần View và thay đổi Mode thành Aspect Fill(giống như Xcode).

Để đảm bảo tính bảo mật thì tôi đã khai báo các trường không cho public để các classes khác không thể truy cập. Vậy chúng ta sẽ cần tạo hàm getter và setter.

Mở PhotoCollectionImageCell.cs và thêm phương thức sau:

public void SetImage(UIImage image)
{
    cellImageView.Image = image;
}

Tiếp theo chúng ta sẽ cập nhật các đoạn mã trong PhotoCollectionDataSource.cs:

using Photos;

Trường imageFetchResult sẽ chưa một danh sách các ảnh, bạn sẽ lấy các photos này qua đối tượng imageManager.

Mục tiêu của chúng ta đó la lấy dữ liệu sau đó cho vào phương thưc GetCell để nó hiển thị lên, vậy các bạn thêm các đoạn mã sau đây:

public PhotoCollectionDataSource()
{
    imageFetchResult = PHAsset.FetchAssets(PHAssetMediaType.Image, null);
    imageManager = new PHImageManager();
}

Hàm khởi tạo này lây ra danh sách tất cả các ảnh ở assets và gán vào imageFetchResult.

Tiếp theo tôi sử dụng Dispose đối tượng imageManager khi kết thúc việc thêm và thêm nó vào hàm destructor.

~PhotoCollectionDataSource()
{
    imageManager.Dispose();
}

Với 2 hàm GetItemsCount và GetCell thì sẽ trả về số lượng photos và ô cell.

public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
    return imageFetchResult.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, 
    NSIndexPath indexPath)
{
    var imageCell = collectionView.DequeueReusableCell(photoCellIdentifier, indexPath) 
        as PhotoCollectionImageCell;
 
    // 1
    var imageAsset = imageFetchResult[indexPath.Item] as PHAsset;
 
    // 2
    imageManager.RequestImageForAsset(imageAsset, 
        new CoreGraphics.CGSize(100.0, 100.0), PHImageContentMode.AspectFill,
        new PHImageRequestOptions(),
         // 3
         (UIImage image, NSDictionary info) =>
        {
           // 4
           imageCell.SetImage(image);
        });
 
    return imageCell;
}

Giải thích các phần trong hàm trên:

  1. Indexpath chứa một tham chiều đến item trong collection view. Để từ đó có thể hiển thị dữ liệu đúng vào ô với index đó.
  2. Sử dụng imageManager để lấy ra các ảnh của asset.
  3. Nếu bạn đã lập trình obj-c hoặc swift thì việc sử dụng các Api kèm theo block để xác định xem lúc nào method đấy hoàn tất thì cũng giống nhau thôi và RequestImageForAsset là một phương thức khi toàn thành thì sẽ trả về một block.
  4. Cối cùng lấy ảnh và gán cho cell thôi.

Chạy ứng dụng xem kêt quả, bạn sẽ thấy nó yêu cầu quyền truy cập ở lần đầu tiên chạy app.

Sau khi bạn ấn OK thì nó không hiện lên gì cả. Đừng buồn tiếp theo chúng ta sẽ giải quyết vấn đề đó.

 

Đăng ký khi cho phép truy cập vào Photos

Đầu tiên, bạn thêm phương thức vào class PhotoCollectionDataSource. Để có thể re-query khi ảnh thay đổi.

public void ReloadPhotos()
{
    imageFetchResult = PHAsset.FetchAssets(PHAssetMediaType.Image, null);
}

Tiếp theo mở ViewController.cs và thêm:

using Photos;

Sau đó thêm đoạn mã sau vào ViewDidLoad()

// 1
PHPhotoLibrary.SharedPhotoLibrary.RegisterChangeObserver((changeObserver) =>
{
    //2
    InvokeOnMainThread(() =>
    {
        // 3
        photoDataSource.ReloadPhotos();
        collectionView.ReloadData();
    });
});

Giải thích:

  1. Đăng ký một delegate để khi thư viện ảnh của thiết bị thay đổi thì nó sẽ thực hiện khối lệnh ở trong.
  2. InvokeOnMainThread() cũng giống như mainqueue thì để chắc chắn việc cập giao diện sử dụng thread 1.
  3. Gọi đến phương thức ReloadPhoto để reload  các photos từ data source và colelctionview.

 

Cuối cùng chỉ còn trường hợp khi người dùng không cho phép truy cập vào photos.

Thêm đoạn mã sau vào ViewDidLoad()

 

Đoạn mã trên kiểm tra trạng thái hiện tại nếu là NotDetermined thì bật lại hộp thoại để cho người dùng chọn.

Vậy bây giờ các bạn có thể chạy ứng dụng để xem ứng dụng đơn giản này đã chạy chưa.

Nguồn: www.raywenderlich.com

Chi tiết

ARKit: Tìm hiểu và sử dụng các đối tượng 3D

Ở phần tiếp theo này chúng ta sẽ cùng tìm hiểu:

  • Cách dùng tool để tạo ra đối tượng 3D

  • Sử dụng node với 3D object

  • Cách thêm ánh sáng

  • Cách thêm nhiều node 3D object

Cách tạo các đối tượng 3D?

  • Blender

  • Sketchup

  • Autodesk 3dsMax

  • Online: SketchFab, TurboSpuid, Blocks

Tạo project và setup camera như bài trước

Tạo một đổi tượng node 3d

Các bạn thêm đoạn mã sau:

func addPaperPlane(x: Float = 0, y: Float = 0, z: Float = -0.5) {
    guard let paperPlaneScene = SCNScene(named: "paperPlane.scn"), let paperPlaneNode = paperPlaneScene.rootNode.childNode(withName: "paperPlane", recursively: true) else { return }
    paperPlaneNode.position = SCNVector3(x, y, z)
    sceneView.scene.rootNode.addChildNode(paperPlaneNode)
}

Với đoạn mã trên đầu tiên tôi khởi tạo mộ đối tượng SCNScene với tên là paperPlan.scn.

Với các tham số thì như mình đã giải thích ở phần trươc nếu các bạn chưa đọc thì có thể quay lại tham khảo.

Các bạn build thì sẽ thấy có 1 cái hình màu tráng như sau:

Như các bạn thấy thì cái hình máy bay này khá là khó nhìn, vì nó đang thiếu phần đổ bóng và ánh sáng, bạn có thể mở đối tượng 3D này ra thì sẽ thấy nó chỉ là màu trắng.

Thêm ánh sáng cho đối tượng

Có nhiều cách để thêm ánh sáng vào một đối tượng 3D nhưng trong  bài này chúng ta sẽ sử dụng cách sau:

func configureLighting() {
    sceneView.autoenablesDefaultLighting = true
    sceneView.automaticallyUpdatesLighting = true
}

Ở hàm configureLighting():

  • Tôi đã set thuộc tính autoenablesDefaultLighting là true, nó có nghĩa là SceneKit sẽ tự động thêm ánh sáng vào scene, ARKit đã sử dụng các kỹ thuật ngầm để phân tích môi trường cho phép thêm ánh sáng sao cho phù hợp với các vật thể xung quanh.

  • Tiếp theo ở thuộc tính automaticallyUpdatesLighting tôi cũng set là true, thuộc tính này cho phép tự động cập nhật độ tương phải tính toán theo camera, bạn có thể set là false để thấy toàn bộ các lights.

Tiếp theo chúng ta cần gọi hàm configureLighting() ở viewDidLoad()

override func viewDidLoad() {
    super.viewDidLoad()
    configureLighting()
    addPaperPlane()
}

Bây giờ các bạn có thể build để thấy kết qủa.

Làm việc với các đối tượng 3D Node

Ở dưới đây tôi sẽ sử dụng đối tượng Car nó chưa nhiều 3D notes.

Cũng giống như hàm addPaper thì tôi sẽ tạo hàm addCar như sau:

func addCar(x: Float = 0, y: Float = 0, z: Float = -0.5) {
    guard let carScene = SCNScene(named: "car.dae") else { return }
    let carNode = SCNNode()
    let carSceneChildNodes = carScene.rootNode.childNodes
        
    for childNode in carSceneChildNodes {
        carNode.addChildNode(childNode)
    }
        
    carNode.position = SCNVector3(x, y, z)
    carNode.scale = SCNVector3(0.5, 0.5, 0.5)
    sceneView.scene.rootNode.addChildNode(carNode)
}

Cũng giống như phần addPlane ở đây chỉ thêm mỗi phần chúng ta lấy toàn bộ nodes ra rồi dùng method addChildNode. Bây giờ chúng ta sẽ gọi hàm addCar() xem điều gì xảy ra.

Vậy là bài này đã kết thúc, chúng ta sẽ tìm hiểu thêm về ARKit trong các phần sau.

Bởi Techmaster Team 

Chi tiết

30 Câu hỏi phỏng vấn hại não nhất của Apple

Một ngày đẹp trời bạn được mời đến văn phòng Apple để chuẩn bị cho buổi phỏng vấn thử việc. Và hàng tá câu hỏi “không có lời giải” đập vào mặt bạn. Liệu bạn có bị nhấn chìm trong đó?

Đây là danh sách 30 câu hỏi phỏng vấn hóc búa nhất của Apple được chúng tôi sắp xếp không theo một thứ tự nào cả. Đơn giản bởi câu hỏi nào cũng là một thử thách thực sự.

Steve Jobs

#1

“Nếu bạn có 2 quả trứng và bạn cần biết độ cao tối đa có thể thả trứng mà không làm vỡ nó thì bạn sẽ làm thế nào? Hãy đưa ra lời giải tối ưu.”

Vị trí Sofware Engineering

#2

“Giải thích cho một đứa trẻ 8 tuổi để nó hiểu được khái niệm và chức năng của router”

Vị trí Hỗ trợ khách hàng

#3

“Tự nghĩ ra và mô tả một vấn đề bạn cho là thú vị. Tìm lời giải cho nó”

Vị trí Sofware Engineering

#4

“Thống kê chi phí sản xuất chiếc bút máy bạn đang cầm”

Vị trí Quản lý xuất nhập khẩu

#5

Bạn có 100 đồng tiền xu xếp trên mặt bàn , 10 mặt ngửa, 90 mặt sấp. Bạn không có cách nào để biết được mặt sấp hoặc ngửa của mỗi đồng xu. Tìm cách để chia số đồng xu trên thành 2 cột sao cho mỗi phần có số đồng xu mặt ngửa bằng nhau.

Vị trí Sofware Engineering

coin

#6

“Ai là bạn thân nhất của anh/chị?”

Vị trí Chuyên gia tư vấn

#7

“Mỗi ngày có bao nhiêu đứa trẻ được sinh ra?”

Vị trí Quản lý xuất nhập khẩu

#8

“Hãy giới thiệu đôi lời về bản thân bạn. Điều gì làm bạn thích thú nhất?”

Vị trí Sofware Engineering

#9

Đây là câu hỏi tình huống: “bạn gặp một khách hàng đang rất giận dữ do anh ta yêu cầu tư vấn từ 20 phút trước nhưng không nhận được hồi âm, và anh ta đang làm loạn…”

Vị trí Hỗ trợ khách hàng

#10

“Bạn có thừa nhận rằng bạn là một người rất thông minh?”

Vị trí Kỹ sư phần cứng

#11

“Chúng tôi đánh giá cao sự tự tin của bạn. Thế nhưng ắt hẳn sẽ có lúc sự tự tin đó bị cướp đi mất? Bạn có đồng ý không?”

Vị trí Chuyên gia tư vấn

#12

“Có 3 hộp đựng hoa quả, 1 đựng táo, 1 đựng cam và 1 cái còn lại đựng cả 2 thứ quả. Chúng được dán nhãn sai. Bạn không được nhìn vào các hộp và chỉ được lấy ra 1 quả duy nhất từ cả 3 hộp. Hãy dán lại đúng nhãn của từng hộp”.

Vị trí Software QA

#13

“Bạn thích làm việc ở bộ phận nào?”

Senior Sofware Engineer

apple

#14

“Một khách hàng gọi cho bạn và than phiền rằng chiếc máy tính thân yêu của anh ta đã dính một lỗi bất đắc kỳ tử và bây giờ nó không khác gì cục sắt vụn. Bạn sẽ làm gì?”

Vị trí Hỗ trợ đường dây nóng

#15

“Bạn đã làm gì để thấy tự hào về bản thân?”

Vị trí Quản lý Team Software Engineering

#16

“Bạn có nghĩ rằng mình sáng tạo? Nếu đúng như vậy, hãy chứng minh cho chúng tôi đi”

Vị trí Software Engineering

#17

“Chúng tôi muốn nghe về những thất bại của bạn. Sau mỗi thất bại đó, bạn học được điều gì?”

Vị trí Quản trị phần mềm

#18

“Chỉ bằng giọng nói qua Voice Call, liệu bạn có thể giúp được khách hàng của mình? Hãy chứng minh điều đó”

Vị trí Hỗ trợ đường dây nóng

#19

“Ắt hẳn smartphone của bạn sẽ chưa những ứng dụng mà bạn yêu thích. Bạn đã bao giờ test chúng chưa? Nếu có hãy chia sẻ với chúng tôi”.

Vị trí Software QA

#20

Bạn đặt một cốc nước lên máy quay đĩa than, sau đó tăng dần tốc độ quay. Hiện tượng nào sẽ xảy ra đầu tiên: cái cốc bị trượt, cái cốc bị lộn nhào, nước bị sánh ra ngoài?

Vị trí Kỹ sư phần cứng

#21

“Bạn đã bác bỏ quyết định của cấp trên chưa? Bạn bác bỏ nó theo hướng nào? Có lẽ bạn nên kể một ví dụ cụ thể và trình bày kết quả cũng như cách khắc phục hậu quả của tình huống đó”

Vị trí Software Engineering

#22

“Câu hỏi này đơn giản thôi, hãy kể về một kỷ niệm làm bạn xấu hổ nhất”

Vị trí Chuyên gia tư vấn bán lẻ

apple store

#23

“Khi bạn thăm quan Apple Store trong vài trò là một khách hàng, bạn cảm thấy điều gì ấn tượng nhất?”

Vị trí Chuyên gia tư vấn bán lẻ

#24

“Apple đã đổi tên từ Apple Computer thành Apple Inc. Điều này 95% mọi người đều nghe. Nhưng lý do thì chỉ có 5% còn lại mới hiểu. Bạn có thuộc 5% đó không?”

#25

“Giữa 2 công việc: sáng tạo ra trải nghiệm người dùng tuyệt vời và giải quyết vấn đề của người dùng, việc nào quan trọng hơn?”

Vị trí Hỗ trợ đường dây nóng

#26

“Bạn có một lọ tiền xu thật và giả lẫn lộn. Tiền thật thì 1 mặt sấp 1 mặt ngửa, còn tiền giả thì 2 mặt sấp hoặc 2 mặt ngửa. Bạn lấy 1 đồng ra và xoay 3 lần. Tính xác suất đồng tiền đó là thật hay giả dựa vào kết quả vừa thu được”

Vị trí Chuyên gia phân tích thị trường

#27

“Chúng tôi có một app kiểu iTunes, nó lôi về quá nhiều hình ảnh và trong số đó, có nhưng ảnh chả bao giờ được dùng đến, bạn sẽ làm thế nào để tống khứ những tấm ảnh vô dụng đó đi?”

Vị trí Lập trình viên di động

Lập trình viên di động

#28

“Bạn hãy kể về 1 ngày tươi đẹp nhất và 1 ngày tồi tệ nhất của bạn trong 4 năm vừa qua”.

#29

“Đây là một câu hỏi rất phổ biến… Tại sao bạn lại đến với chúng tôi? Nếu Apple chọn bạn, bạn sẽ mất đi điều gì?”

Vị trí Software Engineering

#30

“Bạn kiểm tra một cái máy nướng bánh mỳ như thế nào?”

Vị trí Sofware QA

Tham khảo bài viết gốc tại fossbytes

Chi tiết

Bạn đang tìm kiếm thời gian để trở thành một lập trình viên tốt hơn?

Bài viết được dịch từ: https://medium.freecodecamp.com

Không có thời gian để làm mọi thứ. Ít nhất là đó là cái mà bạn cảm thấy? Không có thời gian để học tất cả những thứ mà bạn nghĩ là cần thiết để trở lên giỏi hơn. Không có thời gian để quay trở lại và refactor những phần code xấu xí. Nó làm việc và deadline đang đến gần. Không có thời gian để viết unit test cho tất cả. Không có thời gian để viết tài liệu hướng dẫn hoặc comment cho người tiếp theo, người sẽ bảo trì cái bạn đã viết. Không có thời gian để suy nghĩ. Không có thời gian để thở. Không có thời gian!

Vâng, nếu bạn dành thời gian để đọc bài viết này, Tôi hứa rằng bạn sẽ tìm thấy cho bản thân mình nhiều thời gian hơn, để dành cho những điều quan trọng.

Tôi đã từng nghĩ rằng cách duy nhất để trở thành một lập trình viên giỏi là làm việc cho đến khi mình bị ốm. Sức khỏe, tình bạn, và gia đình tôi tất cả đều bị ảnh hưởng. Hiểu được 5 sự thật về quản lý thời gian cho một lập trình viên đã cứu tôi.

1. Bạn không cần học mọi thứ mới theo một thứ tự nhất định.

Không có thắc mắc gì khi một lập trình viên giỏi luôn phải học, nhưng tập trung vào học cái gì lại có thể tạo ra một sự khác biệt lớn với lượng thời gian mà bạn bỏ ra.

Đầu tiên, đừng bị mắc lừa bởi các tiêu đề trên các blog công nghệ rằng cứ 37 giây trôi qua lại có một chuẩn mới được công bố. Hầu hết các công nghệ, framework, tính năng mới sẽ không bao giờ được sử dụng và bạn sẽ không bao giờ biết đến chúng. Vì rằng sẽ mất rất nhiều thời gian để chúng được sử dụng trong thực tế hơn là trong thế giới blog. Các công ty lớn đã đầu tư vào stack công nghệ của họ nhiều hơn so với các startup công nghệ nhỏ bé, họ không mạo hiểm kiểu tung đồng xu. Vì thế, hãy thư giãn, sự nghiệp của bạn vẫn an toàn.

Hãy tập trung học trong 3 khu vực dưới đây, theo thứ tự đã được liệt kê:

1. Những kiến thức cơ bản – Sẽ dễ dàng hơn nhiều để học một kỹ năng mới khi bạn thực sự làm chủ được những kiến thức cơ bản. Ví dụ, nếu bạn hiểu sâu JavaScript, bạn có thể làm chủ mọi framework JavaScript mới một cách nhanh chóng. Nếu hiểu sâu lập trình hướng đối tượng, bạn cũng có thể làm chủ một ngôn ngữ hướng đối tượng mới nhanh chóng. Học sâu những kiến thức cơ bản sẽ tăng 10 lần hiệu quả học tập. Luôn tập trung để cải thiện kiến thức cơ bản đầu tiên.

2. Học tính năng/phiên bản mới nhất trong stack công nghệ bạn thường xuyên sử dụng – Những công cụ này sẽ đặt thức ăn lên bàn cho bạn và gia đình của mình. Khi các phiên bản mới của các công cụ này được phát hành, việc đầu tư thời gian để học chúng là rất có giá trị.

3. Học các công nghệ được hỗ trợ bởi những người dẫn đầu thị trường – Nếu những công ty lớn như Google, Facebook, hoặc Microsoft đưa ra một thứ gì đó mới và bắt đầu nhận được sự quan tâm, nó đáng để xem xét. Có hàng trăm framework JavaScript cạnh tranh với nhau để được chú ý, sau đó Angular và React xuất hiện đã đá bay chúng ra khỏi bản đồ. Tôi không nói rằng chúng sẽ không gây đảo lộn và trở thành điều lớn tiếp theo nhưng thường xuyên hơn, những công nghệ không có tên tuổi thường biến mất nhanh chóng.

Thời gian học lên là một phần trong lịch làm việc của bạn. Thiết lập một lượng thời gian để học hàng ngày. Nó không cần quá nhiều, thậm chí chỉ 25 phút để đọc và thử nghiệm hàng ngày là đủ.

Tham khảo các khóa học lập trình online, onlab, và thực tập lập trình tại TechMaster

2. Viết code tốt cần ít thời gian hơn code tồi, nhưng nó không cảm nhận theo cách này.

Bạn thường cảm nhận thời gian bạn dành cho một tính năng mới là khi code của bạn chạy được. Nhưng đó mới chỉ là bắt đầu. Thời gian dành cho một tính năng bao gồm thời gian để sửa lỗi sau này, thời gian để refactor và làm việc với những đoạn code liên quan khác xung quanh thiết kế mà bạn tạo ra khi triển khai tính năng đó. Khi bạn bắt đầu hiểu thời gian bạn đã đầu tư theo cách này, nó trở nên rõ ràng rằng, về lâu dài, ít lỗi và thiết kế tốt hơn là một sự đầu tư đáng giá.

Có 2 thứ bạn có thể làm, sẽ giảm thiểu các lỗi và giúp cho thiết kế tốt hơn.

1. Sử dụng test-driven development. Viết test đầu tiên, sau đó viết code theo test. Điều này không chỉ giúp cho ít lỗi hơn mà còn làm cho thiết kế tốt hơn, bởi vì khi bạn có một cấu trúc tốt theo cách có thể kiểm thử được, bạn sẽ tạo ra các hàm nhỏ hơn, đơn giản hơn có ít dependencies.

2. Sử dụng một phương pháp thiết kế lặp đi lặp lại. Đừng dành thời gian để làm cho code hoàn hảo trước khi bạn dành thời gian cố gắng để làm cho code chạy được. Bạn sẽ không bao giờ, làm đúng hoàn toàn ngay trong lần đầu tiên. Bạn cần gõ các ngón tay trên bàn phím và tạo ra code, cái chạy được và làm những thứ bạn mong muốn. Vấn đề là các lập trình viên thường có xu hướng mắc phải 2 lỗi phổ biến: hoặc là họ dành quá nhiều thời gian để suy nghĩ và không đủ thời gian để làm được một điều gì đó thực sự, hoặc họ không dành đủ thời gian để cải thiện giải pháp đầu tiên của họ. Sau đây là câu thần chú được phát biểu lần đầu bởi Kent Beck: “làm cho nó chạy, làm cho nó đúng, làm cho nó nhanh”.

3. Làm việc 24/7 không giúp bạn trở thành một anh hùng. Hãy quản lý những kỳ vọng.

Đây là một trong những thứ gần như đã giết tôi. Tôi đã từng đồng ý và chấp nhận mọi mốc thời gian điên rồ mà sếp hoặc khách hàng đưa ra. Tôi sợ phải nói “không”. Tôi sợ để cho bất cứ ai phải thất vọng. Tôi sẽ làm bất kỳ điều gì được giao. Tôi ngủ ngay dưới bàn của mình, uống nhiều cà phê để có thể làm việc liên tục 40 giờ.

Lần đầu tiên tôi thấy mình như một ngôi sao. Tôi đã làm được một điều to lớn và cảm thấy mình giống như một anh hùng. Nhưng tôi đã thiết lập một kỳ vọng bất khả thi. Làm việc như vậy là không bền vững. Sau cùng, tôi bắt đầu kiệt sức, ốm, và chậm deadline. Tôi bắt đầu có uy tín như là một người không đáng tin cậy và không thống nhất. Đó là một tin buồn.

Cuối cùng tôi cũng đã hiểu ra, và đó cũng là cái bạn nên chấp nhận để học. Một anh hùng thật sự là người nhất quán và đáng tin cậy. Họ nói cái họ sẽ làm và làm cái họ nói. Cách duy nhất để trở thành một anh hùng là quản lý kỳ vọng.

Bạn cần quản lý các mốc thời gian để luôn cung cấp các sản phẩm có chất lượng cao với thời gian chính xác. Điều này vô cùng khó khăn lúc đầu. Nó có nghĩa là bạn phải nói “không”.

Khi bắt đầu, ông chủ và khách hàng của bạn sẽ không hài lòng, nhưng khi bạn cho thấy rằng bạn hoàn toàn đáng tin cậy, mọi thứ sẽ bắt đầu thay đổi.

Theo thời gian, các lập trình viên khác sẽ chậm deadline, hoàn thành công việc một cách cẩu thả và trở lên không đáng tin cậy. Sau đó bạn sẽ trở thành một anh hùng trong nhóm của mình. Trong thực tế, học được điều này giúp tôi trở thành một trong những nhà tư vấn hàng đầu trong thị trường của mình. Tôi đã xây dựng một danh tiếng về chất lượng và đúng thời hạn, bởi vì tôi đã mạnh mẽ trong việc quản lý kỳ vọng.

4. Không phải tất cả thời gian dành để “cải thiện” code đều có cùng một ROI

Thời gian là một khoản đầu tư. Giống như tất cả các khoản đầu tư khác, bạn mong chờ một mức lợi nhuận thu về so với chi phí đầu tư . Bạn nên nhận lại ít nhất là bằng với số đầu tư và hy vọng nhận được nhiều hơn giá trị mà bạn đã bỏ ra.

Chúng ta đã nói “làm cho nó chạy, làm cho nó đúng, làm cho nó nhanh”. Nó là một câu thần chú hay nhưng cũng là một cái bẫy: “đúng’ không có nghĩa là hoàn hảo, và “nhanh” không có nghĩa là nhanh nhất có thể.

“Đúng” có nghĩa là code làm việc nhất quán và dễ dàng refactor. “Nhanh” có nghĩa là tốc độ thực thi nhanh không ảnh hưởng xấu tới trải nghiệm nguời dùng. Điều quan trọng nhất là ứng dụng của bạn làm cho người sử dụng cảm thấy nhanh.

Vì thế, đừng lãng phí bằng cách cố gắng tiết kiệm thời gian cho một hàm ít sử dụng, hoặc cố gắng giảm một vài mini giây trên một vài thứ đã chạy nhanh hơn tốc độ chớp mắt của con người (~300ms). Đừng lãng phí thời gian để cố gắng refactor code đang chạy, có cấu trúc tốt chỉ bởi vì bạn đã học được một vài kỹ thuật hoặc phương pháp mới cái bạn tự thuyết phục bản thân bỗng dưng quay lại và áp dụng vào những thứ bạn đã hoàn thành.

5. Lên lịch nghỉ ngơi giúp bạn làm việc hiệu quả hơn

Đây là điều rất khó đối với tôi khi phải chấp nhận và học. Làm thế nào bạn có thể trở lên hiệu quả hơn khi bạn không dành tất cả thời gian để làm việc? Vâng, nó là sự thật.

Theo như Allison Gabriel, một phó giáo sư về quản trị tại đại học Virginia Commonwealth người nghiên cứu nhu cầu việc làm và động lực của người làm thuê, “Nhiều nghiên cứu nói rằng chúng ta có những nguồn lực giới hạn. Khi bạn sử dụng những nguồn lực trong một thời gian dài, bạn trở lên không hiệu quả như vốn có. Nếu bạn cạn kiệt, hiệu năng sẽ giảm. Bạn có khả năng tập trung ít hơn và gặp khó khăn trong việc giải quyết các nhiệm vụ”.

Luôn làm việc trong tình trạng căng thẳng, chẳng hạn như stress, mệt mỏi, và tâm trạng tiêu cực. Sẽ làm giảm sự tập trung, các nguồn lực vật chất và tinh thần của bạn.

Bộ não có khả năng tự điều chỉnh để tuân theo kỉ luật, nhưng nó sẽ suy yếu với mỗi bài tập tự kiểm soát trong ngày. Đó là sự mất mát và cần bổ sung. Nếu không được bổ sung, nó sẽ trở nên kém hiệu quả khi xử lý các nhiệm vụ, sự tập trung và giải quyết các vấn đề.

Bộ não và cơ thể bạn cần nghỉ ngơi, cho dù bạn có muốn hay không. Vì thế, hãy lên lịch cho việc nghỉ ngơi. Lập kế hoạch thực sự và đặt vào lịch trình của bạn thời gian nghỉ. Điều này cho phép bạn nghỉ ngơi mà không cảm thấy áy náy về nó. Bạn sẽ dễ dàng chấp nhận nó hơn bởi vì bạn biết rằng bạn đã lên kế hoạch cho việc nghỉ ngơi.

Chi tiết
CALL ME
+
Call me!