1. Loa loa! Admin mới thêm tính năng xem 1 rờ víu và cho lọc theo loại công ty và địa chỉ.
2. Từ hôm nay Admin sẽ show "Víu", các bạn Rờ thoả thích .
3. Các bạn Dev bớt bớt lại nha, Dev kiếm chỗ đứng nhưng không muốn đứng ở chợ cá, nên không dùng từ ở "chợ cá"!
4. Do tamsudev.com bị chặn ở một số ISP, các bạn có thể vô tamsudev.tk hoặc dùng Tor Browser hoặc VPN.

Rờ víu ekino Vietnam

District 5, Ho Chi Minh
Outsourcing
51-150
302

Gởi rờ víu đồng nghĩa bạn đã chấp nhận cácĐiều khoản & Điều kiệncủa tamsudev.com

  • Anonymous  mạo danh  ( Since Since )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    23/10/2019 10:14Link chia sẻ

    Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since Since

  • Anonymous  mạo danh  ( xam )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    23/10/2019 10:11Link chia sẻ

    Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since SinceSince Since Since Since Since Since Since Since Since Since Since Since Since Since Since

  • Anonymous  với tư cách là: kout
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 09:51Link chia sẻ

    Chính sách mới nổi bật có hiệu lực từ tháng 10/2019 GIAO THÔNG Tốc độ tối đa của ô tô, xe máy khi tham gia giao thông Một trong những văn bản đáng chú ý nhất có hiệu lực trong tháng 10/2019 là Thông tư 31/2019/TT-BGTVT của Bộ Giao thông Vận tải về tốc độ của xe khi tham gia giao thông. Cụ thể như sau: - Ở trong khu vực đông dân cư: + 60km/giờ nếu chạy trên đường đôi hoặc đường một chiều có từ 2 làn trở lên; + 50km/giờ nếu là đường hai chiều không có dải phân cách giữa hoặc đường một chiều có 01 làn xe. - Nếu ở ngoài khu vực dân cư: + 90km/giờ đối với ô tô con, ô tô đến 30 chỗ ngồi; 70km/giờ đối với xe máy nếu chạy trên đường đôi hoặc đường một chiều có 2 làn trở lên; + 80km/giờ đối với ô tô con, ô tô đến 30 chỗ ngồi; 60km/giờ đối với xe máy nếu chạy trên đường hai chiều không có dải phân cách giữa hoặc đường một chiều có 1 làn xe. Riêng với xe gắn máy (xe dưới 50 phân khối), tốc độ tối đa là 40km/giờ, bất kể trên đoạn đường nào và trong khu vực nào. Thông tư này có hiệu lực từ ngày 15/10/2019. CHÍNH SÁCH Điều kiện chuyển từ nghĩa vụ công an sang chuyên nghiệp Từ ngày 10/10/2019, Nghị định 70/2019/NĐ-CP về nghĩa vụ công an của Chính phủ chính thức có hiệu lực. Nghị định này quy định có 2 trường hợp công an nghĩa vụ được chuyển sang chế độ phục vụ chuyên nghiệp, gồm: - Phục vụ tại ngũ từ 15 tháng đến dưới 24 tháng, hàng năm đều hoàn thành nhiệm vụ, bảo đảm các tiêu chuẩn theo chế độ chuyên nghiệp thì được xét, dự tuyển vào các trường Công an nhân dân. Khi tốt nghiệp ra trường được phong cấp bậc hàm sĩ quan, hạ sĩ quan chuyên nghiệp. - Người không thuộc trường hợp nêu trên, hết thời hạn phục vụ tại ngũ có đủ các tiêu chuẩn đáp ứng yêu cầu của công an nhân dân, nếu tự nguyện và công an nhân dân có nhu cầu thì được xét chuyển sang chế độ phục vụ chuyên nghiệp. Người huyện nghèo đi xuất khẩu lao động được vay 100% vốn ưu đãi Đây là tinh thần của Quyết định số 27/2019/QĐ-TTg do Thủ tướng Chính phủ ban hành; áp dụng từ ngày 25/10/2019. Theo đó, những người lao động tại các huyện nghèo được vay đến 100% chi phí đi làm việc ở nước ngoài mà không cần phải đặt cọc, thế chấp, cầm cố tài sản... Tuy nhiên, để được vay số tiền này, người lao động phải có hộ khẩu thường trú tại huyện nghèo từ đủ 12 tháng trở lên; đã ký hợp đồng đi làm việc ở nước ngoài và được phía nước ngoài chấp nhận vào làm việc. Mức lãi suất vay ưu đãi như sau: - Nếu thuộc hộ nghèo được vay vốn với lãi suất bằng 50% lãi suất cho vay đối với hộ nghèo do Chính phủ quy định; - Nếu không thuộc hộ nghèo vẫn được vay vốn bằng mức lãi suất đối với hộ nghèo do Chính phủ quy định. THUẾ-PHÍ-LỆ PHÍ Lệ phí cấp thẻ Căn cước công dân từ 30.000 đồng Từ ngày 16/10/2019, áp dụng lệ phí cấp thẻ Căn cước công dân mới theo tinh thần của Thông tư 59/2019/TT-BTC do Bộ Tài chính ban hành. Cụ thể như sau: - Chuyển từ chứng minh nhân dân 9 số, 12 số sang thẻ Căn cước công dân: 30.000 đồng; - Đổi thẻ Căn cước công dân khi bị hư hỏng không dùng được; khi có thay đổi thông tin cá nhân hoặc khi có sai sót về thông tin trên thẻ: 50.000 đồng - Cấp lại thẻ Căn cước công dân do bị mất là 70.000 đồng. Nếu người từ đủ 14 tuổi làm thủ tục cấp thẻ Căn cước công dân lần đầu; Đổi thẻ khi có sai sót về thông tin trên thẻ do lỗi của cơ quan quản lý… không phải nộp lệ phí. GIÁO DỤC-ĐÀO TẠO-DẠY NGHỀ Giáo viên mầm non được học cách quản lý cảm xúc bản thân Chương trình bồi dưỡng thường xuyên cho giáo viên mầm non đã được Bộ Giáo dục và Đào tạo ban hành kèm theo Thông tư 12/2019/TT-BGDĐT, có hiệu lực từ ngày 12/10/2019. Chương trình bồi dưỡng này được tổ chức hàng năm với các nội dung liên quan đến đạo đức nghề nghiệp; Rèn luyện phong cách làm việc khoa học; Đảm bảo an toàn cho trẻ trong các cơ sở mầm non; Kỹ năng sơ cứu trẻ em… và đặc biệt là cách quản lý cảm xúc của bản thân. Mỗi giáo viên phải tham gia Chương trình bồi dưỡng với thời lượng 120 tiết/năm học. Giám đốc Sở GDĐT không bắt buộc tốt nghiệp Đại học sư phạm Từ ngày 24/10/2019, quy định về tiêu chuẩn đối với Giám đốc Sở Giáo dục và Đào tạo thuộc UBND cấp tỉnh sẽ được áp dụng theo Thông tư 13/2019/TT-BGDĐT. Theo đó, bên cạnh các tiêu chuẩn chung như: Nắm vững chủ trương, đường lối của Đảng, chính sách và pháp luật của Nhà nước; Có năng lực tập hợp quần chúng… người được xem xét bổ nhiệm Giám đốc Sở Giáo dục và Đào tạo còn phải đảm bảo các tiêu chuẩn riêng sau: - Tốt nghiệp đại học sư phạm hoặc tốt nghiệp đại học và có chứng chỉ nghiệp vụ sư phạm. - Đã đảm nhiệm chức vụ Phó Giám đốc Sở Giáo Dục và Đào tạo hoặc chức vụ tương đương trở lên. - Được cấp có thẩm quyền phê duyệt quy hoạch chức danh Giám đốc Sở Giáo dục và Đào tạo và chức danh tương đương. Y TẾ-SỨC KHỎE Điều kiện để trở thành bác sĩ gia đình từ ngày 15/10/2019 Thông tư 21/2019/TT-BYT của Bộ Y tế hướng dẫn thí điểm về hoạt động y học gia đình sẽ có hiệu lực từ ngày 15/10/2019. Thông tư này nêu rõ, bác sĩ đa khoa, bác sĩ chuyên khoa hệ lâm sàng đã được cấp chứng chỉ hành nghề khám bệnh, chữa bệnh sẽ được khám bệnh, chữa bệnh y học gia đình sau khi đáp ứng một trong các điều kiện sau đây: - Có một trong các văn bằng bác sĩ nội trú, chuyên khoa I, chuyên khoa II, thạc sĩ, tiến sĩ về chuyên ngành y học gia đình. - Có giấy chứng nhận đã được đào tạo, bồi dưỡng về y học gia đình tối thiểu 03 tháng. - Có giấy chứng nhận theo học từng đợt học có các nội dung ghi trong giấy xác nhận hoặc tín chỉ hoặc chương trình đào tạo, bồi dưỡng về y học gia đình với tổng thời gian tối thiểu 03 tháng. Có 56 loại phụ gia phẩm màu được dùng trong thực phẩm Nội dung này nằm trong Thông tư số 24/2019/TT-BYT của Bộ Y tế về quản lý và sử dụng phụ gia thực phẩm, áp dụng từ ngày 16/10/2019. Cụ thể, tại Thông tư này, Bộ Y tế công nhận 56 loại phụ gia phẩm màu được phép dùng trong thực phẩm, như: Curcumin; các bon thực vật; màu ngô tím; màu bắp cải đỏ và hàng trăm phụ gia khác là chất bảo quản, chất điều vị, chất tạo ngọt… Khi sử dụng phụ gia, phải đảm bảo một số nguyên tắc nhất định: - Phụ gia thực phẩm phải là loại được phép sử dụng và đúng đối tượng thực phẩm; - Không vượt quá mức sử dụng tối đa; - Hạn chế đến mức thấp nhất lượng phụ gia cần thiết để đạt được hiệu quả như mong muốn… THƯƠNG MẠI Dịch vụ Bảo hiểm nhân thọ không phải đăng ký hợp đồng theo mẫu Thủ tướng Chính phủ đã ra Quyết định 25/2019/QĐ-TTg về việc sửa đổi Danh mục hàng hóa, dịch vụ thiết yếu phải đăng ký hợp đồng theo mẫu, điều kiện giao dịch chung. Theo đó, bãi bỏ dịch vụ “Bảo hiểm nhân thọ” khỏi Danh mục nêu trên. Quyết định này có hiệu lực từ ngày 01/10/2019. Bán thuốc diệt côn trùng chung với thực phẩm bị phạt đến 3 triệu Từ ngày 15/10/2019, Nghị định 71/2019/NĐ-CP về xử phạt vi phạm hành chính trong lĩnh vực hóa chất và vật liệu nổ công nghiệp sẽ có hiệu lực. Theo đó, sẽ phạt tiền từ 01 - 03 triệu đồng nếu có các hành vi vi phạm trong hoạt động mua bán chế phẩm côn trùng, diệt khuẩn như sau: - Bày bán chế phẩm diệt côn trùng, diệt khuẩn không tách biệt với nơi bày bán các loại thực phẩm; - Điều kiện bảo quản chế phẩm không đáp ứng yêu cầu bảo quản ghi trên nhãn chế phẩm diệt côn trùng, diệt khuẩn; - Không cung cấp đầy đủ thông tin hoặc cung cấp sai về các đặc tính nguy hiểm của hóa chất, chế phẩm diệt côn trùng, diệt khuẩn, gây hại cho sức khỏe… Ngoài bị phạt tiền, người nào vi phạm còn có thể bị đình chỉ hoạt động mua bán chế phẩm diệt côn trùng, diệt khuẩn dùng trong lĩnh vực gia dụng và y tế từ 01 - 03 tháng.

  • Anonymous  mạo danh  ( earn $ )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 09:55Link chia sẻ

    What I Learned From Losing $100,000 on Two Failed Startups Don’t invest more money, energy, or time than you’re prepared to lose A young businessman experiences stress late at night at his work station computer. Photo: PeopleImages/E+/Getty Over the last five years, I founded and shuttered two startups, losing $100,000 of personal and seed money in the process. I worked on the first startup — an app that helped diners discover new restaurants — for a year, and the second startup — a stock market investing publication — for two years. The company details are less important than the insights. Shutting down my dream idea (twice) was painful and humbling. But I survived, learned a ton, and progressed my career in the process. And thankfully, I’m lucky to have a good day job, a happy home, and an amazing family. Recently, I’ve had a lot of time to reflect on what I learned along the way, which boiled down to these 20 lessons: 1) Startups need your money, energy, and time (MET) to survive. New ventures draw on three precious resources: Money, energy, and time (“MET”). Money in this case means your savings, revenue, and any capital raised from friends, family, and investors. Energy is your physical and emotional bandwidth to create something from nothing. Time is both the time you devote during each day to work as well as the timeline required for startup goals to be met. There’s a piece of longstanding wisdom in the startup world that goes something like this: “The job of a startup CEO is to find product/market fit before running out of money.” In my experience, that applies to time and energy as much as it does to money. If any of the three MET supply lines are disrupted, growth will stall. Most people assume startups fail because they run out of money, but exhausted energy and time have also claimed their fair share of new ventures. MET is the lifeblood of your company and success comes down to investing it wisely. 2) Don’t invest more MET than you can afford to lose. When starting your own company, there’s a temptation to go all in. There are moments when you’d trade anything to bring your idea to life. For both of my startups, I invested as much MET as possible, but never more than I could afford to lose. When I closed up shop, I could still continue my career, pay my rent, and spend time with my friends and family. It’s rarely wise to bet the farm on anything. Always keep an eye on how much MET you’re investing and ask yourself, “If things don’t work out and I lose all this MET, will I be OK?” 3) Investing your MET in valuable assets protects your downside. As you invest your precious MET, consider the value of the assets you’re building. During my first startup, I invested most of my money into creating an app that became worthless code when I shut down. But in my second startup, I invested in creating high-quality content, building up my customer list, and researching profitable stock market algorithms, which left me with three valuable assets after I closed shop. Be wary of making large investments in assets which will be worthless if things don’t work out. 4) Do as much as you can before you quit your day job. When you’re excited about a new startup, there’s a temptation to quit your day job and dive in. But it’ll probably take awhile before your company can start making money. Ideally, if you keep working your day job, it’ll subsidize your startup until it can stand on its own two feet. For my first startup, I quit my day job and went 10 months without a paycheck, which rapidly drained my MET. I operated my second startup as a side hustle and never missed a paycheck, which bought me twice the runway. In investing, this approach is called “the barbell strategy” because you place one bet on each end of the risk spectrum: your day job is low-risk with a small upside, while your startup is high-risk with a big upside. If you can, have your day job pay the bills until your startup is ready to take over. 5) Once you taste the startup life, it’s hard to go back. As you experience the thrill of working hard, dreaming big, and tasting success, the traditional corporate life feels less and less appealing. In both of my startups, I’d accomplish in two days what would take two months in my day job. After trailblazing at startup speed, menial tasks like TPS reports start to feel more soul-crushing than ever. Whichever market you target, make sure you’re willing to live fully in that world. 6) The more your company grows, the more it owns you. There’s a certain lightness that comes with a new startup idea. It’s all excitement and hope, without risk and commitment. But the more your company grows, the more you become tied to it. When I was trying to win venture funding for my first startup, I asked myself if I really wanted to answer to investors, customers, employees, partners, vendors, lawyers, and press for years to come. I thought: “Once you fundraise, investors own you. Once you hire, employees depend on you.” That prospect started to feel as confining as my old corporate gig. While some people thrive on being the boss, others value their space, flexibility, and independence. In other words, uneasy lies the head that wears a crown. 7) Operating as a “solopreneur” can be brutal. No one cares about your company as much as you do. No one will put in the hard hours, agonize over the big decisions, or experience the emotional ups and downs like you will. Friends and family will often support you, but at the end of the day, you’re the only one on the frontline. During both my startups, I went through long stretches of intense stress, loneliness, and poor health, which drained my energy and shortened my timeline. If you can find good partners to help share the MET burden, it’ll improve your chances of success. It’s incredibly difficult being in the trenches alone. 8) Be prepared to live in your niche. If your startup serves a certain niche, be prepared to immerse yourself in that culture. For my first startup, I worked with dining enthusiasts, which wasn’t a natural fit for me. For my second startup, I sold to “grumpy old man” investors, which took some getting used to. Honestly, I felt out of place in both markets, which hurt my credibility and wore me down. Whichever market you target, make sure you’re willing to live fully in that world. 9) You’re not as smart as you think you are. When it comes to starting your own company, the Dunning-Kruger Effect is deadly. Put simply, the Dunning-Kruger Effect is the tendency for founders to vastly overestimate their understanding of an industry precisely because they’re so uninformed about it. Before I launched my second startup, I was convinced the financial publishing industry was outdated and ripe for disruption. Because I was so uninformed, I completely misread the field and got my butt kicked by veteran competitors. The smarter you are, the greater the risk you’ll assume you can easily disrupt a market with your brilliant new idea. But the good news is you can avoid this trap by considering the next lesson I learned. 10) Start by stress-testing your big assumptions. Before you start building anything, write down all the major assumptions that underpin your grand plan. Then find a cheap and easy way to vet those assumptions before you get started. My brilliant strategy for my second startup was built on a foundation of 3 to 5 core assumptions I knew “in my gut” had to be true. If I had paused to chat with a handful of industry insiders before charging ahead, I would’ve discovered my big ideas were wrong. A few phone calls could’ve saved me from investing a ton of money, energy, and time into a flawed strategy. Don’t believe your own hype. Test it first. 11) Be wary of consultants. In both my startups, the bulk of my spending went toward consultants and vendors who helped design and build my product. In some ways they added a lot of value by helping me learn the market fast, avoid costly mistakes, and build a winning product. I traded money for more time, energy, and skill — sort of like buying cheat codes for my market. But the reality is that most consultants don’t care about your company. They care about winning more of your business, which often takes the form of overpromising, underdelivering, and asking you to hire them again. Weigh the cost of consulting services against the MET costs of just doing it yourself. If their cost is significantly less than yours, or they fill a critical skills gap, then maybe they’re worth it. But if you can learn on your own quickly and cheaply, then just do it yourself. 12) Take guru crash courses, but temper your expectations. A huge part of startup success hinges on your ability to learn fast. Thankfully, the internet offers a virtual university of gurus teaching every skill imaginable. During my second startup, I took crash courses on email copywriting, brand voice, SEO strategy, customer acquisition, social media marketing, and more. The cost of these courses ranged from $20 to $500, and brought me from novice to competent in a matter of days. But before seeking out your own crash courses, remember to temper your expectations. Every guru promised to unlock the big secret to fast and easy growth. None of them did. But they did all reveal an important part of the larger formula. 13) Find product/market fit for your MVP fast. It’s so tempting to start with a grand vision of what your company could be in 10 years. But you’ll have more success if you start by creating one simple product with solid market fit. In my first startup, I built too many bells and whistles into my minimum viable product (MVP), which burned most of my precious MET. And in my second startup, I tried to juggle several different mass-market products, rather than conquer a single niche. Focus on getting one solid win and build from there. 14) Acquiring customers is the first big challenge. Creating a successful company from nothing involves scaling many challenging peaks. While acquiring investors, hiring employees, expanding products, wrestling competitors, and fighting legal battles tend to come later in the game, winning customers is usually the first big hurdle to overcome. I found customer acquisition incredibly difficult in both my startups. I’m not a natural marketer (I’m too analytical), and markets are often oversaturated with new ideas. There was a time you could throw up a website and eager prospects would find their way to you. That time is long past. Yesterday’s easy internet land-grab has been overrun by an army of hardened growth hackers, SEO ninjas, backlink builders, email copywriters, content experts, PPC specialists, social media masters, and others. It’s really hard to break through, especially if you’re short on MET and marketing experience. Too many entrepreneurs burn their precious MET refining their dream product. Instead, spend it figuring out how to profitably acquire new customers at scale. 15) Try selling your product before you build it. It seems like common sense that you should build your product before selling it. But I’d encourage you to try selling your product before you build it. Early in my startup journey, I fully built a new product before trying to sell it. This was a MET-intensive process that delayed what I needed most: customer feedback. Later, I threw together landing pages for new products in just a few hours. If customers tried to purchase my non-existent product, I captured their name and told them it was coming soon. Some of those landing pages never got a single signup, which meant I learned in a day it wasn’t worth building the product. It’s a strange and uncomfortable concept, but if you can sell your product (or a light version of your product) before you invest heavily in building it, you’ll find product/market fit much faster. 16) The days of easy SEO are long gone. To recruit customers for my investing publication, I posted nearly 100 high-quality blog posts targeting relevant keywords. Despite following all the latest best practices and writing articles that were objectively better than Google’s first page results, I never acquired a single paying-customer from organic search. SEO has become big business, and incumbents employ seasoned content-marketing teams to crank out keyword-friendly content, recruit backlinks, broker guest-posts, and more. Unless you’re targeting an underserved niche market, it’ll take a lot of time, energy, and money to rank well. 17) Beware marketing giants in your space. As digital marketing guru Ryan Deiss says: “He or she who can afford to spend the most to acquire a new customer, wins.” I experienced this during my second startup when best-in-class marketing giants, such as Agora and Motley Fool, drove up ad costs to levels I couldn’t match. Their savvy marketing departments, deep pockets, and high-powered upsell strategies allowed them to happily pay $200 to acquire a new customer to buy a $50 product. I couldn’t compete with those economics, which made paid acquisition extremely challenging. 18) If you want fast results, sell into an existing community. It’s really tough to build your own customer base from scratch. It’s much easier to take your new product to Udemy, YouTube, or other communities that gather and monetize customers for you. There’s real power in giving up a share of your revenue to sell into someone else’s platform of hungry buyers. In many cases your slice of a larger pie is better than the whole of a smaller pie. Once your success grows, you can break off and form your own community. 19) Avoid “entrepreneurship porn.” Most startups require a gradual path to success. “Entrepreneurship porn,” “startup porn,” or “hustle porn” are glorified stories of working to the bone, putting everything on the line, and then winning big. I never maxed out my credit cards, lived in my car, or pulled ramen-fueled all-nighters when running my startups. While extreme hustle might get more mileage out of your money and time in the day, it’ll bankrupt your energy, shorten your runway, and risk more MET than you can afford to lose. 20) There are many good reasons to quit. I don’t think startups are the place for a “never surrender” attitude. Your money, energy, and time are more precious to your life than to your startup. For both my startups, there was a distinct moment where the thought flashed in my mind for the first time: Maybe this isn’t going to work. I kept trying for a few more months, but my subconscious already knew the days were numbered. There are many good reasons to quit. If you see your idea definitely isn’t going to work, don’t waste precious MET on it. If you find yourself not wanting the life that success would bring, it’s time to move on. And if you see a better opportunity on the horizon, adjust your course. Don’t be a martyr for your idea. Many entrepreneurs find success with their second, third, fourth, or tenth startup. Try as hard as you can, then live to fight another day.

  • Anonymous  mạo danh  ( sleep )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 09:57Link chia sẻ

    3 Common Bedtime Habits Destroying Your Sleep​ And why more sleep hygiene isn’t the answer. Nick Wignall Photo by Toa Heftiba on Unsplash Let me guess: you’ve read all the sleep hygiene articles, turned off all your screens at night, drink plenty of sleepy time tea, and yet… you’re still not sleeping well. Maybe you struggle to “shut off your brain” and fall asleep. Maybe you wake up frequently thought the night, unable to go back to sleep. Or maybe you just feel lousy in the mornings, not rested and lacking energy. Whatever your sleep difficulties are, reading another list of sleep hygiene tips and tricks is not the solution. If you suffer from consistently poor sleep, it’s your sleep habits that are the problem. As a psychologist who specializes in insomnia and sleep problems, I work with my clients to understand the underlying dynamics and habits that are causing sleep problems and how to correct them. And I’m going to teach you to do the same. In this article, we’re going to walk through the 3 most common habits that lead to insomnia, plus some very specific advice about how to break these bad habits and build better ones. 1. You try to “catch up” on sleep by sleeping in on the weekends One of the most common mistakes people make with their sleep is sleeping in on the weekends in an attempt to “catch up” on sleep and pay off their “sleep debt.” Although it seemingly makes sense to try for a few extra hours rest on the weekends or your days off to make up for less sleep during the week, such attempts are both misguided and almost never worth the costs. Contrary to the pop psychology we hear in media, there’s no scientific evidence that people actually build up any kind of meaningful long-term sleep debt, even after significant losses in normal amounts of sleep. Consequently, the benefits of sleeping in on Saturday and Sunday morning to catch up for lost sleep during the week are slim to none. But, there are important downsides that go along with sleeping in and trying to play sleep catch-up. The Downsides of Playing Sleep Catch-Up Sleeping in the on the weekends has very little long-term benefit and comes with a couple of very significant downsides: 1. Social Jet Lag. Regular jet lag occurs when there’s a discrepancy between our body’s biological clock and the actual time of day. If you catch a flight from San Francisco at 4:00 pm and land in Boston at 9:00 pm, the clock on the wall at the hotel room may read 10:00 pm, suggesting it’s time for bed. But your biological clock hasn’t had time to adjust — you still feel as if you’re on San Francisco time, which is 7:00 pm and much too early to fall asleep. We suffer from Social Jet Lag when our internal biological clock is similarly mismatched compared to actual time but the cause is a bad sleep schedule rather than a plane flight across time zones. If you stay up 3 hours later than normal Friday and Saturday night and wake up 3 hours later than usual on Saturday and Sunday morning, the Social Jet Lag you’ll experience for the next few days (when you return to your normal schedule) is the same as if you crossed three time zones! TAKEAWAY: Sleeping in leads to Jet Lag just as much as jets do. 2. Low Sleep Drive. The second problem with playing sleep catchup and sleeping in is that it depletes your Sleep Drive. Sleep drive is the body’s need for deep, restorative sleep. Being awake and active throughout the day builds it up so that when bedtime rolls around, your body has a strong need for deep sleep — this results in a faster time to fall asleep and deeper, more restful sleep throughout the night. But when you sleep in you have less time to build up sleep drive over the course of the day, which means you’ll be A) less sleepy at your normal bedtime, and B) more likely to wake up in the middle of the night and have trouble falling back to sleep. TAKEAWAY: Low sleep drive leads to low sleep quality. The Solution The good news is that both of the above problems — Social Jet Lag, and Low Sleep Drive — can be cured by one simple fix: Wake up at the same time every day. Even on weekends, holidays, and vacations. Even if you didn’t sleep well the night before or had a stressful/exhausting day. When you keep your wake up time consistent, you avoid getting yourself into social jet lag in the first place because your schedule remains constant. You also give yourself plenty of time to build up sleep drive over the course of the day so that you’re sufficiently sleepy when bedtime rolls around. Unfortunately, while conceptually simple, waking up at the same time every day is often a major challenge for most folks. Below are the 3 most common obstacles or points of resistance I hear from people trying to adopt a more consistent wake-up schedule and some suggestions on how to think differently or work through them. But sleeping in feels so good! True, but does the pleasure that comes from an hour or two of sleeping in each week really outweigh the costs of chronic poor sleep? If I get just a little more sleep I’ll feel much better (and perform much better) during the day. The degree to which you feel rested throughout the day and can function at your normal level is almost entirely dependent on how much deep sleep you get, not the overall number of hours you sleep. And almost all of our deep sleep happens in the first 3 hours of sleep. Consequently, the sleep you get from 7:00 am to 8:00 am, while it may feel good, is not going to meaningfully impact how you feel or your performance throughout the day. But it will decrease your sleep drive and make it harder to fall asleep that evening, perpetuating the cycle of poor sleep. Weekend mornings in bed are the only time my spouse and I have to be affectionate/intimate/cuddle. If Saturday and Sunday mornings are truly the only time you can find to cuddle and be intimate, maybe it’s time to re-adjust your priorities and make some time for physical and emotional affection with your partner during a couple of the other 100+ hours during the week. TAKEAWAY: To avoid social jet lag and low sleep drive, wake up at the same time every single day. 2. You get into bed too early Turning in early before a big day is the flip side of playing sleep catch up. In both cases, by trying to modify your sleep routines in order to get better sleep, you end up creating worse sleep in the long run. When you turn in early before a big day, you more often than not end up laying in bed awake instead of falling asleep. For example: Tomorrow is the start of a big trial, the outcome of which determines whether you make partner. Or maybe you’re defending your dissertation, pitching your startup to a group of VCs, playing in a championship tennis match, or any other stressful, high-stakes situation. In the face of a daunting challenge tomorrow, many of us make the mistake of “turning in early” tonight in an attempt to get more sleep and therefore be better rested and able to perform well the following day. The crucial error in this line of thinking is that the degree to which you feel rested and perform at your peak potential has far less to do with the quantity of sleep and far more to do with the quality of your sleep. Of course, in a perfect world, we’d get both ample quantity and quality of sleep every night. And while this occasionally happens as a result of a perfect storm of positive factors, it’s foolhardy to think that we can make it happen by simply getting into bed earlier than usual. Think about it this way: If you had to choose, would you rather get 6 hours of high-quality sleep or 8 hours of fitful, restless sleep? When you try to turn in early before a big day, you typically end up doing more harm than good because your body may not be ready to fall asleep. As a result, you lay in bed for a long time not sleeping. This sets you up for two major sleep problems: Sleep Anxiety and Problematic Sleep Conditioning. 1. Sleep Anxiety. You’re laying in bed, lights off, alone, with nothing going on. No external stimuli whatsoever because you’re religious about following your sleep hygiene rules (eye mask on, earplug and white noise machine, blackout drapes, etc.). In a perfect world, this would help you sleep. Unfortunately, your sleep world isn’t perfect, in part because you got into bed too early without your sleep drive being sufficiently high. As a result, you’re going to lay awake with nothing but your thoughts and no sleepiness. Inevitably, you start thinking about your to-do list for tomorrow, the big presentation you have to give next week at work, that thing you promised your mother you’d take care of, etc… When you’re in bed but not sleepy, your mind starts working — in this case, thinking, because there’s nothing external to work on. Right away, this thinking increases your overall level of arousal and signals to your body that sleep drive should be suppressed because it’s time to work. Instead of drifting off into sleep, you find yourself even more awake and alert. This leads to an uncomfortable thought: “What if I can’t sleep? How will things go tomorrow if I’m groggy and “out of it.” I need to fall asleep NOW!” And so begins sleep worry and anxiety, which takes your already aroused brain to new heights of arousal (the challenge of a to-do list or presentation are mildly arousing but the anxiety of being sleep deprived is majorly arousing). TAKEAWAY: By worrying about the effects of not sleeping you’re creating a self-fulfilling prophecy that’s keeping you awake. All because you got into bed too early. 2. Problematic Sleep Conditioning. Problematic Sleep Conditioning is when you teach your brain to associate arousing activities with the act of laying down in bed. If every time you lay down in bed you start reviewing your to-do list for tomorrow and worrying about the quality of your sleep, your bed is going to become an unconscious cue for anxious feelings and mental arousal, and by extension, suppressed sleep drive. In other words, being in bed when you’re not truly sleepy is doubly harmful: In the moment, it creates arousal and sleep anxiety which makes it harder to fall asleep that night. But over time it also established an unconscious association between your bed and arousal, which is the worst thing to have associated with your bed since it turns the act of getting into bed as a signal to wake up! TAKEAWAY: When you spend time in bed not sleepy, you train your brain to associate the bed with wakefulness. The Solution No matter how tired you are, if you’re not sleepy specifically (more on this distinction below), you should not be getting into bed. If you do, chances are you will: A) Start to worry, problem-solve, and generally activate yourself, and B) You will be creating or strengthening all sorts of arousing associations with your bed, all of which interfere with falling asleep. TAKEAWAY: Don’t get into bed until you are truly sleepy, not just tired. Why It’s Difficult We make the old mistake of believing that quantity rather than quality of sleep is what’s most important. Remember: 6 hours of quality sleep beats 8 hours of crummy sleep every time. If you’re worried about performing well tomorrow, remind yourself that the quality of your sleep is the most important thing to prioritize. If anything, you should try to go to bed slightly later than usual before a big day since this will allow your sleep drive to build up even further, increasing the odds of falling asleep quickly and staying asleep. Tired isn’t the same thing as sleepy. Tired is a broad umbrella term for fatigue or exhaustion. Sleepy is a very specific term for when your body is ready to fall asleep. When people cross the finish line of a marathon they’re often quite tired, but I’ve never heard of anyone falling asleep at the finish line. Similarly, after a long day at work with multiple physical, mental, and emotional stressors, you may feel extremely tired, but that fact is often independent of sleepiness. The foolproof way to know when you’re truly sleepy and not just tired is droopy eyelids. During the evenings, try to notice the difference between tiredness and sleepiness, so that you can more effectively refrain from getting into bed too early. TAKEAWAY: Only get into bed when you are truly sleepy, not just tired. 3. Your “sleep runway” is too short Many people are frustrated with their poor sleep because they expect that their minds will simply shut off and go to sleep as soon as they decide to get into bed. But the mind doesn’t work that way. You’ve probably spent all day with your mind being fairly active and energetic so that you can be productive, solve problems, and get things done. Doesn’t it seem a bit unrealistic to think that all of that will instantly shut off and go into sleep mode at the drop of a hat? Your mind before bed is like a jet before landing: The bigger, more powerful the jet the longer a runway it needs to land and come to a complete stop. In other words, the more mentally active and stimulated you are during the day, the more time you need to gradually slow your mind down in the evening before it’s ready to fall asleep. If you have the common problem of getting into bed only to have your mind racing with thoughts, worries, to-do list items, and memories, it’s probably because you haven’t given your mind a long enough period of time to transition from alert and aroused to relaxed and sleepy. The Solution In order to fall asleep quickly in bed, you need a transition period of relaxation that bridges work and rest. Specifically, your mind needs some time to switch out of problem-solving work mode and into relaxed rest mode. If you want to be able to easily and quickly fall asleep. This dedicated time you give to your mind to unwind and relax is called a sleep runway. By intentionally creating space and time for relaxation before bedtime, you allow your mind to slowly and organically shift gears into a sleep-promoting state of relaxation. If you’re not doing this already, it may take some deliberate thought and planning on your part. By implementing and sticking with a consistent sleep runway, you’ll also be creating reliable and powerful cues for sleep that will serve as unconscious signals to your mind that it’s time to fall asleep soon. This will make the actual act of falling asleep easier and more effortless. To create an effective sleep runway, schedule an hour or so before your anticipated bedtime where you do no work at all. And the term work here is used in a broad sense — of course, you shouldn’t be emailing clients or reviewing spreadsheets, but you also should abstain as much as possible from any kind of goal-directed or striving activity. Anything that might signal to your mind, I need to do some mental work. Reading the news, for example, is a good way to subtly put your mind into work mode. After all, the news is — almost by definition, unfortunately — a long series of problems and crises to which your mind will naturally respond with worry and problem-solving. And when you start worrying or problem-solving, you put your mind in work mode, which is arousing and inhibits your sleep drive and increases sleep anxiety. Why It’s Difficult We’re good at working and problem-solving and we do it a lot, so it can actually be a challenge to come up with and implement non-work and non-arousing activities for our sleep runway. The key to good sleep runway activities is to think of things that hit the sweet spot of being interesting or enjoyable enough to hold your attention but not so exciting that they become arousing. Reading is typically a good choice and often fiction tends to be better than non-fiction. A good trick is to re-read a favourite novel or story. This tends to hit that sweet spot of interesting and enjoyable but also not arousing since you’ve read it before and there aren’t any surprises. Other good sleep runway activities include: TV Shows. A lot of people report success with nature documentaries like Planet Earth or old favourite sitcoms like Cheers or Seinfeld. And don’t worry about “blue light” impacting your sleep. The science of this is shaky at best, and even when some studies have shown a negative effect of blue light on sleep, the effects are typically quite small — much less influential than, say, worrying and getting anxious about not sleeping because you got into bed without being sleepy. Stretching or yoga Meditation or formal relaxation practices like Progressive Muscle Relaxation or Diaphragmatic Breathing Puzzles or other non-competitive games Certain hobbies may have aspects that are non-stimulating and would, therefore, be appropriate sleep runway activities. For example, sketching ideas for a new watercolour painting or simply listening to music without doing anything else. TAKEAWAY: To fall asleep quickly and easily, create a sleep runway of an hour or more where you do nothing arousing or goal-oriented. Putting it all together If you suffer from consistently poor sleep, implementing standard sleep hygiene tips are not enough to improve things. You must identify and correct the underlying sleep habits that are producing poor sleep in the first place. Three of the most common yet counter-intuitive sleep habits that end up disturbing our sleep are: Sleeping in on weekends and the social jet lag it produces. Getting in bed too early and associating wakefulness with your bed. Not having a long enough sleep runway. If you can address these problematic sleep habits, you will find that consistently good sleep is closer than you think. To drastically improve the quality of your sleep, remember the following: Wake up at the same time every single day. Don’t get into bed unless you’re sleepy (heavy eyelids), not just tired. Maintain a sleep runway of at least an hour before bedtime that includes no work or even goal-directed behaviour. Mind Cafe in Your Inbox Want to stay up to date with our top-performing posts each week? Sign up for email updates by following this link. Mind Cafe Relaxed, inspiring essays about happiness.

  • Anonymous  mạo danh  ( PostgreSQL )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 09:59Link chia sẻ

    Lessons learned scaling PostgreSQL database to 1.2bn records/month Choosing where to host the database, materialising data and using database as a job queue This isn’t my first rodeo with large datasets. The authentication and product management database that I have designed for the largest UK public Wi-Fi provider had impressive volumes too. We were tracking authentication for millions of devices daily. However, that project had a funding that allowed us to pick any hardware, any supporting services and hire any DBAs to assist with replication/data warehousing/troubleshooting. Furthermore, all analytics queries/reporting were done off logical replicas and there were multiple sysadmins that looked after the supporting infrastructure. Whereas this was a venture of my own, with limited funding and 20x the volume. Others’ mistakes This is not to say that if we did have loadsamoney we would have spent it on purchasing top-of-the-line hardware, flashy monitoring systems or DBAs (Okay, maybe having a dedicated DBA would have been nice). Over many years of consulting I have developed a view that the root of all evil lies in the unnecessarily complex data processing pipeline. You don’t need a message queue for ETL and you don’t need an application-layer cache for database queries. More often than not, these are workarounds for the underlying database issues (e.g. latency, poor indexing strategy) that create more issues down the line. In ideal scenario, you want to have all data contained within a single database and all data loading operations abstracted into atomic transactions. My goal was not to repeat these mistakes. Our goals As you have already guessed, our PostgreSQL database became the central piece of the business (aptly called ‘mother’, although my co-founder insists that me calling various infrastructure components ‘mother’, ‘mothership’, ‘motherland’, etc is worrying). We don’t have a standalone message queue service, cache service or replicas for data warehousing. Instead of maintaining the supporting infrastructure, I have dedicated my efforts to eliminating any bottlenecks by minimizing latency, provisioning the most suitable hardware, and carefully planning the database schema. What we have is an easy to scale infrastructure with a single database and many data processing agents. I love the simplicity of it — if something breaks, we can pin point and fix the issue within minutes. However, a lot of mistakes were done along the way — this articles summarizes some of them. Dataset Before we dig in, let’s quickly summaries the dataset. I am a co-founder of a company Applaudience. We aggregate cinema data. Our primary dataset includes movie showtimes, ticket prices and admissions. We combine this data with all sorts of supporting data, including data that we get from YouTube, Twitter and weather reports. The end result is a comprehensive time-series dataset describing the entire theatrical movie release window. The goal is to predict movie performance far into the future. We currently track 3200+ cinemas across 22 territories in Europe and the US. This approximates to 47,000 showtimes/day. Every time a person reserves or purchases a ticket from either of these cinemas, we capture a snapshot describing attributes of every seat in the auditorium. How we monitor data aggregation and detect anomalies is whole another topic. However, having PostgreSQL as the single source of truth about all data that is being aggregated and all the processes that aggregate the data made it a lot easier. This adds up to 1.2bn records/month, and thats just for the admissions data. Choosing where to host the database We went through several providers: 1. Google 2. Amazon 3. Aiven.io 4. Self-hosting Google Cloud SQL for PostgreSQL We got USD 100k in startup credits from Google. This was the primary deciding factor for choosing their services. We used Cloud SQL for PostgreSQL for about 6 months. The primary reason we migrated away from Google SQL for PostgreSQL is because we discovered a bug that was causing data corruption. This was a known bug that is fixed in newer PostgreSQL versions. However, Google SQL for PostgreSQL is several versions behind. The lack of response from the support acknowledging the issue was a big enough red-flag to move on. I am glad we did move on, because it has been 8 months since we have raised the issue, and the version of PostgreSQL has not been updated: postgres=> SELECT version(); PostgreSQL 9.6.6 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4, 64-bit(1 row) Amazon RDS for PostgreSQL Then we secured credits from Amazon and migrated to Amazon RDS for PostgreSQL — their version of PostgreSQL was kept up to date and my research into the RDS community raised no concerns. However, Amazon RDS for PostgreSQL does not support TimescaleDB extension that we planed to use for partitioning of our database. As Amazon announced Timestream (their own time-series database), it became clear that this requirement will not be addressed in the foreseeable future (this issue has been already open for 2 years). Aiven.io Then we moved to Aiven.io. Aiven.io manages PostgreSQL database for you on your cloud service provider of choice. It had all the extensions that I needed (including TimescaleDB), it did not lock us in with a particular server provider (meaning we could host our Kubernetes cluster on either of the Aiven.io supported providers), their support was helpful from the first interaction and my due diligence came back only with praise. However, what I have overlooked is that you do not get superuser access. This resulted in numerous issues (e.g., various maintenance procedures we have been using stopped working and we couldn’t use our monitoring software due to permission issues; unable to use auto_explain; logical replication requires custom extensions) and long outages that could have been prevented. Update 2019–02–05: Aiven.io have now rolled out the auto_explain support as well as the fixed Timescale 1.2 version as available maintenance updates. In general, I didn’t understand what added value Aiven.io provides – we weren’t even warned when the database was running out of storage. Running out of the disk space due to an unattended replication slot that kept the WAL growing. When this happened, support offered to upgrade the instance to one with a larger volume. While this is a fine solution, it caused a longer than necessary outage. Someone with SSH access could have diagnosed and fixed this issue in couple of minutes. And when we started to experience continuous outages due to (what later turned out to be) a bug in TimescaleDB extension used by Aiven.io support did not offer any workarounds for the issue. We’re looking into this issue and working with the timescale team, but response to most things isn’t immediate. Our help article at https://help.aiven.io/support/aiven-support-details describes the response times we provide. Which is a terribly passive response when your customer’s server is in a crashing loop (Two days later: No follow up from Aiven.io.) Despite me giving shit to Aiven.io over a couple of issues, overall their support was great. Tolerating my questions that are already covered in documentation and aiding with troubleshooting issues. The primary reason we are moving away is the lack of SSH/superuser. Self-hosted All this time I was trying to avoid the unavoidable — managing the database ourselves. Now we are renting our own hardware and maintain the database. We have a lot better hardware than any of the cloud service providers could offer, point in time recovery (thanks to Barman) and no vendor lock-in, and (on paper) it is about 30% cheaper than hosting using Google Cloud or AWS. That 30% we can use to hire a freelance DBA to check in on the servers once a day. Takeaway The takeaway here is that Google and Amazon prioritise their proprietary solutions (Google BigQuery, AWS Redshift). Therefore, you must plan for what features you will require in the future. For a simple database that will not grow into billions of records and does not require custom extensions, I would pick either without a second thought (the near instant ability to scale the instance, migrate servers to different territories, point-in-time recovery, built-in monitoring tools and managed replication saves a lot of time.). If your business is all about the data and you know that you will require custom hardware configuration and whatnot, then your best bet is hosting and managing the database yourself. That said, logical migration is simple enough — if you can start with either of the managed providers and leverage their startup credits, then that is a great way to kick start a project and you can migrate later as/if it becomes necessary. If I would start over and would have spent time to estimate how quick and how large we are going to grow, I would have used bare-metal setup and hired a freelance DBA from the first day. Bonus: Performance My primary criteria for choosing managed services was the reduced management overhead. I assumed that the cost and hardware is going to be about the same. Aiven.io has written an article where they compare PostgreSQL performance in AWS, GCP, Azure, DO and UpCloud (GCP beats AWS by a factor of 2 in all tests). Materializing data Did I mention that this is the first time I have used PostgreSQL? Up to this venture, I have been primarily using MySQL. The reason I decided to use PostgreSQL for this startup was because PostgreSQL has support for materialized views and programming languages. I thought that the materialized views is a good enough feature on its own to learn PostgreSQL. In contrast, I thought I will never run scripts in the database (MySQL teaches you that database is only for storing data and all logic must be implemented in the application code). Two years later, we got rid of most materialized views and we are using hundreds of custom procedures. But before that, there were multiple botched attempts at using materialized views. First attempt at using PostgreSQL materialized views My first use case for materialized views could be summarized as ‘having a base table enriched with a metadata’, e.g. CREATE MATERIALIZED VIEW venue_view AS WITH auditorium_with_future_events AS ( SELECT e1.venue_id, e1.auditorium_id FROM event e1 WHERE -- The 30 days interval ensures that we do not remove auditoriums -- that are temporarily unavailable. e1.start_time > now() - INTERVAL '30 day' AND e1.auditorium_id IS NOT NULL GROUP BY e1.venue_id, e1.auditorium_id ), auditorium_with_future_events_count AS ( SELECT awfe1.venue_id, count(*) auditorium_count FROM auditorium_with_future_events awfe1 GROUP BY awfe1.venue_id ), venue_auditorium_seat_count AS ( SELECT DISTINCT ON (e1.venue_id, e1.auditorium_id) e1.venue_id, e1.auditorium_id, e1.seat_count FROM auditorium_with_future_events awfe1 INNER JOIN event e1 ON e1.venue_id = awfe1.venue_id AND e1.auditorium_id = awfe1.auditorium_id WHERE e1.start_time > now() - INTERVAL '30 day' AND e1.auditorium_id IS NOT NULL AND e1.seat_count IS NOT NULL ORDER BY e1.venue_id, e1.auditorium_id ), venue_seat_count AS ( SELECT vasc1.venue_id, sum(vasc1.seat_count) seat_count FROM venue_auditorium_seat_count vasc1 GROUP BY vasc1.venue_id ) SELECT DISTINCT ON (v1.id) v1.id, v1.google_place_id, v1.fuid, v1.cinema_id, v1.street_1, v1.street_2, v1.postcode, v1.coordinates, gp1.country_id, gp1.timezone_id, COALESCE(v1.phone_number, c1.phone_number) AS phone_number, v1.display_name AS name, COALESCE(v1.alternative_url, v1.url) AS url, v1.permanently_closed_at, awfec1.auditorium_count, nearest_venue.id nearest_venue_id, CASE WHEN nearest_venue.id IS NULL THEN NULL ELSE round(ST_DistanceSphere(gp1.location, nearest_venue.location)) END nearest_venue_distance, vsc1.seat_count seat_count FROM venue v1 LEFT JOIN venue_seat_count vsc1 ON vsc1.venue_id = v1.id LEFT JOIN google_place gp1 ON gp1.id = v1.google_place_id LEFT JOIN LATERAL ( SELECT v2.id, gp2.location FROM venue v2 INNER JOIN google_place gp2 ON gp2.id = v2.google_place_id WHERE v2.id != v1.id ORDER BY gp1.location <-> gp2.location LIMIT 1 ) nearest_venue ON TRUE LEFT JOIN auditorium_with_future_events_count awfec1 ON awfec1.venue_id = v1.id INNER JOIN cinema c1 ON c1.id = v1.cinema_id WITH NO DATA; CREATE UNIQUE INDEX ON venue_view (id); CREATE INDEX ON venue_view (google_place_id); CREATE INDEX ON venue_view (cinema_id); CREATE INDEX ON venue_view (country_id); CREATE INDEX ON venue_view (nearest_venue_id); Here venue is the base table that we extend with additional data and call it venue_view. There were only two rules to adhere: _view must include all columns of the base table. _view must include all rows of the base table. There is nothing wrong with the above query. This approach worked for a long time. However, as the number of records grew to millions and billions the time it took to refresh materialized views grew from a couple of seconds to hours. (If you are not familiar with materialized views, then it is worth noting that you can only refresh the entire materialized view; there is no way to refresh a subset of a view based on a condition.) Second attempt: divide and conquer I tried to solve the issue by breaking down MVs into multiple smaller MVs, e.g. (Notice that we have moved queries from CTEs to dedicated MVs.) CREATE MATERIALIZED VIEW auditorium_with_future_events_view SELECT e1.venue_id, e1.auditorium_id FROM event e1 WHERE -- The 30 days interval ensures that we do not remove auditoriums -- that are temporarily unavailable. e1.start_time > now() - INTERVAL '30 day' AND e1.auditorium_id IS NOT NULL GROUP BY e1.venue_id, e1.auditorium_id WITH NO DATA; CREATE UNIQUE INDEX ON auditorium_with_future_events_view (venue_id, auditorium_id); CREATE MATERIALIZED VIEW venue_auditorium_seat_count_view SELECT DISTINCT ON (e1.venue_id, e1.auditorium_id) e1.venue_id, e1.auditorium_id, e1.seat_count FROM auditorium_with_future_events_view awfe1 INNER JOIN event e1 ON e1.venue_id = awfe1.venue_id AND e1.auditorium_id = awfe1.auditorium_id WHERE e1.start_time > now() - INTERVAL '30 day' AND e1.auditorium_id IS NOT NULL AND e1.seat_count IS NOT NULL ORDER BY e1.venue_id, e1.auditorium_id WITH NO DATA; CREATE UNIQUE INDEX ON venue_auditorium_seat_count_view (venue_id, auditorium_id); CREATE MATERIALIZED VIEW venue_view AS WITH auditorium_with_future_events_count AS ( SELECT awfe1.venue_id, count(*) auditorium_count FROM auditorium_with_future_events_view awfe1 GROUP BY awfe1.venue_id ), venue_seat_count AS ( SELECT vasc1.venue_id, sum(vasc1.seat_count) seat_count FROM venue_auditorium_seat_count_view vasc1 GROUP BY vasc1.venue_id ) SELECT DISTINCT ON (v1.id) v1.id, v1.google_place_id, v1.fuid, v1.cinema_id, v1.street_1, v1.street_2, v1.postcode, v1.coordinates, gp1.country_id, gp1.timezone_id, COALESCE(v1.phone_number, c1.phone_number) AS phone_number, v1.display_name AS name, COALESCE(v1.alternative_url, v1.url) AS url, v1.permanently_closed_at, awfec1.auditorium_count, nearest_venue.id nearest_venue_id, CASE WHEN nearest_venue.id IS NULL THEN NULL ELSE round(ST_DistanceSphere(gp1.location, nearest_venue.location)) END nearest_venue_distance, vsc1.seat_count seat_count FROM venue v1 LEFT JOIN venue_seat_count vsc1 ON vsc1.venue_id = v1.id LEFT JOIN google_place gp1 ON gp1.id = v1.google_place_id LEFT JOIN LATERAL ( SELECT v2.id, gp2.location FROM venue v2 INNER JOIN google_place gp2 ON gp2.id = v2.google_place_id WHERE v2.id != v1.id ORDER BY gp1.location <-> gp2.location LIMIT 1 ) nearest_venue ON TRUE LEFT JOIN auditorium_with_future_events_count awfec1 ON awfec1.venue_id = v1.id INNER JOIN cinema c1 ON c1.id = v1.cinema_id WITH NO DATA; CREATE UNIQUE INDEX ON venue_view (id); CREATE INDEX ON venue_view (google_place_id); CREATE INDEX ON venue_view (cinema_id); CREATE INDEX ON venue_view (country_id); CREATE INDEX ON venue_view (nearest_venue_id); The benefit of this approach is that: 1. We broke-down one long-transaction into many shorter transactions. 2. We are able to use indexes to speed up the JOINs. 3. We are able to refresh individual materialized views (some data changes more often than the other). The downside of this approach is that it proliferated the number of materialized views that we use and required to develop a custom solution to orchestrate refreshing of the materialized views. At the time, it seemed reasonable and I went with it. Thus was materialized_view_refresh_schedule table born and our first in-database queue: CREATE TABLE materialized_view_refresh_schedule ( id SERIAL PRIMARY KEY, materialized_view_name citext NOT NULL, refresh_interval interval NOT NULL, last_attempted_at timestamp with time zone, maximum_execution_duration interval NOT NULL DEFAULT '00:30:00'::interval ); CREATE UNIQUE INDEX materialized_view_refresh_schedule_materialized_view_name_idx ON materialized_view_refresh_schedule(materialized_view_name citext_ops); CREATE TABLE materialized_view_refresh_schedule_execution ( id integer DEFAULT nextval('materialized_view_refresh_id_seq'::regclass) PRIMARY KEY, materialized_view_refresh_schedule_id integer NOT NULL REFERENCES materialized_view_refresh_schedule(id) ON DELETE CASCADE, started_at timestamp with time zone NOT NULL, ended_at timestamp with time zone, execution_is_successful boolean, error_name text, error_message text, terminated_at timestamp with time zone, CONSTRAINT materialized_view_refresh_schedule_execution_check CHECK (terminated_at IS NULL OR ended_at IS NOT NULL) ); CREATE INDEX materialized_view_refresh_schedule_execution_materialized_view_ ON materialized_view_refresh_schedule_execution(materialized_view_refresh_schedule_id int4_ops); Names of the materialized views are stored in materialized_view_refresh_schedule table with instructions as to how often they need be refreshed. A separate program was written to perform materialization using these instructions. CREATE OR REPLACE FUNCTION schedule_new_materialized_view_refresh_schedule_execution() RETURNS table(materialized_view_refresh_schedule_id int) AS $$ BEGIN RETURN QUERY UPDATE materialized_view_refresh_schedule SET last_attempted_at = now() WHERE id IN ( SELECT mvrs1.id FROM materialized_view_refresh_schedule mvrs1 LEFT JOIN LATERAL ( SELECT 1 FROM materialized_view_refresh_schedule_execution mvrse1 WHERE mvrse1.ended_at IS NULL AND mvrse1.materialized_view_refresh_schedule_id = mvrs1.id ) AS unendeded_materialized_view_refresh_schedule_execution ON TRUE WHERE unendeded_materialized_view_refresh_schedule_execution IS NULL AND ( mvrs1.last_attempted_at IS NULL OR mvrs1.last_attempted_at + mvrs1.refresh_interval < now() ) ORDER BY mvrs1.last_attempted_at ASC NULLS FIRST LIMIT 1 FOR UPDATE OF mvrs1 SKIP LOCKED ) RETURNING id; END $$ LANGUAGE plpgsql; This program would call schedule_new_materialized_view_refresh_schedule_execution to schedule a materialized view refresh, evaluate REFRESH MATERIALIZED VIEW … CONCURRENTLY, and log the result. In general, this approach worked well. However, we soon outgrew this approach. A view that requires to scan an entire table was not feasible for large tables with billions of records. Third attempt: using MVs to abstract a subset of data I have described how we have used MVs to effectively extend a table. This approach did not scale with large tables. Thus the third iteration was born: instead of using materialized views to extend the base table, create materialized views that abstract a data domain. Due to its size venue_view could remain as it was, but a hypothetical view such as event_view with billions of records would become last_week_event, future_event, etc. This approach works and we continue to use several such materialized views. Fourth attempt: materialized table columns While the latter approach covered all our day to day operations, we still needed to run queries on the historical data. Running these queries without materialized views would take a lot of index planning for individual queries. Furthermore, running long transactions against the master instance would have prevented autovacuum and caused table bloat. I could have created a logical replication and allowed analysts to run whatever queries on that instance without blocking autovacuum. However, the bigger problem is that as a startup we cannot afford queries that take hours or days to run. We need to move faster than anyone else. Thus was born the current solution: materialized table columns. The principal is simple: Tables that describe entities that we want to enrich with additional information are altered to include a materialized_at timestamptz column and a column for each data point that we want to materialize. In the example of the venue_view, we would get rid of the materialized view entirely and add materialized_at, country_id, timezone_id, phone_number and other columns that were present in the original venue_view materialized view to the venue table itself. Then there is a script that observes all tables that have materialized_at column and every time it detects a row where materialized_at IS NULL it computes new values for the materialized columns and updates the row, e.g. CREATE OR REPLACE FUNCTION materialize_event_seat_state_change() RETURNS void AS $$ BEGIN WITH event_seat_state_count AS ( SELECT essc1.id, count(*)::smallint seat_count, count(*) FILTER (WHERE ss1.nid = 'BLOCKED')::smallint seat_blocked_count, count(*) FILTER (WHERE ss1.nid = 'BROKEN')::smallint seat_broken_count, count(*) FILTER (WHERE ss1.nid = 'EMPTY')::smallint seat_empty_count, count(*) FILTER (WHERE ss1.nid = 'HOUSE')::smallint seat_house_count, count(*) FILTER (WHERE ss1.nid = 'SOLD')::smallint seat_sold_count, count(*) FILTER (WHERE ss1.nid = 'UNKNOWN')::smallint seat_unknown_count, count(*) FILTER (WHERE ss1.id IS NULL)::smallint seat_unmapped_count, count(*) FILTER (WHERE ss1.nid IN ('BLOCKED', 'BROKEN', 'HOUSE', 'SOLD', 'UNKNOWN')) seat_unavailable_count FROM event e1 LEFT JOIN event_seat_state_change essc1 ON essc1.event_id = e1.id LEFT JOIN event_seat_state_change_seat_state esscss1 ON esscss1.event_seat_state_change_id = essc1.id LEFT JOIN cinema_foreign_seat_state fcss1 ON fcss1.id = cinema_foreign_seat_state_id LEFT JOIN seat_state ss1 ON ss1.id = fcss1.seat_state_id WHERE essc1.id IN ( SELECT id FROM event_seat_state_change WHERE materialized_at IS NULL ORDER BY materialized_at DESC LIMIT 100 ) GROUP BY essc1.id ) UPDATE event_seat_state_change essc1 SET materialized_at = now(), seat_count = essc2.seat_count, seat_blocked_count = essc2.seat_blocked_count, seat_broken_count = essc2.seat_broken_count, seat_empty_count = essc2.seat_empty_count, seat_house_count = essc2.seat_house_count, seat_sold_count = essc2.seat_sold_count, seat_unknown_count = essc2.seat_unknown_count, seat_unmapped_count = essc2.seat_unmapped_count FROM event_seat_state_count essc2 WHERE essc1.id = essc2.id; END $$ LANGUAGE plpgsql SET work_mem='1GB' SET max_parallel_workers_per_gather=4; Once again, this required to write a custom solution that observes tables and manages their materialization, row and column expiration logic, etc. I am currently developing an open-source version that I plan to publish in the near future. The biggest benefit of this approach is that you can be as granular as you want about updating the materialized table columns: you can update individual rows and you can update individual columns (e.g. when new materialized column is added and there is a need to populate new column values, you would only need to generate value for that column; no need to run full materialization query). Furthermore, as the updates are granular, they can all be applied in a near real-time. Takeaway The takeaway here is that PostgreSQL materialized views are a great feature for small datasets. However, as the dataset grows, careful planning is required for how data is going to be accessed and what materialization strategy supports such requirement. Using a combination of granular materialized views and materialized table columns we were able to enrich the database in real-time and use it for all our analytics queries without adding the complexity of a logical replicate for data-warehousing. Using database as a job queue This has less to do with the volume of the data that we process and more with how we are using the database. As I mentioned earlier, my goal was to reduce the number of services that participate in the data processing pipeline. The added benefit of containing the job queue within a database is that you are able to keep and query records of all jobs (and their attributes) associated with every data point that is in the database. Being able query jobs and logs associated with every data point, join it with parent and descendent jobs, etc. proved extremely valuable for flagging failing jobs and pin-pointing the origin of the issue. Building a simple, reliable and efficient concurrent work queues using PostgreSQL. It is worth noting that normally, a RDBMs would be a poor choice for a concurrent job queue (for reasons outlined in What is SKIP LOCKED for in PostgreSQL 9.5?). However, in case of PostgreSQL, we can use FOR UPDATE … SKIP LOCKED to build a simple, reliable and efficient concurrent work queues. The downside is the performance: Each transaction scans the table and skips over locked rows, so with high numbers of active workers it can land up doing a bit of work to acquire a new item. It’s not just popping items off a stack. The query will probably have to walk an index with an index scan, fetching each candidate item from the heap and checking the lock status. With any reasonable queue this will all be in memory but it’s still a fair bit of churn. – https://blog.2ndquadrant.com/what-is-select-skip-locked-for-in-postgresql-9-5/ I did not pay enough attention to this warning and landed myself in quite a bit of trouble. The short version is that the first version of the query used to schedule jobs took a long time to execute, which meant meant that worker nodes were primarily sitting idle, we were wasting valuable resources and important tasks were not done in time. The solution was quite simple: a dedicated table that is populated with a list of outstanding tasks. Picking up a job from this table is as simple as: CREATE OR REPLACE FUNCTION schedule_cinema_data_task() RETURNS table(cinema_data_task_id int) AS $$ DECLARE scheduled_cinema_data_task_id int; BEGIN UPDATE cinema_data_task_queue SET attempted_at = now() WHERE id = ( SELECT cdtq1.id FROM cinema_data_task_queue cdtq1 WHERE cdtq1.attempted_at IS NULL ORDER BY cdtq1.id ASC LIMIT 1 FOR UPDATE OF cdtq1 SKIP LOCKED ) RETURNING cinema_data_task_queue.cinema_data_task_id INTO scheduled_cinema_data_task_id; UPDATE cinema_data_task SET last_attempted_at = now() WHERE id = scheduled_cinema_data_task_id; RETURN QUERY SELECT scheduled_cinema_data_task_id; END $$ LANGUAGE plpgsql SET work_mem='100MB'; The main task definition is stored in cinema_data_task . cinema_data_task_queue is used only for queuing ready to execute tasks. The biggest gotcha is that the priority and limitations of which tasks can run changes every time a new task is executed. Therefore, instead of scheduling large number of jobs, we are running a process that every second checks if the queue is running dry and populates it with new tasks, e.g. CREATE OR REPLACE FUNCTION update_cinema_data_task_queue() RETURNS void AS $$ DECLARE outstanding_task_count int; BEGIN SELECT count(*) FROM cinema_data_task_queue WHERE attempted_at IS NULL INTO outstanding_task_count; IF outstanding_task_count < 100 THEN INSERT INTO cinema_data_task_queue (cinema_data_task_id) SELECT cdtq1.cinema_data_task_id FROM cinema_data_task_queue(100, 50, 100, false) cdtq1 WHERE NOT EXISTS ( SELECT 1 FROM cinema_data_task_queue WHERE cinema_data_task_id = cdtq1.cinema_data_task_id AND attempted_at IS NULL ) ON CONFLICT (cinema_data_task_id) WHERE attempted_at IS NULL DO NOTHING; END IF; END $$ LANGUAGE plpgsql SET work_mem='50MB'; After the task is completed, the reference to the task is deleted from cinema_data_task_queue . This ensured that table scans are quick and do not keep the CPU busy. This approach allowed us to scale to 2000+ concurrent data aggregation agents. Note: The 100 outstanding tasks limit is somewhat arbitrary. I have experimented with values as large as 10k without any measurable performance penalty. However, as long as we can keep the queue from drying out, then the more granular the scheduling is, the better we load-balance data aggregation between different sources, the sooner we can stop pulling data from failing data sources, etc. Takeway If you are going to use database as a job queue, the table containing the jobs must be reasonable size and the query used to schedule the next job execution must not take more than couple of milliseconds. Miscs These 3 things were the biggest challenges when scaling the database. Some other gotchas include: When you have hundreds of clients each running dozens of queries a second then latency between the database and the database clients matters a lot. I have observed that the latency between our database (at the time) hosted on AWS RDS and our Kubernetes cluster hosted on GKE was 12ms. By moving the database to the same datacenter and reducing latency to <1ms, our job throughout increased 4x. Identifying latency between different cloud providers. Column order matters. We have tables with 60+ columns. Ordering columns to avoid padding saved 20%+ storage (https://blog.2ndquadrant.com/on-rocks-and-sand/). If you are going to run long-queries on master, evaluate vacuum_freeze_table_age to prevent table bloat. Two configurations that I do not see being talked enough about: from_collapse_limit, join_collapse_limit . Both configurations default to 8. Not knowing about these configuration caused a lot of headache debugging confusing execution plans. We increased from_collapse_limit to 20 and join_collapse_limit to 50. It is unclear to me what is the reason the defaults are low. There appears to be no penalty for having them infinitely high. Plan for table bloat and how to repair it. As the database grows large, VACUUM FULL becomes unfeasible. Explore pg_repack and pg_squeeze . Constantly monitor pg_stat_statements . Sort by total_time. Top queries are the low hanging fruits. Constantly monitor pg_stat_user_tables. Identify underused indexes and monitor dead tuple accumulation. Constantly monitor pg_stat_activity . Identify bottlenecks due to locks and refactor the offending transactions. Bonus: Slonik PostgreSQL client We were using PostgreSQL a lot. We began by using node-postgres. node-postgres provided a great protocol abstraction. However, the code felt verbose and we kept adding new helpers to abstract repeating patterns and to enable debugging experience. We needed these helpers across many different programs. Therefore, I ended up developing Slonik – A PostgreSQL client with strict types, detail logging and assertions. Slonik helps us to keep the code lean, protects against SQL injections, enables detail logging and application log correlation with auto_explain. Continue reading: Processing large volumes of data safely and fast using Node.js and PostgreSQL About designing a PostgreSQL client for Node.js medium.com Acknowledgements I want to thank Freenode #postgresql community for the warm welcome, mentoring and aiding throughout my PostgreSQL journey. Whether I asked esoteric questions, dumb questions, needed help debugging an issue or just wanted to learn a bit of history about PostgreSQL origins, I always got full support from #postgresql community. I especially want to thank Berge, depesz, ilmari, Myon, nickb, peerce, RhodiumToad, Snow-Man, xocolatl and Zr40: your support halved the time I needed to learn as much as I have up to now. If (you support my open-source work through Buy me a coffee or Patreon) {you will have my eternal gratitude 🙌}

  • Anonymous  mạo danh  ( Habits )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 10:09Link chia sẻ

    10 Life-Changing Habits You Can Form in 66 Days Trust me — even you have time for a daily walk What sets them apart are the simple acts we don’t see Michael Thompson Michael Thompson Follow Friend helping an injured team mate at urban sports ground. Photo: Hinterhaus Productions/Getty WWhen I was growing up, my dad told me that the fastest way to get what you want is to get to know the people who already have it. But I didn’t really understand his advice until my wife and I moved to rural Spain to start a family. Cut off geographically from the centers of my industry, I had to create my own online networks from scratch. Since I couldn’t go into the city every day to make connections in the coaching and writing worlds, I decided to take just one hour a week to reach out online to people whose work I enjoyed. Quickly, that decision began paying dividends, as I started to build a network of people I admired — a network that today includes top businesspeople, renowned coaches, and prolific creators. The fastest way to get what you want is to get to know the people who already have it. It took me 15 years to follow my dad’s advice, but I’m glad I finally did. In learning how successful people navigate their own lives, I’ve managed to better steer my own. The most powerful discovery I’ve made is that successful people don’t have any hidden superpowers. They aren’t doing anything dramatically different from you or me. They’ve simply made the decision to do these six things consistently. They proactively share everything they have I run an online group with a handful of the people I’ve met through my weekly outreach. From the beginning, one thing that’s stood out to me is their generosity. All of them make it a point to share their time and resources, and they also don’t hesitate to give their best ideas away for free. That’s not to say that they’re selfless to their own detriment. I think often of something my mentor, leadership speaker Conor Neill, once said: “The fastest way to see your ideas become a reality is by giving them to someone else.” And the more you offer to the world, I’ve learned, the more opportunities you will have in the future. The phrase “When you give, you get” is cliché for a reason: It’s grounded in truth. They write things down The phrase I hear most often when dealing with highflyers is: “Give me a second — I’m taking notes.” They understand that achieving their goals is all about analyzing what’s happening around them, recognizing patterns, and recalling what they’ve learned. Writing down their thoughts and ideas on a daily basis expedites this process. Moving slowly now — taking the time to think, and process — is the key to moving fast later. They see failure as part of the process Good salesmen don’t focus on how many deals they’re closing. They focus on the number of people they’re contacting each day. Success comes from giving yourself opportunities to try. Writer and entrepreneur Seth Godin goes as far as to say, “If I fail more than you do, I win.” Every successful person I’ve met embraces this mindset. They don’t see their actions as failures — instead, they know messing up is a necessary step on the path to one day getting things right. Mistakes are simply an opportunity to reevaluate and do things better the next time. They seek out negative feedback The easiest way to stomach negative feedback is to ask for it. It’s hard to get angry with someone whose advice you request to hear. Successful people understand this. They don’t hesitate to ask others for their opinion. They genuinely want to know what they may have missed and where they can do better. But they don’t just ask anyone. They understand that wasting a person’s time jeopardizes trust. Instead, they take the time to identify the right people who can give them the feedback they truly need to hear. “I do not learn anything when I am speaking. I learn a lot when I am listening.” They don’t hesitate to say no Recently, my friend Rafael Sarandeses, a racecar driver turned serial entrepreneur, told me something that’s stuck with me: “Everyone says time is our most valuable asset. But it’s not. Our presence is.” In thinking about his words, I’ve come to realize that the most successful people aren’t necessarily any smarter, faster, or stronger than everyone else. They just choose to spend more time living in the present moment. They aren’t afraid to say no to opportunities that will distract them from their goals. I used to think this was rude, but I now believe Warren Buffett got it right when he said: “Integrity is saying no to most things.” They listen more than they speak Jim Quigley, the former CEO of Deloitte, put it best: “I do not learn anything when I am speaking. I learn a lot when I am listening.” Both relationships and breakthroughs are built by understanding people’s needs. The fastest way to impede progress in both of these areas is by prioritizing your one mouth over your two ears. Together, these six things have formed my most important, and biggest realization: Successful people don’t try and reinvent the wheel. They simply do the right things on a daily basis. Anyone can share. Anyone can ask for feedback. Anyone can lift up the people around them. But to move from good to great, you can’t just do these things when you feel like it. You have to do them when you don’t. The key is consistency. There is no hack.

  • Anonymous  mạo danh  ( Analysis in Python )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 10:11Link chia sẻ

    7 things to quickly improve your Data Analysis in Python Take your Data Analysis to the next level! Thank you (…again) Turning a blind eye to the completely obvious risk of sounding like a broken record I just want to voice yet another giant thank you to everyone who’s been reading and sharing my last two articles: Python tricks 101, what every new programmer should know and Exploring your data with just 1 line of Python. Here I was, thinking that the “Python tricks 101…” article had been successful and then you go ahead and blow any expectations away once more. So, to quote myself: “Thanks and lets get on with it!” For this article I thought it would be nice to create a list of things I’ve learned that have sped up or improved my average day-to-day data analysis. So without any further ado, here’s a list of what we’ll be covering in the article: Content overview: Pandas Profiling Plotting Pandas data using Cufflinks & Plotly IPython Magic Commands Fancy formatting in Jupyter Jupyter shortcuts Multiple outputs per cell in Jupyter (or IPython) Instantly create slideshows of your Jupyter Notebook If these sound like something you might enjoy learning about, keep scrolling. Note that this will be quite a long one. Still, I’ve tried my best to be as concise and as to-the-point as possible. I hope you enjoy! #1: Pandas Profiling This should be no surprise to those of you who’ve been following me. The benefits of this tool are obvious. The animation below is the results of calling the simple method df.profile_report(), take a look at the resulting report yourself: Using this tool is simple a matter of installing and importing the Pandas Profiling package. I wont spend too much time on this one since I’ve already written a small article on the subject, so if you want to know more about this gem of a package, then please read my article about Pandas Profiling here: Exploring your data with just 1 line of Python Getting all your standard data analysis done in less than 30 seconds. The wonders of Pandas Profiling. towardsdatascience.com #2: Plotting Pandas data using Cufflinks & Plotly Most of us who’re quote-unquote “experienced” Data Scientist or Data Analysts, will be quite familiar with the integration between matplotlib and pandas. Namely the fact that you can make quick plots of a simple pd.DataFrame or pd.Series by simply calling the .plot() method: Kind of boring right? Now this is all fine and dandy, but how about an interactive, pan-able, zoom-able, scale-able plot instead? Cufflinks to the rescue! (courtesy of Plotly) To install Cufflinks in your environment simply run ! pip install cufflinks --upgrade in your favorite terminal and you’re ready to go. Take a look at the following: Much better! Notice that the only thing that changed above is the imports and the setting of cf.go_offline() for Cufflinks. Other than that it’s simply a matter of changing your .plot() method to .iplot() . Other methods like .scatter_matrix() can give you some really nice visualisation as well: Very cool! I urge anyone that works with a lot of data visualisation to take a look at the documentation for both Cufflinks and Plotly to discover more methods for yourselves! #3: IPython Magic Commands The ‘Magics’ of IPython are basically a series of enhancements that IPython has layered on-top of the standard Python syntax. Magic commands come in two flavors: line magics, which are denoted by a single % prefix and operate on a single line of input, and cell magics, which are denoted by a double %% prefix and operate on multiple lines of input. Below are just a few of the useful functionalities provided by the ‘Magics’: %lsmagic: Find them all. Why not start with some good-old self-help? If you’re to remember just one Magic Command it should probably be this one. Executing the %lsmagic command will grant you a full list of all available Magic Commands: %debug: Interactive debugging. This is probably the Magic Command I use the most. Most of us have tried it: You find yourself executing a code-block that keeps breaking and you — in pure desperation — write 20 print()-statements to output the contents of each variable. Then, when you finally fix the issue, you have to go back and delete all the printing functionality again. But not anymore! Simply execute the %debug command after encountering a problem and execute whatever part of the code you want: So what’s happening above? We have a function that takes a list as input and squares all even number. We run our function but something breaks. We’re not told at what! We use the %debug command to tab into the function at the time it broke. We ask the debugger to tell us the value of x as well as the type(x). The failure is obvious. We’re passing '6' as a string! This is highly useful for more complex functions as I’m sure you can imagine! %store: Pass variables between notebooks. This one is pretty cool as well. Let’s say for the sake of argument, that you spend a while cleaning some data in a notebook, now you want to test some functionality in another notebook so you have to either implement the functionality in the same notebook or save your data and load it in the other notebook right? Not with %store ! Simply store the variable and retrieve it in whatever other notebook you want: %store [variable] stores the variable. %store -r [variable] reads/retrieves a stored variable. %who: List all variables of global scope. Ever assigned some value to a variable but forgot the variable name? Maybe you accidentally deleted the cells responsibility for assigning the value to the variable? With %who you get a list of all globally assigned variables: %%time: Timing with magic. With this little command you get all the timing information you might need. Simply apply the %%time command to any piece of executable code you want and you’ll get an output like this: 24 micro-seconds.. Sloppy %%writefile: Write the cell-content to a file. And this will be the last one I’ll talk about in this article. This one is especially useful for when you’ve written some complicated function or class in your notebook that you want to save in its own file, separate from the notebook. Simply prefix the cell of your function or class with the %%writefile command followed by a filename to save it: As you can see, we can simply save the function we’ve created to a “utils.py” file and then we’re free to import it in whatever fashion we want. In other notebooks as well! (As long as they’re in the same directory of the utils.py file) #4: Fancy formatting in Jupyter This one is super cool! Basically Jupyter allows for some HTML / CSS formatting in the markdown cells. These are the once I use the most: The blue and stylish one: <div class="alert alert-block alert-info"> This is <b>fancy</b>! </div> The red and slightly panic-inducing one: <div class="alert alert-block alert-danger"> This is <b>baaaaad</b>! </div> The green and calming one: <div class="alert alert-block alert-success"> This is <b>gooood</b>! </div> Take a look at them in action here: These are quite nice for when you want to present some findings in a Notebook format! #5: Jupyter shortcuts Accessing and learning the keyboard shortcuts, you can use the command palette: Ctrl + Shift + P . This brings up a list of all functionalities of the notebook. The following is an excerpt of the most basic commands: Esc : This will take you into command mode. This is also the mode in which you can navigate your notebook using the arrow-keys. While in command mode: A and B : Inserts a new cell [A]bove or [B]elow the current cell. M : Changes the current cell to [M]arkdown. Y : Changes the current cell to code. (y tho?) D,D : [D]efinetly [D]eletes the current cell. Enter : Takes you back into edit mode for the current cell. While in edit mode: Shift + Tab : Shows you the Docstring (documentation) for the the object you typed in the current cell — keep pressing the shortcut to cycle through modes of documentation. Ctrl + Shift + - : Splits the current cell from where your cursor is. Esc + F : Find and replace on your code excluding outputs. Esc + O : Toggles cell output. Selecting Multiple Cells: Shift + Down and Shift + Up : Selects the next sell in a downwards or upwards direction. I think you can use the power of deduction to find out which is which. Shift + M : Merges the selected cells. As a side-note, remember that once cells are selected, you can delete / copy / cut / paste / run them as a batch. #6: Multiple outputs per cell in Jupyter (or IPython) This one is great. Have you ever wanted to display the .head() and the .tail() of a pandas DataFrame but you you gave up halfway-through because it was too much of a hassle to create the additional code-cell to run the .tail() method? Fear no more, now you can display all the outputs you want using the following lines of code: from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all" Now lo and behold, the power of multiple outputs: Easy peasy lemon squeezy #7: Instantly create a slideshow of your notebook With RISE you can instantly turn your Jupyter Notebook into a slideshow with a single keystroke. Best of all, the notebook is still active, so you can perform live coding while presenting! Take a look: Source: https://github.com/damianavila/RISE To use this brilliant tool, simple install RISE either by virtue of conda or pip depending on your environment: conda install -c conda-forge rise /// OR /// pip install RISE Now you’ll be able to create fancy slides from your notebook by simply clicking the new button: Closing remarks Thanks for reading. I would urge anyone to explore each point in more detail on your own to find out exactly what and how you want to apply them to your own workflows. Hopefully, you found the article useful! If you enjoyed it and want to see and learn more, be sure to follow my profile! Peter Nistrup - Medium Read writing from Peter Nistrup on Medium. DATA SCIENCE, STATISTICS & AI ... Towards Data Science Sharing concepts, ideas, and codes.

  • Anonymous  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:09Link chia sẻ

    Why Cutting Costs is Expensive: How $9/Hour Software Engineers Cost Boeing Billions Eric Elliott Eric Elliott Follow Photo by Liam Allport (CC-BY-2.0) On October 29, 2018 Lion Air Flight 610, a 737 MAX 8 flight from Jakarta, Indonesia to Pangkal Pinang, Indonesia, crashed into the sea 13 minutes after takeoff, killing all 189 people aboard. Investigations into the precise cause of the crash are still ongoing, but investigators believe that the crash may have been caused by erroneous activation of commands from the Maneuvering Characteristics Augmentation System (MCAS) which caused the aircraft to pitch nose down to avoid danger based on airspeed, altitude and angle of attack sensor readings. March 10, 2019, Ethiopian Airlines Flight 302, also a 737 MAX 8 went down under similar circumstances, killing all 157 people aboard. Flight 302 also reporting possible erroneous AND (Aircraft Nose Down) commands. According to Wikipedia: “In the next 10 seconds the trim moved back up to 2.3 units as a result of pilot input and the pilots agreed on and executed the stabilizer trim cut-out procedure, cutting power to the trim motor operated by MCAS”. After the 2nd accident, the Boeing 737 Max was grounded world-wide, and over $6 billion dollars evaporated from the company’s market cap virtually overnight. Boeing Stock Ticker 2 days after the flight 302 crash. The price fell from $422 to $375 in 2 days. The short-term impact is just the beginning, though. If Boeing doesn’t fix the crisis effectively and restore the public trust, it could materially impact the long-term stability of the company. According to Goldman Sachs, Boeing 737 sales account for 33 percent of Boeing’s projected sales for the next five years. The good news is, according to a Boeing official speaking to CNN Business: “We believe this can be updated through a software fix.” It seems that the MCAS system can fail and send the aircraft into a steep nose dive from which pilots are unable to recover. Whether this flaw is software or microprocessor hardware, it’s a computing system failure of a life-critical system. Normally, for such systems, it’s not uncommon to employ many lines of defense in order to assure quality control. Some common lines of defense in software development include: Requirements Gathering Requirements Specification & Review Risk Analysis Test Driven Development (TDD) Software Linting Static Analysis Software Inspection / Code Review Model Simulation Formal Methods Acceptance Testing I primarily write consumer applications governing non-life-critical systems for millions of users. All the teams I have led or been a part of recently have used systems for requirements gathering, specification review (using technical Readme Driven Development with peer review), TDD, production simulation using Continuous Integration/Continuous Delivery (CI/CD) to ensure that the software will work in the production environment, linting, static analysis, code review (a trimmed-down version of software inspection), and acceptance testing. We invest heavily in software quality, and pay even our most junior engineers at least $100k/year no matter where they live in the world in order to attract the best software engineers we can find to produce high quality software that is easy to maintain. We do employ junior developers but we ensure that there are always enough senior level engineers to provide mentorship, code review, and support. We also invest heavily in training and mentorship to ensure that every engineer on our teams are supported with the understanding they need to build reliable software systems. If I were in charge of a life-critical system, I would double down on quality and consider adding more thorough training, mentorship, requirements gathering, risk assessment, software inspection (e.g., employ a language-relevant and data-backed variation of NASA’s Power of 10 rules as a code inspection checklist), static analysis, and even formal methods for critical systems to mathematically prove that our algorithms are correctly specified. If I had Boeing’s budget, I’d also invest in research to see if the selection of programming language could make a difference. In my experience, investing in mentorship and the other quality measures I’ve already discussed makes a much bigger difference than language selection, but with life-critical systems, a data-driven decision that could reduce the likelihood of defects even a little bit could be the difference between life and death. We need better research on software quality, and with a market cap in excess of $200 billion to protect, I’d think funding these kinds of studies would be a no-brainer for Boeing. We don’t invest heavily in software quality because our teams have big budgets (they’re a drop in the ocean compared to Boeing’s engineering budget). We invest heavily in software quality because it helps us move faster and save money in the long-run. In software, slow is fast. Fast is Slow and Cheap is Expensive, So Why Are So Many Managers Cheap? To cut costs, engineering managers often rush developers, impose arbitrary unrealistic deadlines, or in the case of Boeing, outsource engineering to cheap contractors to try to increase production bandwidth. Boeing’s cultural emphasis on cost savings seems to have trickled all the way down to the engineers working on the 737. One 737 contract software engineer from HCL, an Indian company Boeing outsourced to, illustrates the cost cutting culture on his resume: “Provided quick workaround to resolve production issue which resulted in not delaying flight test of 737-Max (delay in each flight test will cost very big amount for Boeing).” Regardless of which systems these engineers worked on, if you foster an engineering culture where developers are made to feel that management values fast and cheap over continuous progress and quality software, that will have a tremendously negative impact on both the quality and the timely delivery of your software. Buggy software takes longer to build. When management over-emphasizes cost savings, developers feel rushed. When developers feel rushed: Mentorship & reviews halt Bugs pile up Tests get skipped Communication suffers Developers burn out Productivity suffers Mark Rabin, who worked in a Boeing flight-test group that supported the 737 Max, told Bloomberg that the decision to outsource engineering to HCL was “controversial because it was far less efficient than Boeing engineers just writing the code. […] It took many rounds going back and forth because the code was not done correctly.” According to Rabin, one manager shared at an all-hands meeting that Boeing didn’t need senior engineers because its products were mature. That anecdote is what prompted me to write this article. In case there are any doubts, letting junior engineers code without senior engineers to review their work and guide them is equivalent to stashing time bombs all over the codebase. When it comes to engineering, fast is slow, and cheap is expensive. The phrase “slow is fast” is well known in engineering circles. It has origins in the military phrase “slow is smooth and smooth is fast”, and it’s a form of uncommon sense. Everybody seems to know it’s true, but very few companies are good at putting it into practice: particularly when they’re under pressure and they need it the most. Boeing was facing a serious competitive threat from their rival Airbus. In 2010, Airbus announced the new A320neo which was 7% more fuel efficient, and sold more in a week than Boeing 737 sales for the entire year of 2010. Boeing needed to answer back, fast. To make the offering attractive to airlines, they decided to base their answer on the existing 737, which both saved the time of designing a new platform from scratch, and also locked them into a legacy platform with similar controls and instrumentation to all the previous models, dating back to the 1960’s. That choice was also an important sales talking point for airlines who would need to re-certify pilots if they made too many changes. This would be a serious engineering challenge. To avoid losing too much ground to Airbus, they decided they would try to make the new 737 available just a few months after Airbus shipped the A320neo. They gave themselves 6 years to deliver the new model, which shaved more than a year off the time it took them to ship the 787 and 777. In other words, they started the project with an optimistic deadline in mind, but instead of making it aspirational, they committed to it hard. Before they even began, they had locked all of the constraints of the project management triangle. Project Management Triangle Scope was constrained by the ambitious engineering goals that were preset by the competition. Time was locked in order to avoid a default win by Airbus. That meant that the only lever they had left to ensure quality was to ensure that the project had an adequate budget. But the culture of Boeing was already locked into a cost cutting mandate. The only thing left to give was quality. The problem with cost cutting culture is that companies like Boeing get so obsessed with it that it ends up costing them far more than they save. Boeing’s initial budget for the 737 Max was $3 billion. In spite of the efforts to save time and money, they landed several billion dollars over budget and delivered late. The ensuing disasters cost them tens of billions in market cap, $30 billion in airline order cancellation threats, and unmeasurable damage to the Boeing brand. They could have invested billions of dollars more to follow better engineering practices and still come out far ahead. This all serves as a great lesson for all software managers and engineers: In software, fast is slow and cheap is expensive. An investment in quality is an investment in productivity, cost savings, and stronger sales. What could have been a huge win for Boeing had they not been obsessed with cost cutting turned into a big disaster that took a hatchet to the Boeing brand. Don’t repeat Boeing’s mistakes. Related Articles for JavaScript Developers If you’re a JavaScript developer, these resources can help you improve your software quality process: TDD Changed My Life TDD Day — A day dedicated to TDD training Streamline code reviews with ES Lint and Prettier The Essential Guide to Building Balanced Development Teams Eric Elliott is the author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of EricElliottJS.com and DevAnywhere.io, he teaches developers essential software development skills. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall StreetJournal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He enjoys a remote lifestyle with the most beautiful woman in the world.

  • Anonymous  mạo danh  ( Unmotivated )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 10:06Link chia sẻ

    You’re Not Lazy, Bored, or Unmotivated And the cure for what really ails you can be found in an advertising slogan you’ve heard before don’t know you, but I know this: You have internet access, and enough time to spend some of it reading. It sounds obvious, but this tells me two more important things about you: One, you’re in the top half of humanity’s wealth distribution, because the other half of the world’s population isn’t even online yet. And two, since you’re here, you’re likely fighting a very modern human fight. You’ve probably already got the basics covered — food, a roof over your head. For you, the obstacles to a better, happier life aren’t all concrete. You’re trying to defeat more abstract enemies: laziness, boredom, self-doubt, procrastination. Here’s the thing: All these concepts are one and the same. And there’s only one way to deal with them. You’re not lazy. You’re not bored. You’re not unmotivated. What you are — what all of us are — is afraid. And the best advice for overcoming fear is the bland three-word sentence Nike turned into the most successful marketing slogan of all time (after slightly tweaking a serial killer’s last words): Just do it. You’re not unmotivated “I’m not motivated” is never a true statement. Not motivated to do what? Work? In that case, aren’t you motivated to avoid it? Every action human beings ever take is driven by some kind of incentive, whether it’s money, or happiness, or peace, or satisfying your conscience. Your motivation may not always be obvious, but it’s always there. If you hate every second of the workday, you’re not unmotivated to change your job. But you haven’t, which means there’s something holding you back. For some reason, it feels like you can’t make the change. It’s too hard, requires too much effort, makes you too vulnerable to rejection. So you don’t even try. But that’s entirely different from not being motivated, and it’s only a sign that it’s time to dig into this feeling. You’re not bored I once struck up a chat on Tinder with a woman who was a scrum master and a physiologist. She was in business school, but, really, she wanted to study fashion and launch her own creative company. In short, she was a fascinating person. When I asked her why she even used the app, she spoke the most common lie in the world: “I’m bored.” How do I know it was a lie? Because no one is ever bored anymore. There’s no reason to be. Most of us don’t even choose to try. We’re 100% connected, 100% of the time. We just pretend to be bored so we can keep filling our days with meaningless distractions, like small talk on Tinder, because we know what lies beneath the stillness: existential dread. Go through the door of boredom, and that’s what you’ll find. The great scientist and mathematician Blaise Pascal once said: “All of humanity’s problems stem from man’s inability to sit quietly in a room alone.” You’re not bored. You’re terrified of being alone with yourself in your own head. You’re not lazy Laziness is the scapegoat of everyone who’s trying to capitalize on your claim of “being bored.” “You’re not bored — you’re boring!” is what they’ll tell you. You need a hobby, or a calling, or a $250 fitness program with a personalized meal plan. This, too, is nonsense. Laziness, like boredom, doesn’t exist. As psychology professor Devon Price has explained on Medium: “No one wants to feel incapable, apathetic, or ineffective. If you look at a person’s action (or inaction) and see only laziness, you are missing key details.” What looks like laziness or self-sabotage, he wrote, is almost always something else — a lack of confidence, an unmet need. Once again, it’s not a lack of motivation, an inexplicable unwillingness to act, that obstructs your path to success and happiness. It’s the invisible boundaries in your head that you’re tripping over — sometimes without ever moving at all. Medicating the symptoms Laziness, boredom, procrastination — all of these are symptoms of the same disease. My dad once told me this story: A colleague was driving to an appointment with a customer. As he was overtaking a truck, the truck moved into his lane. Seeing his car get crushed from the passenger side and compressing towards him, his animal instincts kicked in. Unleashing an ancient roar at the top of his lungs, he ripped out the gear lever of his automatic gearbox with one hand. This is an automatic gearbox: Credit: OSX/Wikipedia Clearly, we’re not talking about breaking off a knob on your radio. It’s a heavy, difficult-to-break piece of machinery. That’s the power of fear. It can make you do unimaginable things. Now imagine turning this same power not onto your physical environment, but against your own mind. That’s what we tend to do when faced with a struggle — we take this unbelievable source of raw power and turn it on ourselves. We do it by self-medicating, by concocting and treating powerful symptoms, like laziness and boredom. Instead of seeing everyone rip their gear levers out of their cars, we see them staring at their phones on the subway, or procrastinating on a deadline by bingeing TV, or getting dragged into dumb fights on social media. We’re all afraid of something; we just choose to medicate that fear differently. The dog that keeps on chasing The number of things you can be afraid of is endless. You’re afraid of dying early from a plane crash or an armed robbery or a natural disaster or a newly discovered parasite, even though the odds strongly suggest you won’t. You’re afraid of being alone because of existential dread, but also because it looks weird and gets weird looks, and if your parents haven’t asked why you’re still single yet, your friends most certainly have. You’re afraid of writing the first chapter of your book, because who thinks that’ll ever work out? But you’re also afraid of wasting 10 more hours watching Game of Thrones, especially now that you’ve already seen the whole thing twice. You’re afraid of never being rich, but not nearly as much as you’re afraid of losing whatever you already have. I could keep going all day. Fear of failure, fear of success, fear of looking stupid, fear of losing something or someone, fear of fear, fear of wasting time, fear of not being good enough, smart enough, attractive enough. In order to deal with all these fears, you could buy a new book from a new guru each week, collect a stunning array of probably-placebo supplements on your shelf, churn through organizational systems and mantras and resolutions. Or, you could wake up and realize that all these fears are the same thing. Fear is the same dark creature that’s always plagued us, and it will continue to invent new tricks till kingdom come. You have to find a way to live in spite of it. That dog is going to keep chasing you until you die. And some days, it will get to you. But you have to keep moving. Forever. The day you run into the bright light at the end of the tunnel, I want you to look back and give the finger to that dog trailing behind. The cure I’m no more qualified to talk about fear that any random guy you’d meet on the street. I don’t have a degree in psychology, or even formal training as a writer. But, like you, I have lived with fear my whole life. And, somehow, I’ve still arrived in a place where I have a job I love, lots of time to spend how I want, and a general sense of happiness. I have my own issues to resolve, but I feel okay taking life one day at a time. And that’s what it’s about. Beat the dog again and again. And again. My theme for this year is ‘focus.’ Across all areas of my life, I’m trying my best to drill down to what really matters: projects, people, how I manage my time and my energy. And the one thing that has helped me show up consistently in spite of fear is some version of Nike’s annoyingly obvious slogan: Just Do It. Because besides being annoyingly obvious, it’s also universally, inescapably true. “Just Do It” isn’t an elegant solution. It’s not dismissive or snobby, but empowering and humble. It’s motivation. Inspiration. Action. Energy. People don’t realize how deep this slogan is. “If it were that easy, don’t you think everybody would ‘just do it?’” No, no, no. That’s not what it’s about. It’s about something Marcus Aurelius told himself 2,000 years ago: “You must build up your life action by action, and be content if each one achieves its goal as far as possible — and no one can keep you from this.” If all we did was focus on the task right in front of us, we’d accomplish 99% of our goals and then some. Sure, we’d still have to pause and reflect on occasion, and not all goals would turn out to be worth chasing in the first place, but we’d get there. This is everything. The whole strategy. You don’t have time for big picture concerns when you’re doing. And I don’t mean running around all day like a rat in a maze. I mean steadily engaging and re-focusing on the task at hand. “Just Do It” as a strategy A strategy is a long-term approach to getting what you want. It’s a set of behaviors you’re committed to, a line of principles you’re unwilling to compromise. Using “Just Do It” as the strategy, the operating system of your life, means committing to figuring it out on your own. You chase your goals based on what you believe in. If you think art should be free, then make art for free and get sponsors or donors. If you don’t believe in remote work, rent an office and hire locally. “Just Do It” is the best advice because it’s the only advice that works. When I started writing, I gave lots of specific tips in my articles: how to set goals, have a morning routine, be productive. But specifics are full of hindsight bias. I’m only giving you the final 10% that worked, and that worked for me in particular. The messy 90% of the journey that led me there? I left that out completely. And my specific advice is only going to work for a tiny fraction of people who happen to be in the right place at the right time and for whom it will click immediately. Everyone else who still needs to go through the random 90% in their journey will be left out in the cold. Still feeling alone, still stuck with their fears. Except now, they’re disappointed too. “Just Do It” may not be perfect, but at least it clears the air from the start: Yes, you are alone, but you also have everything you could ever need to figure things out. You will make many mistakes, but since no one on this planet can give you the perfect answers to the questions created by your own unique circumstances, choosing for yourself and continuing to move forward is not just the best thing you can do, it’s also the only thing. “Just Do It” as a tactic A tactic is a short- to medium-term course of action that helps you live up to your strategy. “Just Do It” as a tactic is refusing to let everyday hurdles get to you, while relentlessly focusing on the next, smallest action you can control. Your boss didn’t like the presentation? Fine, do it over and show her again. You’ve run out of clients and your freelance business never really got off the ground? Fine, shut it down and start from scratch. Ghosted on Tinder? Fine, delete the app and try another way of meeting people. The faster you can re-center after completing something or getting rattled, the better. Again, this isn’t to say you should never rest, or that you’ll never have moments where the dog creeps back around the corner and stares at you with unblinking eyes. It’s to say that, with this focus on moving forward, you’ll feel more confident in handling it when it does. Make a promise to yourself You’re not unmotivated. You’re not lazy. You’re not bored. You are afraid. We are all afraid. And yet, we are still here. So every day, choose to be here, moving forward.

  • Anonymous  mạo danh  ( Data Scientists )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 10:12Link chia sẻ

    How to write Web apps using simple Python for Data Scientists? Convert your Data Science Projects into cool apps easily without knowing any web frameworks A Machine Learning project is never really complete if we don’t have a good way to showcase it. While in the past, a well-made visualization or a small PPT used to be enough for showcasing a data science project, with the advent of dashboarding tools like RShiny and Dash, a good data scientist needs to have a fair bit of knowledge of web frameworks to get along. And Web frameworks are hard to learn. I still get confused in all that HTML, CSS, and Javascript with all the hit and trials, for something seemingly simple to do. Not to mention the many ways to do the same thing, making it confusing for us data science folks for whom web development is a secondary skill. So, are we doomed to learn web frameworks? Or to call our developer friend for silly doubts in the middle of the night? This is where StreamLit comes in and delivers on its promise to create web apps just using Python. Zen of Python: Simple is better than complex and Streamlit makes it dead simple to create apps. This post is about understanding how to create apps that support data science projects using Streamlit. To understand more about the architecture and the thought process that led to streamlit, have a look at this excellent post by one of the original developers/founder Adrien Treuille. Installation Installation is as simple as running the command: pip install streamlit To see if our installation is successful, we can just run: streamlit hello This should show you a screen that says: You can go to the local URL: localhost:8501 in your browser to see a Streamlit app in action. The developers have provided some cool demos that you can play with. Do take your time and feel the power of the tool before coming back. Streamlit Hello World Streamlit aims to make app development easy using simple Python. So let us write a simple app to see if it delivers on that promise. Here I start with a simple app which we will call the Hello World of streamlit. Just paste the code given below in a file named helloworld.py import streamlit as st x = st.slider('x') st.write(x, 'squared is', x * x) And, on the terminal run: streamlit run helloworld.py And voila, you should be able to see a simple app in action in your browser at localhost:8501 that allows you to move a slider and gives the result. A Simple slider widget app It was pretty easy. In the above app, we used two features from Streamlit: the st.slider widget that we can slide to change the output of the web app. and the versatile st.write command. I am amazed at how it can write anything from charts, dataframes, and simple text. More on this later. Important: Remember that every time we change the widget value, the whole app runs from top to bottom. Streamlit Widgets Widgets provide us a way to control our app. The best place to read about the widgets is the API reference documentation itself but I will describe some most prominent ones that you might end up using. 1. Slider streamlit.slider(label, min_value=None, max_value=None, value=None, step=None, format=None) We already saw st.slider in action above. It can be used with min_value,max_value, and step for getting inputs in a range. 2. Text Input The simplest way to get user input be it some URL input or some text input for sentiment analysis. It just needs a single label for naming the textbox. import streamlit as st url = st.text_input('Enter URL') st.write('The Entered URL is', url) This is how the app looks: A Simple text_input widget app Tip: You can just change the file helloworld.py and refresh the browser. The way I work is to open and changehelloworld.py in sublime text and see the changes in the browser side by side. 3. Checkbox One use case for checkboxes is to hide or show/hide a specific section in an app. Another could be setting up a boolean value in the parameters for a function.st.checkbox() takes a single argument, which is the widget label. In this app, the checkbox is used to toggle a conditional statement. import streamlit as st import pandas as pd import numpy as np df = pd.read_csv("football_data.csv") if st.checkbox('Show dataframe'): st.write(df) A Simple checkbox widget app 4. SelectBox We can use st.selectbox to choose from a series or a list. Normally a use case is to use it as a simple dropdown to select values from a list. import streamlit as st import pandas as pd import numpy as np df = pd.read_csv("football_data.csv") option = st.selectbox( 'Which Club do you like best?', df['Club'].unique()) 'You selected: ', option A Simple dropdown/selectbox widget app 5. MultiSelect We can also use multiple values from a dropdown. Here we use st.multiselect to get multiple values as a list in the variable options import streamlit as st import pandas as pd import numpy as np df = pd.read_csv("football_data.csv") options = st.multiselect( 'What are your favorite clubs?', df['Club'].unique()) st.write('You selected:', options) A Simple multiselect widget app Creating Our Simple App Step by Step So much for understanding the important widgets. Now, we are going to create a simple app using multiple widgets at once. To start simple, we will try to visualize our football data using streamlit. It is pretty much simple to do this with the help of the above widgets. import streamlit as st import pandas as pd import numpy as np df = pd.read_csv("football_data.csv") clubs = st.multiselect('Show Player for clubs?', df['Club'].unique()) nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique()) # Filter dataframe new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))] # write dataframe to screen st.write(new_df) Our simple app looks like: Using multiple widgets in conjunction That was easy. But it seems pretty basic right now. Can we add some charts? Streamlit currently supports many libraries for plotting. Plotly, Bokeh, Matplotlib, Altair, and Vega charts being some of them. Plotly Express also works, although they didn’t specify it in the docs. It also has some inbuilt chart types that are “native” to Streamlit, like st.line_chart and st.area_chart. We will work with plotly_express here. Here is the code for our simple app. We just used four calls to streamlit. Rest is all simple python. import streamlit as st import pandas as pd import numpy as np import plotly_express as px df = pd.read_csv("football_data.csv") clubs = st.multiselect('Show Player for clubs?', df['Club'].unique()) nationalities = st.multiselect('Show Player from Nationalities?', df['Nationality'].unique()) new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))] st.write(new_df) # create figure using plotly express fig = px.scatter(new_df, x ='Overall',y='Age',color='Name') # Plot! st.plotly_chart(fig) Adding charts Improvements In the start we said that each time we change any widget, the whole app runs from start to end. This is not feasible when we create apps that will serve deep learning models or complicated machine learning models. Streamlit covers us in this aspect by introducing Caching. 1. Caching In our simple app. We read the pandas dataframe again and again whenever a value changes. While it works for the small data we have, it will not work for big data or when we have to do a lot of processing on the data. Let us use caching using the st.cache decorator function in streamlit like below. import streamlit as st import pandas as pd import numpy as np import plotly_express as px df = st.cache(pd.read_csv)("football_data.csv") Or for more complex and time taking functions that need to run only once, using: @st.cache def complex_func(a,b): DO SOMETHING COMPLEX # Won't run again and again. complex_func(a,b) When we mark a function with Streamlit’s cache decorator, whenever the function is called streamlit checks the input parameters that you called the function with. If this is the first time Streamlit has seen these params, it runs the function and stores the result in a local cache. When the function is called the next time, if those params have not changed, Streamlit knows it can skip executing the function altogether. It just uses the results from the cache. 2. Sidebar For a cleaner look based on your preference, you might want to move your widgets into a sidebar, something like Rshiny dashboards. This is pretty simple. Just add st.sidebar in your widget’s code. import streamlit as st import pandas as pd import numpy as np import plotly_express as px df = st.cache(pd.read_csv)("football_data.csv") clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique()) nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique()) new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))] st.write(new_df) # Create distplot with custom bin_size fig = px.scatter(new_df, x ='Overall',y='Age',color='Name') # Plot! st.plotly_chart(fig) Move widgets to the sidebar 3. Markdown? I love writing in Markdown. I find it less verbose than HTML and much more suited for data science work. So, can we use Markdown with the streamlit app? Yes, we can. There are a couple of ways to do this. In my view, the best one is to use Magic commands. Magic commands allow you to write markdown as easily as comments. You could also have used the command st.markdown import streamlit as st import pandas as pd import numpy as np import plotly_express as px ''' # Club and Nationality App This very simple webapp allows you to select and visualize players from certain clubs and certain nationalities. ''' df = st.cache(pd.read_csv)("football_data.csv") clubs = st.sidebar.multiselect('Show Player for clubs?', df['Club'].unique()) nationalities = st.sidebar.multiselect('Show Player from Nationalities?', df['Nationality'].unique()) new_df = df[(df['Club'].isin(clubs)) & (df['Nationality'].isin(nationalities))] st.write(new_df) # Create distplot with custom bin_size fig = px.scatter(new_df, x ='Overall',y='Age',color='Name') ''' ### Here is a simple chart between player age and overall ''' st.plotly_chart(fig) Our final App Demo Conclusion Streamlit has democratized the whole process to create apps, and I couldn’t recommend it more. In this post, we created a simple web app. But the possibilities are endless. To give an example here is face GAN from the streamlit site. And it works by just using the same guiding ideas of widgets and caching. I love the default colors and styles that the developers have used, and I found it much more comfortable than using Dash, which I was using until now for my demos. You can also include audio and video in your streamlit apps. On top of that, Streamlit is a free and open-source rather than a proprietary web app that just works out of the box. In the past, I had to reach out to my developer friends for any single change in a demo or presentation; now it is relatively trivial to do that. I aim to use it more in my workflow from now on, and considering the capabilities it provides without all the hard work, I think you should too. I don’t have an idea if it will perform well in a production environment yet, but its a boon for the small proof of concept projects and demos. I aim to use it more in my workflow from now on, and considering the capabilities it provides without all the hard work, I think you should too. You can find the full code for the final app here. If you want to learn about the best strategies for creating Visualizations, I would like to call out an excellent course about Data Visualization and applied plotting from the University of Michigan, which is a part of a pretty good Data Science Specialization with Python in itself. Do check it out. Thanks for the read. I am going to be writing more beginner-friendly posts in the future too. Follow me up at Medium or Subscribe to my blog to be informed about them. As always, I welcome feedback and constructive criticism and can be reached on Twitter @mlwhiz. Also, a small disclaimer — There might be some affiliate links in this post to relevant resources, as sharing knowledge is never a bad idea.

  • Anonymous  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:10Link chia sẻ

    10 Interview Questions Every JavaScript Developer Should Know AKA: The Keys to JavaScript Mastery Eric Elliott Eric Elliott Follow 12 min read At most companies, management must trust the developers to give technical interviews in order to assess candidate skills. If you do well as a candidate, you’ll eventually need to interview. Here’s how. It Starts With People In “How to Build a High Velocity Development Team”, I made a couple points worth repeating: “Nothing predicts business outcomes better than an exceptional team. If you’re going to beat the odds, you need to invest here, first.” As Marcus Lemonis says, focus on the 3 P’s: “People, Process, Product” Your early hires should be very strong, senior-level candidates. People who can hire and mentor other developers, and help the mid-level and junior developers you’ll eventually want to hire down the road. Read “Why Hiring is So Hard in Tech” for a good breakdown of the general do’s and don’ts of candidate evaluation. The best way to evaluate a candidate is a pair programming exercise. Pair program with the candidate. Let the candidate drive. Watch and listen more than you talk. A good project might be to pull tweets from the Twitter API and display them on a timeline. That said, no single exercise will tell you everything you need to know. An interview can be a very useful tool as well, but don’t waste time asking about syntax or language quirks. You need to see the big picture. Ask about architecture and paradigms — the big decisions that can have a major impact on the whole project. Syntax and features are easy to Google. It’s much harder to Google for software engineering wisdom or the common paradigms and idioms JavaScript developers pick up with experience. JavaScript is special, and it plays a critical role in almost every large application. What is it about JavaScript that makes it meaningfully different from other languages? Here are some questions that will help you explore the stuff that really matters: 1. Can you name two programming paradigms important for JavaScript app developers? JavaScript is a multi-paradigm language, supporting imperative/procedural programming along with OOP (Object-Oriented Programming) and functional programming. JavaScript supports OOP with prototypal inheritance. Good to hear: Prototypal inheritance (also: prototypes, OLOO). Functional programming (also: closures, first class functions, lambdas). Red flags: No clue what a paradigm is, no mention of prototypal oo or functional programming. Learn More: The Two Pillars of JavaScript Part 1 — Prototypal OO. The Two Pillars of JavaScript Part 2 — Functional Programming. 2. What is functional programming? Functional programming produces programs by composing mathematical functions and avoids shared state & mutable data. Lisp (specified in 1958) was among the first languages to support functional programming, and was heavily inspired by lambda calculus. Lisp and many Lisp family languages are still in common use today. Functional programming is an essential concept in JavaScript (one of the two pillars of JavaScript). Several common functional utilities were added to JavaScript in ES5. Good to hear: Pure functions / function purity. Avoid side-effects. Simple function composition. Examples of functional languages: Lisp, ML, Haskell, Erlang, Clojure, Elm, F Sharp, OCaml, etc… Mention of features that support FP: first-class functions, higher order functions, functions as arguments/values. Red flags: No mention of pure functions / avoiding side-effects. Unable to provide examples of functional programming languages. Unable to identify the features of JavaScript that enable FP. Learn More: The Two Pillars of JavaScript Part 2. The Dao of Immutability. Composing Software. The Haskell School of Music. 3. What is the difference between classical inheritance and prototypal inheritance? Class Inheritance: instances inherit from classes (like a blueprint — a description of the class), and create sub-class relationships: hierarchical class taxonomies. Instances are typically instantiated via constructor functions with the `new` keyword. Class inheritance may or may not use the `class` keyword from ES6. Prototypal Inheritance: instances inherit directly from other objects. Instances are typically instantiated via factory functions or `Object.create()`. Instances may be composed from many different objects, allowing for easy selective inheritance. In JavaScript, prototypal inheritance is simpler & more flexible than class inheritance. Good to hear: Classes: create tight coupling or hierarchies/taxonomies. Prototypes: mentions of concatenative inheritance, prototype delegation, functional inheritance, object composition. Red Flags: No preference for prototypal inheritance & composition over class inheritance. Learn More: The Two Pillars of JavaScript Part 1 — Prototypal OO. Common Misconceptions About Inheritance in JavaScript. 4. What are the pros and cons of functional programming vs object-oriented programming? OOP Pros: It’s easy to understand the basic concept of objects and easy to interpret the meaning of method calls. OOP tends to use an imperative style rather than a declarative style, which reads like a straight-forward set of instructions for the computer to follow. OOP Cons: OOP Typically depends on shared state. Objects and behaviors are typically tacked together on the same entity, which may be accessed at random by any number of functions with non-deterministic order, which may lead to undesirable behavior such as race conditions. FP Pros: Using the functional paradigm, programmers avoid any shared state or side-effects, which eliminates bugs caused by multiple functions competing for the same resources. With features such as the availability of point-free style (aka tacit programming), functions tend to be radically simplified and easily recomposed for more generally reusable code compared to OOP. FP also tends to favor declarative and denotational styles, which do not spell out step-by-step instructions for operations, but instead concentrate on what to do, letting the underlying functions take care of the how. This leaves tremendous latitude for refactoring and performance optimization, even allowing you to replace entire algorithms with more efficient ones with very little code change. (e.g., memoize, or use lazy evaluation in place of eager evaluation.) Computation that makes use of pure functions is also easy to scale across multiple processors, or across distributed computing clusters without fear of threading resource conflicts, race conditions, etc… FP Cons: Over exploitation of FP features such as point-free style and large compositions can potentially reduce readability because the resulting code is often more abstractly specified, more terse, and less concrete. More people are familiar with OO and imperative programming than functional programming, so even common idioms in functional programming can be confusing to new team members. FP has a much steeper learning curve than OOP because the broad popularity of OOP has allowed the language and learning materials of OOP to become more conversational, whereas the language of FP tends to be much more academic and formal. FP concepts are frequently written about using idioms and notations from lambda calculus, algebras, and category theory, all of which requires a prior knowledge foundation in those domains to be understood. Good to hear: Mentions of trouble with shared state, different things competing for the same resources, etc… Awareness of FP’s capability to radically simplify many applications. Awareness of the differences in learning curves. Articulation of side-effects and how they impact program maintainability. Awareness that a highly functional codebase can have a steep learning curve. Awareness that a highly OOP codebase can be extremely resistant to change and very brittle compared to an equivalent FP codebase. Awareness that immutability gives rise to an extremely accessible and malleable program state history, allowing for the easy addition of features like infinite undo/redo, rewind/replay, time-travel debugging, and so on. Immutability can be achieved in either paradigm, but a proliferation of shared stateful objects complicates the implementation in OOP. Red flags: Unable to list disadvantages of one style or another — Anybody experienced with either style should have bumped up against some of the limitations. Learn More: The Two Pillars of JavaScript Part 1 — Prototypal OO. The Two Pillars of JavaScript Part 2 — Functional Programming. 5. When is classical inheritance an appropriate choice? The answer is never, or almost never. Certainly never more than one level. Multi-level class hierarchies are an anti-pattern. I’ve been issuing this challenge for years, and the only answers I’ve ever heard fall into one of several common misconceptions. More frequently, the challenge is met with silence. “If a feature is sometimes useful and sometimes dangerous and if there is a better option then always use the better option.” ~ Douglas Crockford Good to hear: Rarely, almost never, or never. A single level is sometimes OK, from a framework base-class such as React.Component. “Favor object composition over class inheritance.” Learn More: The Two Pillars of JavaScript Part 1 — Prototypal OO. JS Objects — Inherited a Mess. 6. When is prototypal inheritance an appropriate choice? There is more than one type of prototypal inheritance: Delegation (i.e., the prototype chain). Concatenative (i.e. mixins, `Object.assign()`). Functional (Not to be confused with functional programming. A function used to create a closure for private state/encapsulation). Each type of prototypal inheritance has its own set of use-cases, but all of them are equally useful in their ability to enable composition, which creates has-a or uses-a or can-do relationships as opposed to the is-a relationship created with class inheritance. Good to hear: In situations where modules or functional programming don’t provide an obvious solution. When you need to compose objects from multiple sources. Any time you need inheritance. Red flags: No knowledge of when to use prototypes. No awareness of mixins or `Object.assign()`. Learn More: “Programming JavaScript Applications”: Prototypes section. 7. What does “favor object composition over class inheritance” mean? This is a quote from “Design Patterns: Elements of Reusable Object-Oriented Software”. It means that code reuse should be achieved by assembling smaller units of functionality into new objects instead of inheriting from classes and creating object taxonomies. In other words, use can-do, has-a, or uses-a relationships instead of is-a relationships. Good to hear: Avoid class hierarchies. Avoid brittle base class problem. Avoid tight coupling. Avoid rigid taxonomy (forced is-a relationships that are eventually wrong for new use cases). Avoid the gorilla banana problem (“what you wanted was a banana, what you got was a gorilla holding the banana, and the entire jungle”). Make code more flexible. Red Flags: Fail to mention any of the problems above. Fail to articulate the difference between composition and class inheritance, or the advantages of composition. Learn More: Introducing the Stamp Specification Move Over, `class`: Composable Factory Functions Are Here medium.com 8. What are two-way data binding and one-way data flow, and how are they different? Two way data binding means that UI fields are bound to model data dynamically such that when a UI field changes, the model data changes with it and vice-versa. One way data flow means that the model is the single source of truth. Changes in the UI trigger messages that signal user intent to the model (or “store” in React). Only the model has the access to change the app’s state. The effect is that data always flows in a single direction, which makes it easier to understand. One way data flows are deterministic, whereas two-way binding can cause side-effects which are harder to follow and understand. Good to hear: React is the new canonical example of one-way data flow, so mentions of React are a good signal. Cycle.js is another popular implementation of uni-directional data flow. Angular is a popular framework which uses two-way binding. Red flags: No understanding of what either one means. Unable to articulate the difference. Learn more: 9. What are the pros and cons of monolithic vs microservice architectures? A monolithic architecture means that your app is written as one cohesive unit of code whose components are designed to work together, sharing the same memory space and resources. A microservice architecture means that your app is made up of lots of smaller, independent applications capable of running in their own memory space and scaling independently from each other across potentially many separate machines. Monolithic Pros: The major advantage of the monolithic architecture is that most apps typically have a large number of cross-cutting concerns, such as logging, rate limiting, and security features such audit trails and DOS protection. When everything is running through the same app, it’s easy to hook up components to those cross-cutting concerns. There can also be performance advantages, since shared-memory access is faster than inter-process communication (IPC). Monolithic cons: Monolithic app services tend to get tightly coupled and entangled as the application evolves, making it difficult to isolate services for purposes such as independent scaling or code maintainability. Monolithic architectures are also much harder to understand, because there may be dependencies, side-effects, and magic which are not obvious when you’re looking at a particular service or controller. Microservice pros: Microservice architectures are typically better organized, since each microservice has a very specific job, and is not concerned with the jobs of other components. Decoupled services are also easier to recompose and reconfigure to serve the purposes of different apps (for example, serving both the web clients and public API). They can also have performance advantages depending on how they’re organized because it’s possible to isolate hot services and scale them independent of the rest of the app. Microservice cons: As you’re building a new microservice architecture, you’re likely to discover lots of cross-cutting concerns that you did not anticipate at design time. A monolithic app could establish shared magic helpers or middleware to handle such cross-cutting concerns without much effort. In a microservice architecture, you’ll either need to incur the overhead of separate modules for each cross-cutting concern, or encapsulate cross-cutting concerns in another service layer that all traffic gets routed through. Eventually, even monolthic architectures tend to route traffic through an outer service layer for cross-cutting concerns, but with a monolithic architecture, it’s possible to delay the cost of that work until the project is much more mature. Microservices are frequently deployed on their own virtual machines or containers, causing a proliferation of VM wrangling work. These tasks are frequently automated with container fleet management tools. Good to hear: Positive attitudes toward microservices, despite the higher initial cost vs monolthic apps. Aware that microservices tend to perform and scale better in the long run. Practical about microservices vs monolithic apps. Structure the app so that services are independent from each other at the code level, but easy to bundle together as a monolithic app in the beginning. Microservice overhead costs can be delayed until it becomes more practical to pay the price. Red flags: Unaware of the differences between monolithic and microservice architectures. Unaware or impractical about the additional overhead of microservices. Unaware of the additional performance overhead caused by IPC and network communication for microservices. Too negative about the drawbacks of microservices. Unable to articulate ways in which to decouple monolithic apps such that they’re easy to split into microservices when the time comes. Underestimates the advantage of independently scalable microservices. 10. What is asynchronous programming, and why is it important in JavaScript? Synchronous programming means that, barring conditionals and function calls, code is executed sequentially from top-to-bottom, blocking on long-running tasks such as network requests and disk I/O. Asynchronous programming means that the engine runs in an event loop. When a blocking operation is needed, the request is started, and the code keeps running without blocking for the result. When the response is ready, an interrupt is fired, which causes an event handler to be run, where the control flow continues. In this way, a single program thread can handle many concurrent operations. User interfaces are asynchronous by nature, and spend most of their time waiting for user input to interrupt the event loop and trigger event handlers. Node is asynchronous by default, meaning that the server works in much the same way, waiting in a loop for a network request, and accepting more incoming requests while the first one is being handled. This is important in JavaScript, because it is a very natural fit for user interface code, and very beneficial to performance on the server. Good to hear: An understanding of what blocking means, and the performance implications. An understanding of event handling, and why its important for UI code. Red flags: Unfamiliar with the terms asynchronous or synchronous. Unable to articulate performance implications or the relationship between asynchronous code and UI code. Conclusion Stick to high-level topics. If they can answer these questions, that typically means that they have enough programming experience to pick up language quirks & syntax in a few weeks, even if they don’t have a lot of JavaScript experience. Don’t disqualify candidates based on stuff that’s easy to learn (including classic CS-101 algorithms, or any type of puzzle problem). What you really need to know is, “does this candidate understand how to put an application together?” That’s it for the spoken interview. In real interviews, I place a much stronger emphasis on coding challenges and watching candidates code. Those topics are covered in depth in my “Master the JavaScript Interview” series. Start your free lesson on EricElliottJS.com Eric Elliott is the author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of EricElliottJS.com and DevAnywhere.io, he teaches developers essential software development skills. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall StreetJournal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He enjoys a remote lifestyle with the most beautiful woman in the world.

  • Anonymous  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:10Link chia sẻ

    Composing Software: An Introduction Eric Elliott Eric Elliott Follow May 18, 2017 · 11 min read Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0) Note: This is part of the “Composing Software” series (now a book!) on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come! Buy the Book | Index | Next > Composition: “The act of combining parts or elements to form a whole.” ~ Dictionary.com In my first high school programming class, I was told that software development is “the act of breaking a complex problem down into smaller problems, and composing simple solutions to form a complete solution to the complex problem.” One of my biggest regrets in life is that I failed to understand the significance of that lesson early on. I learned the essence of software design far too late in life. I have interviewed hundreds of developers. What I’ve learned from those sessions is that I’m not alone. Very few working software developers have a good grasp on the essence of software development. They aren’t aware of the most important tools we have at our disposal, or how to put them to good use. 100% have struggled to answer one or both of the most important questions in the field of software development: What is function composition? What is object composition? The problem is that you can’t avoid composition just because you’re not aware of it. You still do it — but you do it badly. You write code with more bugs, and make it harder for other developers to understand. This is a big problem. The effects are very costly. We spend more time maintaining software than we do creating it from scratch, and our bugs impact billions of people all over the world. The entire world runs on software today. Every new car is a mini super-computer on wheels, and problems with software design cause real accidents and cost real human lives. In 2013, a jury found Toyota’s software development team guilty of “reckless disregard” after an accident investigation revealed spaghetti code with 10,000 global variables. Hackers and governments stockpile bugs in order to spy on people, steal credit cards, harness computing resources to launch Distributed Denial of Service (DDoS) attacks, crack passwords, and even manipulate elections. We must do better. You Compose Software Every Day If you’re a software developer, you compose functions and data structures every day, whether you know it or not. You can do it consciously (and better), or you can do it accidentally, with duct-tape and crazy glue. The process of software development is breaking down large problems into smaller problems, building components that solve those smaller problems, then composing those components together to form a complete application. Composing Functions Function composition is the process of applying a function to the output of another function. In algebra, given two functions, fand g, (f ∘ g)(x) = f(g(x)). The circle is the composition operator. It's commonly pronounced "composed with" or "after". You can say that out-loud as "f composed with g equals f of g of x", or "f after g equals f of g of x". We say f after g because g is evaluated first, then its output is passed as an argument to f. Every time you write code like this, you’re composing functions: const g = n => n + 1; const f = n => n * 2; const doStuff = x => { const afterG = g(x); const afterF = f(afterG); return afterF; }; doStuff(20); // 42 Every time you write a promise chain, you’re composing functions: const g = n => n + 1; const f = n => n * 2; const wait = time => new Promise( (resolve, reject) => setTimeout( resolve, time ) ); wait(300) .then(() => 20) .then(g) .then(f) .then(value => console.log(value)) // 42 ; Likewise, every time you chain array method calls, lodash methods, observables (RxJS, etc…) you’re composing functions. If you’re chaining, you’re composing. If you’re passing return values into other functions, you’re composing. If you call two methods in a sequence, you’re composing using this as input data. If you’re chaining, you’re composing. When you compose functions intentionally, you’ll do it better. Composing functions intentionally, we can improve our doStuff() function to a simple one-liner: const g = n => n + 1; const f = n => n * 2; const doStuffBetter = x => f(g(x)); doStuffBetter(20); // 42 A common objection to this form is that it’s harder to debug. For example, how would we write this using function composition? const doStuff = x => { const afterG = g(x); console.log(`after g: ${ afterG }`); const afterF = f(afterG); console.log(`after f: ${ afterF }`); return afterF; }; doStuff(20); // => /* "after g: 21" "after f: 42" */ First, let’s abstract that “after f”, “after g” logging into a little utility called trace(): const trace = label => value => { console.log(`${ label }: ${ value }`); return value; }; Now we can use it like this: const doStuff = x => { const afterG = g(x); trace('after g')(afterG); const afterF = f(afterG); trace('after f')(afterF); return afterF; }; doStuff(20); // => /* "after g: 21" "after f: 42" */ Popular functional programming libraries like Lodash and Ramda include utilities to make function composition easier. You can rewrite the above function like this: import pipe from 'lodash/fp/flow'; const doStuffBetter = pipe( g, trace('after g'), f, trace('after f') ); doStuffBetter(20); // => /* "after g: 21" "after f: 42" */ If you want to try this code without importing something, you can define pipe like this: // pipe(...fns: [...Function]) => x => y const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x); Don’t worry if you’re not following how that works, yet. Later on we’ll explore function composition in a lot more detail. In fact, it’s so essential, you’ll see it defined and demonstrated many times throughout this text. The point is to help you become so familiar with it that its definition and usage becomes automatic. Be one with the composition. pipe() creates a pipeline of functions, passing the output of one function to the input of another. When you use pipe() (and its twin, compose()) You don't need intermediary variables. Writing functions without mention of the arguments is called point-free style. To do it, you'll call a function that returns the new function, rather than declaring the function explicitly. That means you won't need the function keyword or the arrow syntax (=>). Point-free style can be taken too far, but a little bit here and there is great because those intermediary variables add unnecessary complexity to your functions. There are several benefits to reduced complexity: Working Memory The average human brain has only a few shared resources for discrete quanta in working memory, and each variable potentially consumes one of those quanta. As you add more variables, our ability to accurately recall the meaning of each variable is diminished. Working memory models typically involve 4–7 discrete quanta. Above those numbers, error rates dramatically increase. Using the pipe form, we eliminated 3 variables — freeing up almost half of our available working memory for other things. That reduces our cognitive load significantly. Software developers tend to be better at chunking data into working memory than the average person, but not so much more as to weaken the importance of conservation. Signal to Noise Ratio Concise code also improves the signal-to-noise ratio of your code. It’s like listening to a radio — when the radio is not tuned properly to the station, you get a lot of interfering noise, and it’s harder to hear the music. When you tune it to the correct station, the noise goes away, and you get a stronger musical signal. Code is the same way. More concise code expression leads to enhanced comprehension. Some code gives us useful information, and some code just takes up space. If you can reduce the amount of code you use without reducing the meaning that gets transmitted, you’ll make the code easier to parse and understand for other people who need to read it. Surface Area for Bugs Take a look at the before and after functions. It looks like the function went on a diet and lost a ton of weight. That’s important because extra code means extra surface area for bugs to hide in, which means more bugs will hide in it. Less code = less surface area for bugs = fewer bugs. Composing Objects “Favor object composition over class inheritance” the Gang of Four, “Design Patterns: Elements of Reusable Object Oriented Software” “In computer science, a composite data type or compound data type is any data type which can be constructed in a program using the programming language’s primitive data types and other composite types. […] The act of constructing a composite type is known as composition.” ~ Wikipedia These are primitives: const firstName = 'Claude'; const lastName = 'Debussy'; And this is a composite: const fullName = { firstName, lastName }; Likewise, all Arrays, Sets, Maps, WeakMaps, TypedArrays, etc… are composite datatypes. Any time you build any non-primitive data structure, you’re performing some kind of object composition. Note that the Gang of Four defines a pattern called the composite pattern which is a specific type of recursive object composition which allows you to treat individual components and aggregated composites identically. Some developers get confused, thinking that the composite pattern is the only form of object composition. Don’t get confused. There are many different kinds of object composition. The Gang of Four continues, “you’ll see object composition applied again and again in design patterns”, and then they catalog three kinds of object compositional relationships, including delegation (as used in the state, strategy, and visitor patterns), acquaintance (when an object knows about another object by reference, usually passed as a parameter: a uses-a relationship, e.g., a network request handler might be passed a reference to a logger to log the request — the request handler uses a logger), and aggregation (when child objects form part of a parent object: a has-a relationship, e.g., DOM children are component elements in a DOM node — A DOM node has children). Class inheritance can be used to construct composite objects, but it’s a restrictive and brittle way to do it. When the Gang of Four says “favor object composition over class inheritance”, they’re advising you to use flexible approaches to composite object building, rather than the rigid, tightly-coupled approach of class inheritance. We’ll use a more general definition of object composition from “Categorical Methods in Computer Science: With Aspects from Topology” (1989): “Composite objects are formed by putting objects together such that each of the latter is ‘part of’ the former.” Another good reference is “Reliable Software Through Composite Design”, Glenford J Myers, 1975. Both books are long out of print, but you can still find sellers on Amazon or eBay if you’d like to explore the subject of object composition in more technical depth. Class inheritance is just one kind of composite object construction. All classes produce composite objects, but not all composite objects are produced by classes or class inheritance. “Favor object composition over class inheritance” means that you should form composite objects from small component parts, rather than inheriting all properties from an ancestor in a class hierarchy. The latter causes a large variety of well-known problems in object oriented design: The tight coupling problem: Because child classes are dependent on the implementation of the parent class, class inheritance is the tightest coupling available in object oriented design. The fragile base class problem: Due to tight coupling, changes to the base class can potentially break a large number of descendant classes — potentially in code managed by third parties. The author could break code they’re not aware of. The inflexible hierarchy problem: With single ancestor taxonomies, given enough time and evolution, all class taxonomies are eventually wrong for new use-cases. The duplication by necessity problem: Due to inflexible hierarchies, new use cases are often implemented by duplication, rather than extension, leading to similar classes which are unexpectedly divergent. Once duplication sets in, it’s not obvious which class new classes should descend from, or why. The gorilla/banana problem: “…the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” ~ Joe Armstrong, “Coders at Work” The most common form of object composition in JavaScript is known as object concatenation (aka mixin composition). It works like ice-cream. You start with an object (like vanilla ice-cream), and then mix in the features you want. Add some nuts, caramel, chocolate swirl, and you wind up with nutty caramel chocolate swirl ice cream. Building composites with class inheritance: class Foo { constructor () { this.a = 'a' } } class Bar extends Foo { constructor (options) { super(options); this.b = 'b' } } const myBar = new Bar(); // {a: 'a', b: 'b'} Building composites with mixin composition: const a = { a: 'a' }; const b = { b: 'b' }; const c = {...a, ...b}; // {a: 'a', b: 'b'} We’ll explore other styles of object composition in more depth later. For now, your understanding should be: There’s more than one way to do it. Some ways are better than others. You want to select the simplest, most flexible solution for the task at hand. Conclusion This isn’t about functional programming (FP) vs object-oriented programming (OOP), or one language vs another. Components can take the form of functions, data structures, classes, etc… Different programming languages tend to afford different atomic elements for components. Java affords classes, Haskell affords functions, etc… But no matter what language and what paradigm you favor, you can’t get away from composing functions and data structures. In the end, that’s what it all boils down to. We’ll talk a lot about functional programming, because functions are the simplest things to compose in JavaScript, and the functional programming community has invested a lot of time and effort formalizing function composition techniques. What we won’t do is say that functional programming is better than object-oriented programming, or that you must choose one over the other. OOP vs FP is a false dichotomy. Every real Javascript application I’ve seen in recent years mixes FP and OOP extensively. We’ll use object composition to produce datatypes for functional programming, and functional programming to produce objects for OOP. No matter how you write software, you should compose it well. The essence of software development is composition. A software developer who doesn’t understand composition is like a home builder who doesn’t know about bolts or nails. Building software without awareness of composition is like a home builder putting walls together with duct tape and crazy glue. It’s time to simplify, and the best way to simplify is to get to the essence. The trouble is, almost nobody in the industry has a good handle on the essentials. We as an industry have failed you, the software developer. It’s our responsibility as an industry to train developers better. We must improve. We need to take responsibility. Everything runs on software today, from the economy to medical equipment. There is literally no corner of human life on this planet that is not impacted by the quality of our software. We need to know what we’re doing. It’s time to learn how to compose software. Buy the Book | Index | Next > Learn More at EricElliottJS.com Video lessons with interactive code challenges are available for members of EricElliottJS.com. If you’re not a member, sign up today. Eric Elliott is a distributed systems expert and author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of DevAnywhere.io, he teaches developers the skills they need to work remotely and embrace work/life balance. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems,Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He enjoys a remote lifestyle with the most beautiful woman in the world.

  • Anonymous  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:11Link chia sẻ

    Mocking is a Code Smell Eric Elliott Eric Elliott Follow Oct 21, 2017 · 23 min read Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0) Note: This is part of the “Composing Software” series (now a book!) on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come! < Previous | << Start Over One of the biggest complaints I hear about TDD and unit tests is that people struggle with all of the mocking required to isolate units. Some people struggle to understand how their unit tests are even meaningful. In fact, I’ve seen developers get so lost in mocks, fakes, and stubs that they wrote entire files of unit tests where no actual implementation code was exercised at all. Oops. On the other end of the spectrum, it’s common to see developers get so sucked into the dogma of TDD that they think they absolutely must achieve 100% code coverage, by any means necessary, even if that means they have to make their codebase more complex to pull it off. I frequently tell people that mocking is a code smell, but most developers pass through a stage in their TDD skills where they want to achieve 100% unit test coverage, and can’t imagine a world in which they do not use mocks extensively. In order to squeeze mocks into their application, they tend to wrap dependency injection functions around their units or (worse), pack services into dependency injection containers. Angular takes this to an extreme by baking dependency injection right into all Angular component classes, tempting users to view dependency injection as the primary means of decoupling. But dependency injection is not the best way to accomplish decoupling. TDD should lead to better design The process of learning effective TDD is the process of learning how to build more modular applications. TDD tends to have a simplifying effect on code, not a complicating effect. If you find that your code gets harder to read or maintain when you make it more testable, or you have to bloat your code with dependency injection boilerplate, you’re doing TDD wrong. Don’t waste your time wedging dependency injection into your app so you can mock the whole world. Chances are very good that it’s hurting you more than it’s helping. Writing more testable code should simplify your code. It should require fewer lines of code and more readable, flexible, maintainable constructions. Dependency injection has the opposite effect. This text exists to teach you two things: You can write decoupled code without dependency injection, and Maximizing code coverage brings diminishing returns — the closer you get to 100% coverage, the more you have to complicate your application code to get even closer, which can subvert the important goal of reducing bugs in your application. More complex code is often accompanied by more cluttered code. You want to produce uncluttered code for the same reasons you want to keep your house tidy: More clutter leads to more convenient places for bugs to hide, which leads to more bugs, and It’s easier to find what you’re looking for when there’s less clutter to get lost in. What is a code smell? “A code smell is a surface indication that usually corresponds to a deeper problem in the system.” ~ Martin Fowler A code smell does not mean that something is definitely wrong, or that something must be fixed right away. It is a rule of thumb that should alert you to a possible opportunity to improve something. This text and its title in no way imply that all mocking is bad, or that you should never mock anything. Additionally, different types of code need different levels (and different kinds) of mocks. Some code exists primarily to facilitate I/O, in which case, there is little to do other than test I/O, and reducing mocks might mean your unit test coverage would be close to 0. If there is no logic in your code (just pipes and pure compositions), 0% unit test coverage might be acceptable, assuming your integration or functional test coverage is close to 100%. However, if there is logic (conditional expressions, assignments to variables, explicit function calls to units, etc…), you probably do need unit test coverage, and there may be opportunities to simplify your code and reduce mocking requirements. What is a mock? A mock is a test double that stands in for real implementation code during the unit testing process. A mock is capable of producing assertions about how it was manipulated by the test subject during the test run. If your test double produces assertions, it’s a mock in the specific sense of the word. The term “mock” is also used more generally to refer to the use of any kind of test double. For the purpose of this text, we’ll use the words “mock” and “test double” interchangeably to match popular usage. All test doubles (dummies, spies, fakes, etc…) stand in for real code that the test subject is tightly coupled to, therefore, all test doubles are an indication of coupling, and there may be an opportunity to simplify the implementation and improve the quality of the code under test. At the same time, eliminating the need for mocking can radically simplify the tests themselves, because you won’t have to construct the mocks. What is a unit test? Unit tests test individual units (modules, functions, classes) in isolation from the rest of the program. Contrast unit tests with integration tests, which test integrations between two or more units, and functional tests, which test the application from the point of view of the user, including complete user interaction workflows from simulated UI manipulation, to data layer updates, and back to the user output (e.g., the on-screen representation of the app). Functional tests are a subset of integration tests, because they test all of the units of an application, integrated in the context of the running application. In general, units are tested using only the public interface of the unit (aka “public API” or “surface area”). This is referred to as black box testing. Black box testing leads to less brittle tests, because the implementation details of a unit tend to change more over time than the public API of the unit. If you use white box testing, where tests are aware of implementation details, any change to the implementation details could break the test, even if the public API continues to function as expected. In other words, white-box testing leads to wasted rework. What is test coverage? Code coverage refers to the amount of code covered by test cases. Coverage reports can be created by instrumenting the code and recording which lines were exercised during a test run. In general, we try to produce a high level of coverage, but code coverage starts to deliver diminishing returns as it gets closer to 100%. In my experience, increasing coverage beyond ~90% seems to have little continued correlation with lower bug density. Why would that be? Doesn’t 100% tested code mean that we know with 100% certainty that the code does what it was designed to do? It turns out, it’s not that simple. What most people don’t realize is that there are two kinds of coverage: Code coverage: how much of the code is exercised, and Case coverage: how many of the use-cases are covered by the test suites Case coverage refers to use-case scenarios: How the code will behave in the context of real world environment, with real users, real networks, and even hackers intentionally trying to subvert the design of the software for nefarious purposes. Coverage reports identify code-coverage weaknesses, not case-coverage weaknesses. The same code may apply to more than one use-case, and a single use-case may depend on code outside the subject-under-test, or even in a separate application or 3rd party API. Because use-cases may involve the environment, multiple units, users, and networking conditions, it is impossible to cover all required use-cases with a test suite that only contains unit tests. Unit tests by definition test units in isolation, not in integration, meaning that a test suite containing only unit tests will always have close to 0% case coverage for integration and functionaluse-case scenarios. 100% code coverage does not guarantee 100% case coverage. Developers targeting 100% code coverage are chasing the wrong metric. What is tight coupling? The need to mock in order to achieve unit isolation for the purpose of unit tests is caused by coupling between units. Tight coupling makes code more rigid and brittle: more likely to break when changes are required. In general, less coupling is desirable for its own sake because it makes code easier to extend and maintain. The fact that it also makes testing easier by eliminating the need for mocks is just icing on the cake. From this we can deduce that if we’re mocking something, there may be an opportunity to make our code more flexible by reducing the coupling between units. Once that’s done, you won’t need the mocks anymore. Coupling is the degree to which a unit of code (module, function, class, etc…) depends upon other units of code. Tight coupling, or a high degree of coupling, refers to how likely a unit is to break when changes are made to its dependencies. In other words, the tighter the coupling, the harder it is to maintain or extend the application. Loose coupling reduces the complexity of fixing bugs and adapting the application to new use-cases. Coupling takes different forms: Subclass coupling: Subclasses are dependent on the implementation and entire hierarchy of the parent class: the tightest form of coupling available in OO design. Control dependencies: Code that controls its dependencies by telling them what to do, e.g., passing method names, etc… If the control API of the dependency changes, the dependent code will break. Mutable state dependencies: Code that shares mutable state with other code, e.g., can change properties on a shared object. If relative timing of mutations change, it could break dependent code. If timing is nondeterministic, it may be impossible to achieve program correctness without a complete overhaul of all dependent units: e.g., there may be an irreparable tangle of race conditions. Fixing one bug could cause others to appear in other dependent units. State shape dependencies: Code that shares data structures with other code, and only uses a subset of the structure. If the shape of the shared structure changes, it could break the dependent code. Event/message coupling: Code that communicates with other units via message passing, events, etc… What causes tight coupling? Tight coupling has many causes: Mutation vs immutability Side-Effects vs purity/isolated side-effects Responsibility overload vs Do One Thing (DOT) Procedural instructions vs describing structure Class Inheritance vs composition Imperative and object-oriented code is more susceptible to tight coupling than functional code. That doesn’t mean that programming in a functional style makes your code immune to tight coupling, but functional code uses pure functions as the elemental unit of composition, and pure functions are less vulnerable to tight coupling by nature. Pure functions: Given the same input, always return the same output, and Produce no side-effects How do pure functions reduce coupling? Immutability: Pure functions don’t mutate existing values. They return new ones, instead. No side effects: The only observable effect of a pure function is its return value, so there’s no chance for it to interfere with the operation of other functions that may be observing external state such as the screen, the DOM, the console, standard out, the network, or the disk. Do one thing: Pure functions do one thing: Map some input to some corresponding output, avoiding the responsibility overload that tends to plague object and class-based code. Structure, not instructions: Pure functions can be safely memoized, meaning that, if the system had infinite memory, any pure function could be replaced with a lookup table that uses the function’s input as an index to retrieve a corresponding value from the table. In other words, pure functions describe structural relationships between data, not instructions for the computer to follow, so two different sets of conflicting instructions running at the same time can’t step on each other’s toes and cause problems. What does composition have to do with mocking? Everything. The essence of all software development is the process of breaking a large problem down into smaller, independent pieces (decomposition) and composing the solutions together to form an application that solves the large problem (composition). Mocking is required when our decomposition strategy has failed. Mocking is required when the units used to break the large problem down into smaller parts depend on each other. Put another way, mocking is required when our supposed atomic units of composition are not really atomic, and our decomposition strategy has failed to decompose the larger problem into smaller, independent problems. When decomposition succeeds, it’s possible to use a generic composition utility to compose the pieces back together. Examples: Function composition e.g., lodash/fp/compose Component composition e.g., composing higher-order components with function composition State store/model composition e.g., Redux combineReducers Object or factory composition e.g., mixins or functional mixins Process composition e.g., transducers Promise or monadic composition e.g., asyncPipe(), Kleisli composition with composeM(), composeK(), etc... etc… When you use generic composition utilities, each element of the composition can be unit tested in isolation without mocking the others. The compositions themselves will be declarative, so they’ll contain zero unit-testable logic (presumably the composition utility is a third party library with its own unit tests). Under those circumstances, there’s nothing meaningful to unit test. You need integration tests, instead. Let’s contrast imperative vs declarative composition using a familiar example: // Function composition OR // import pipe from 'lodash/fp/flow'; const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x); // Functions to compose const g = n => n + 1; const f = n => n * 2; // Imperative composition const doStuffBadly = x => { const afterG = g(x); const afterF = f(afterG); return afterF; }; // Declarative composition const doStuffBetter = pipe(g, f); console.log( doStuffBadly(20), // 42 doStuffBetter(20) // 42 ); Function composition is the process of applying a function to the return value of another function. In other words, you create a pipeline of functions, then pass a value to the pipeline, and the value will go through each function like a stage in an assembly line, transforming the value in some way before it’s passed to the next function in the pipeline. Eventually, the last function in the pipeline returns the final value. initialValue -> [g] -> [f] -> result It is the primary means of organizing application code in every mainstream language, regardless of paradigm. Even Java uses functions (methods) as the primary message passing mechanism between different class instances. You can compose functions manually (imperatively), or automatically (declaratively). In languages without first-class functions, you don’t have much choice. You’re stuck with imperative. In JavaScript (and almost all the other major popular languages), you can do it better with declarative composition. Imperative style means that we’re commanding the computer to do something step-by-step. It’s a how-to guide. In the example above, the imperative style says: Take an argument and assign it to x Create a binding called afterG and assign the result of g(x) to it Create a binding called afterF and assign the result of f(afterG) to it Return the value of afterF. The imperative style version requires logic that should be tested. I know those are just simple assignments, but I’ve frequently seen (and written) bugs where I pass or return the wrong variable. Declarative style means we’re telling the computer the relationships between things. It’s a description of structure using equational reasoning. The declarative example says: doStuffBetter is the piped composition of g and f. That’s it. Assuming f and g have their own unit tests, and pipe() has its own unit tests (use flow() from Lodash or pipe() from Ramda, and it will), there's no new logic here to unit test. In order for this style to work correctly, the units we compose need to be decoupled. How do we remove coupling? To remove coupling, we first need a better understanding of where coupling dependencies come from. Here are the main sources, roughly in order of how tight the coupling is: Tight coupling: Class inheritance (coupling is multiplied by each layer of inheritance and each descendant class) Global variables Other mutable global state (browser DOM, shared storage, network, etc…) Module imports with side-effects Implicit dependencies from compositions, e.g., const enhancedWidgetFactory = compose(eventEmitter, widgetFactory, enhancements); where widgetFactory depends on eventEmitter Dependency injection containers Dependency injection parameters Control parameters (an outside unit is controlling the subject unit by telling it what to do) Mutable parameters Loose coupling: Module imports without side-effects (in black box testing, not all imports need isolating) Message passing/pubsub Immutable parameters (can still cause shared dependencies on state shape) Ironically, most of the sources of coupling are mechanisms originally designed to reduce coupling. That makes sense, because in order to recompose our smaller problem solutions into a complete application, they need to integrate and communicate somehow. There are good ways, and bad ways. The sources that cause tight coupling should be avoided whenever it’s practical to do so. The loose coupling options are generally desirable in a healthy application. You might be confused that I classified dependency injection containers and dependency injection parameters in the “tight coupling” group, when so many books and blog post categorize them as “loose coupling”. Coupling is not binary. It’s a gradient scale. That means that any grouping is going to be somewhat subjective and arbitrary. I draw the line with a simple, objective litmus test: Can the unit be tested without mocking dependencies? If it can’t, it’s tightly coupled to the mocked dependencies. The more dependencies your unit has, the more likely it is that there may be problematic coupling. Now that we understand how coupling happens, what can we do about it? Use pure functions as the atomic unit of composition, as opposed to classes, imperative procedures, or mutating functions. Isolate side-effects from the rest of your program logic. That means don’t mix logic with I/O (including network I/O, rendering UI, logging, etc…). Remove dependent logic from imperative compositions so that they can become declarative compositions which don’t need their own unit tests. If there’s no logic, there’s nothing meaningful to unit test. That means that the code you use to set up network requests and request handlers won’t need unit tests. Use integration tests for those, instead. That bears repeating: Don’t unit test I/O. I/O is for integrations. Use integration tests, instead. It’s perfectly OK to mock and fake for integration tests. Use pure functions Using pure functions takes a little practice, and without that practice, it’s not always clear how to write a pure function to do what you want to do. Pure functions can’t directly mutate global variables, the arguments passed into them, the network, the disk, or the screen. All they can do is return a value. If you’re passed an array or an object, and you want to return a changed version of that object, you can’t just make the changes to the object and return it. You have to create a new copy of the object with the required changes. You can do that with the array accessor methods (not the mutator methods), Object.assign(), using a new empty object as the target, or the array or object spread syntax. For example: // Not pure const signInUser = user => user.isSignedIn = true; const foo = { name: 'Foo', isSignedIn: false }; // Foo was mutated console.log( signInUser(foo), // true foo // { name: "Foo", isSignedIn: true } ); vs… // Pure const signInUser = user => ({...user, isSignedIn: true }); const foo = { name: 'Foo', isSignedIn: false }; // Foo was not mutated console.log( signInUser(foo), // { name: "Foo", isSignedIn: true } foo // { name: "Foo", isSignedIn: false } ); Alternatively, you can try a library for immutable data types, such as Mori or Immutable.js. I’m hopeful that we’ll someday get a nice set of immutable datatypes similar to Clojure’s in JavaScript, but I’m not holding my breath. You may think that returning new objects could cause a performance hit because we’re creating a new object instead of reusing the existing ones, but a fortunate side-effect of that is that we can detect changes to objects by using an identity comparison (=== check), so we don't have to traverse through the entire object to discover if anything has changed. You can use that trick to make React components render faster if you have a complex state tree that you may not need to traverse in depth with each render pass. Inherit from PureComponent and it implements shouldComponentUpdate() with a shallow prop and state comparison. When it detects identity equality, it knows that nothing has changed in that part of the state tree and it can move on without a deep state traversal. Pure functions can also be memoized, meaning that you don’t have to build the whole object again if you’ve seen the same inputs before. You can trade computation complexity for memory and store pre-calculated values in a lookup table. For computationally expensive processes which don’t require unbounded memory, this may be a great optimization strategy. Another property of pure functions is that, because they have no side-effects, it’s safe to distribute complex computations over large clusters of processors, using a divide-and-conquer strategy. This tactic is often employed to process images, videos, or audio frames using massively parallel GPUs originally designed for graphics, but now commonly used for lots of other purposes, like scientific computing. In other words, mutation isn’t always faster, and it is often orders of magnitude slower because it takes a micro-optimization at the expense of macro-optimizations. Isolate side-effects from the rest of your program logic There are several strategies that can help you isolate side-effects from the rest of your program logic. Here are some of them: Use pub/sub to decouple I/O from views and program logic. Rather than directly triggering side-effects in UI views or program logic, emit an event or action object describing an event or intent. Isolate logic from I/O e.g., compose functions which return promises using asyncPipe(). Use objects that represent future computations rather than directly triggering computation with I/O, e.g., call() from redux-saga doesn't actually call a function. Instead, it returns an object with a reference to a function and its arguments, and the saga middleware calls it for you. That makes call() and all the functions that use it pure functions, which are easy to unit test with no mocking required. Use pub/sub Pub/sub is short for the publish/subscribe pattern. In the publish/subscribe pattern, units don’t directly call each other. Instead, they publish messages that other units (subscribers) can listen to. Publishers don’t know what (if any) units will subscribe, and subscribers don’t know what (if any) publishers will publish. Pub/sub is baked into the Document Object Model (DOM). Any component in your application can listen to events dispatched from DOM elements, such as mouse movements, clicks, scroll events, keystrokes, and so on. Back when everyone built web apps with jQuery, it was common to jQuery custom events to turn the DOM into a pub/sub event bus to decouple view rendering concerns from state logic. Pub/sub is also baked into Redux. In Redux, you create a global model for application state (called the store). Instead of directly manipulating models, views and I/O handlers dispatch action objects to the store. An action object has a special key, called type which various reducers can listen for and respond to. Additionally, Redux supports middleware, which can also listen for and respond to specific action types. This way, your views don't need to know anything about how your application state is handled, and the state logic doesn't need to know anything about the views. It also makes it trivial to patch into the dispatcher via middleware and trigger cross-cutting concerns, such as action logging/analytics, syncing state with storage or the server, and patching in realtime communication features with servers and network peers. Isolate logic from I/O Sometimes you can use monad compositions (like promises) to eliminate dependent logic from your compositions. For example, the following function contains logic that you can’t unit test without mocking all of the async functions: async function uploadFiles({user, folder, files}) { const dbUser = await readUser(user); const folderInfo = await getFolderInfo(folder); if (await haveWriteAccess({dbUser, folderInfo})) { return uploadToFolder({dbUser, folderInfo, files }); } else { throw new Error("No write access to that folder"); } } Let’s throw in some helper pseudo-code to make it runnable: const log = (...args) => console.log(...args); // Ignore these. In your real code you'd import // the real things. const readUser = () => Promise.resolve(true); const getFolderInfo = () => Promise.resolve(true); const haveWriteAccess = () => Promise.resolve(true); const uploadToFolder = () => Promise.resolve('Success!'); // gibberish starting variables const user = '123'; const folder = '456'; const files = ['a', 'b', 'c']; async function uploadFiles({user, folder, files}) { const dbUser = await readUser({ user }); const folderInfo = await getFolderInfo({ folder }); if (await haveWriteAccess({dbUser, folderInfo})) { return uploadToFolder({dbUser, folderInfo, files }); } else { throw new Error("No write access to that folder"); } } uploadFiles({user, folder, files}) .then(log) ; And now refactor it to use promise composition via asyncPipe(): const asyncPipe = (...fns) => x => ( fns.reduce(async (y, f) => f(await y), x) ); const uploadFiles = asyncPipe( readUser, getFolderInfo, haveWriteAccess, uploadToFolder ); uploadFiles({user, folder, files}) .then(log) ; The conditional logic is easily removed because promises have conditional branching built-in. The idea is that logic and I/O don’t mix well, so we want to remove the logic from the I/O dependent code. In order to make this kind of composition work, we need to ensure 2 things: haveWriteAccess() will reject if the user doesn't have write access. That moves the conditional logic into the promise context so we don't have to unit test it or worry about it at all (promises have their own tests baked into the JS engine code). Each of these functions takes and resolves with the same data type. We could create a pipelineData type for this composition which is just an object containing the following keys: { user, folder, files, dbUser?, folderInfo? }. This creates a structure sharing dependency between the components, but you can use more generic versions of these functions in other places and specialize them for this pipeline with thin wrapping functions. With those conditions met, it’s trivial to test each of these functions in isolation from each other without mocking the other functions. Since we’ve extracted all of the logic out of the pipeline, there’s nothing meaningful left to unit test in this file. All that’s left to test are the integrations. Remember: Logic and I/O are separate concerns. Logic is thinking. Effects are actions. Think before you act! Use objects that represent future computations The strategy used by redux-saga is to use objects that represent future computations. The idea is similar to returning a monad, except that it doesn’t always have to be a monad that gets returned. Monads are capable of composing functions with the chain operation, but you can manually chain functions using imperative-style code, instead. Here’s a rough sketch of how redux-saga does it: // sugar for console.log we'll use later const log = msg => console.log(msg); const call = (fn, ...args) => ({ fn, args }); const put = (msg) => ({ msg }); // imported from I/O API const sendMessage = msg => Promise.resolve('some response'); // imported from state handler/Reducer const handleResponse = response => ({ type: 'RECEIVED_RESPONSE', payload: response }); const handleError = err => ({ type: 'IO_ERROR', payload: err }); function* sendMessageSaga (msg) { try { const response = yield call(sendMessage, msg); yield put(handleResponse(response)); } catch (err) { yield put(handleError(err)); } } You can see all the calls being made in your unit tests without mocking the network API or invoking any side-effects. Bonus: This makes your application extremely easy to debug without worrying about nondeterministic network state, etc… Want to simulate what happens in your app when a network error occurs? Simply call iter.throw(NetworkError) Elsewhere, some library middleware is driving the function, and actually triggering the side-effects in the production application: const iter = sendMessageSaga('Hello, world!'); // Returns an object representing the status and value: const step1 = iter.next(); log(step1); /* => { done: false, value: { fn: sendMessage args: ["Hello, world!"] } } */ Destructure the call() object from the yielded value to inspect or invoke the future computation: const { value: {fn, args }} = step1; Effects run in the real middleware. You can skip this part when you’re testing and debugging. const step2 = fn(args); step2.then(log); // "some response" If you want to simulate a network response without mocking APIs or the http calls, you can pass a simulated response into .next(): iter.next(simulatedNetworkResponse); From there you can keep calling .next() until done is true, and your function is finished running. Using generators and representations of computations in your unit tests, you can simulate everything up to but excluding invoking the real side-effects. You can pass values into .next() calls to fake responses, or throw errors at the iterator to fake errors and promise rejections. Using this style, there’s no need to mock anything in unit tests, even for complex integrational workflows with lots of side-effects. “Code smells” are warning signs, not laws. Mocks are not evil. All this stuff about using better architecture is great, but in the real world, we have to use other people’s APIs, and integrate with legacy code, and there are lots of APIs that aren’t pure. Isolated test doubles may be useful in those cases. For example, express passes shared mutable state and models side-effects via continuation passing. Let’s look at a common example. People try to tell me that the express server definition file needs dependency injection because how else will you unit test all the stuff that goes into the express app? E.g.: const express = require('express'); const app = express(); app.get('/', function (req, res) { res.send('Hello World!') }); app.listen(3000, function () { console.log('Example app listening on port 3000!') }); In order to “unit test” this file, we’d have to work up a dependency injection solution and then pass mocks for everything into it (possibly including express() itself). If this was a very complex file where different request handlers were using different features of express, and counting on that logic to be there, you'd probably have to come up with a pretty sophisticated fake to make that work. I've seen developers create elaborate fakes and mocks of things like express, the session middleware, log handlers, realtime network protocols, you name it. I've faced hard mocking questions myself, but the correct answer is simple. This file doesn’t need unit tests. The server definition file for an express app is by definition the app’s main integration point. Testing an express app file is by definition testing an integration between your program logic, express, and all the handlers for that express app. You absolutely should not skip integration tests even if you can achieve 100% unit test coverage. Instead of trying to unit test this file, isolate your program logic into separate units, and unit test those files. Write real integration tests for the server file, meaning you’ll actually hit the network, or at least create the actual http messages, complete with headers using a tool like supertest. Let’s refactor the Hello World express example to make it more testable: Pull the hello handler into its own file and write unit tests for it. No need to mock the rest of the app components. This obviously isn't a pure function, so we'll need to spy or mock the response object to make sure we call .send(). const hello = (req, res) => res.send('Hello World!'); You could test it something like this. Swap out the if statement for your favorite test framework expectation: { const expected = 'Hello World!'; const msg = `should call .send() with ${ expected }`; const res = { send: (actual) => { if (actual !== expected) { throw new Error(`NOT OK ${ msg }`); } console.log(`OK: ${ msg }`); } } hello({}, res); } Pull the listen handler into its own file and write unit tests for it, too. We have the same problem here. Express handlers are not pure, so we need to spy on the logger to make sure it gets called. Testing is similar to the previous example: const handleListen = (log, port) => () => log(`Example app listening on port ${ port }!`); All that’s left in the server file now is integration logic: const express = require('express'); const hello = require('./hello.js'); const handleListen = require('./handleListen'); const log = require('./log'); const port = 3000; const app = express(); app.get('/', hello); app.listen(port, handleListen(port, log)); You still need integration tests for this file, but further unit tests won’t meaningfully enhance your case coverage. We use some very minimal dependency injection to pass a logger into handleListen(), but there is certainly no need for any dependency injection framework for express apps. Mocking is great for integration tests Because integration tests test collaborative integrations between units, it’s perfectly OK to fake servers, network protocols, network messages, and so on in order to reproduce all the various conditions you’ll encounter during communication with other units, potentially distributed across clusters of CPUs or separate machines on a network. Sometimes you’ll want to test how your unit will communicate with a 3rd party API, and sometimes those API’s are prohibitively expensive to test for real. You can record real workflow transactions against the real services and replay them from a fake server to test how well your unit integrates with a third party service actually running in a separate network process. Often this is the best way to test things like “did we see the correct message headers?” There are lots of useful integration testing tools that throttle network bandwidth, introduce network lag, produce network errors, and otherwise test lots of other conditions that are impossible to test using unit tests which mock away the communication layer. It’s impossible to achieve 100% case coverage without integration tests. Don’t skip them even if you manage to achieve 100% unit test coverage. Sometimes 100% is not 100%. Next Steps Learn why I think every development team should be using TDD on the Cross Cutting Concerns podcast. JS Cheerleader is documenting our adventures on Instagram. Learn More at EricElliottJS.com Video lessons on unit testing are available for members of EricElliottJS.com. If you’re not a member, sign up today. Eric Elliott is the author of “Programming JavaScript Applications” (O’Reilly), and “Learn JavaScript with Eric Elliott”. He has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He works remote from anywhere with the most beautiful woman in the world.

  • Anonymous  mạo danh  ( Rethinking Unit Test Assertions )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:12Link chia sẻ

    Well written automated tests always act as a good bug report when they fail, but few developers spend time to think about what information a good bug report needs. There are 5 questions every unit test must answer. I’ve described them in detail before, so we’ll just skim them this time: What is the unit under test (module, function, class, whatever)? What should it do? (Prose description) What was the actual output? What was the expected output? How do you reproduce the failure? A lot of test frameworks allows you to ignore one or more of these questions, and that leads to bug reports that aren’t very useful. Let’s take a look at this example using a fictional testing framework that supplies the commonly supplied pass() and fail() assertions: describe('addEntity()', async ({ pass, fail }) => { const myEntity = { id: 'baz', foo: 'bar' }; try { const response = await addEntity(myEntity); const storedEntity = await getEntity(response.id); pass('should add the new entity'); } catch(err) { fail('failed to add and read entity', { myEntity, error }); } }); We’re on the right track here, but we’re missing some information. Let’s try to answer the 5 questions using the data available in this test: What is the unit under test? addEntity() What should it do? 'should add the new entity' What was the actual output? Oops. We don’t know. We didn’t supply this data to the testing framework. What was the expected output? Again, we don’t know. We’re not testing a return value here. Instead, we’re assuming that if it doesn’t throw, everything worked as expected — but what if it didn’t? We should be testing the resulting value if the function returns a value or resolving promise. How do you reproduce the failure? We can see this a little bit in the test setup, but we could be more explicit about this. For example, it would be nice to have a prose description of the input that you’re feeding in to give us a better understanding of the intent of the test case. I’d score this 2.5 out of 5. Fail. This test is not doing its job. It is clearly not answering the 5 questions every unit test must answer. The problem with most test frameworks is that they’re so busy making it easy for you to take shortcuts with their “convenient” assertions that they forget that the biggest value of a test is realized when the test fails. At the failure stage, the convenience of writing the test matters a lot less than how easy it is to figure out what went wrong when we read the test. In “5 Questions Every Unit Test Must Answer”, I wrote: “equal() is my favorite assertion. If the only available assertion in every test suite was equal(), almost every test suite in the world would be better for it.” In the years since I wrote that, I doubled down on that belief. While testing frameworks got busy adding even more “convenient” assertions, I wrote a thin wrapper around Tape that only exposed a deep equality assertion. In other words, I took the already minimal Tape library, and removed features to make the testing experience better. I called the wrapper library “RITEway” after the RITE Way testing principles. Tests should be: Readable Isolated (for unit tests) or Integrated (for functional and integration tests, test should be isolated and components/modules should be integrated) Thorough, and Explicit RITEway forces you to write Readable, Isolated, and Explicit tests, because that’s the only way you can use the API. It also makes it easier to be thorough by making test assertions so simple that you’ll want to write more of them. Here’s the signature for RITEway’s assert(): assert({ given: Any, should: String, actual: Any, expected: Any }) => Void The assertion must be in a describe() block which takes a label for the unit under test as the first parameter. A complete test looks like this: describe('sum()', async assert => { assert({ given: 'no arguments', should: 'return 0', actual: sum(), expected: 0 }); }); Which produces the following: TAP version 13 # sum() ok 1 Given no arguments: should return 0 Let’s take another look at our 2.5 star test from above and see if we can improve our score: describe('addEntity()', async assert => { const myEntity = { id: 'baz', foo: 'bar' }; const given = 'an entity'; const should = 'read the same entity from the api'; try { const response = await addEntity(myEntity); const storedEntity = await getEntity(response.id); assert({ given, should, actual: storedEntity, expected: myEntity }); } catch(error) { assert({ given, should, actual: error, expected: myEntity }); } }); What is the unit under test? addEntity() What should it do? 'given an entity: should read the same entity from the api' What was the actual output? { id: 'baz', foo: 'bar' } What was the expected output? { id: 'baz', foo: 'bar' } How do you reproduce the failure? Now the instructions to reproduce the test are more explicitly spelled out in the message: The given and should descriptions are supplied. Nice! Now we’re passing the testing test. Is a Deep Equality Assertion Really Enough? I have been using RITEway on an almost-daily basis across several large production projects for almost a year and a half. It has evolved a little. We’ve made the interface even simpler than it originally was, but I’ve never wanted another assertion in all that time, and our test suites are the simplest, most readable test suites I have ever seen in my entire career. I think it’s time to share this innovation with the rest of the world. If you want to get started with RITEway: npm install --save-dev riteway It’s going to change the way you think about testing software. In short: Simple tests are better tests. P.S. I’ve been using the term “unit tests” throughout this article, but that’s just because it’s easier to type than “automated software tests” or “unit tests and functional tests and integration tests”, but everything I’ve said about unit tests in this article applies to every automated software test I can think of. I like these tests much better than Cucumber/Gherkin for functional tests, too. Next Steps TDD Day is an online recorded webinar deep dive on test driven development, different kinds of tests and the roles they play, how to write more testable software, and how TDD made me a better developer, and how it can do the same for you. It’s a great master class to help you or your team reach the next level of TDD practice, featuring 5 hours of video content and interactive quizzes to test your memory. More video lessons on test driven development are available for members of EricElliottJS.com. If you’re not a member, sign up today. Eric Elliott is the author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of EricElliottJS.com and DevAnywhere.io, he teaches developers essential software development skills. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He enjoys a remote lifestyle with the most beautiful woman in the world. JavaScript Scene JavaScript, software leadership, software development, and related technologies. Follow 6K JavaScript

  • Anonymous  mạo danh  ( What’s Better than a College Degree? Mentorship. )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:13Link chia sẻ

    Dry Wraps — Vern (CC-BY-NC-2.0) [Updated August 2017] According to the 2016 Stack Overflow survey of over 56,000 coders, mentorship programs correlate with higher pay than a college degree. I’ve always suggested that students find a good mentor, but with that kind of data-backed endorsement, I thought we should do a little more. I’m an application consultant for companies ranging from hot startups to fortune 500 giants. I’m the author of “Programming JavaScript Applications” (O’Reilly), and EricElliottJS.com and contributor to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. My blog posts attract half a million readers per month. I speak at conferences around the world, and students pay hundreds of dollars to attend my master class workshops in a classroom environment packed with other students. I’m partnered with JS Cheerleader, tech agent extraordinaire. She works with hiring managers from the top tech companies in the business. She offers the best tech career advice you’ll ever get. Together, we have a bird’s eye view of what skills the industry is looking for, and what companies value in potential engineering hires. Over the past couple years, people have been asking if I would consider one-on-one mentorship. We decided to give it a try. We ran a 6-month pilot program with dozens of mentees. We learned a lot of great lessons and developed a highly effective curriculum for JavaScript developers who want to level up into advanced JavaScript skills and take on senior level challenges. We built the first long-term subscription JavaScript mentorship program designed and operated by an experienced team who interview, hire, and lead JavaScript developers for a living. It’s time to introduce the world to DevAnywhere.io — a weekly 1:1 remote mentorship subscription program. How Will We Meet? We’ll meet online via video chat for pair programming, and you’ll get links to a ton of great materials to study on your own time after each session. What Will We Talk About? The strength of mentorship is that we can build on your existing skills and move at your own pace. We’ll interview you to discover your strengths and the gaps you need to focus on. We’ll put you on the fast-track to advanced JavaScript mastery. Here is a small selection of topics: Universal JavaScript (ES6+) Functional Programming Prototypal Inheritance & Object Composition TDD Application Architecture React Redux Node.js Express Next.js In particular, we’ll talk in-depth about software composition techniques using functional programming and object composition as the essential tools of application design. These topics are usually overlooked in other training resources, but learning them can have a profound impact on the quality of the software you produce. They’ll help you build code that is much easier to understand and maintain over time. Who Should Apply? This program is not for absolute beginners. Some JavaScript experience is required. If you know enough to land an entry level job developing JavaScript applications, you should be ready. The ideal candidate is already a JavaScript developer looking to step up from entry level or mid-level jobs into positions requiring advanced JavaScript skills. If you’d like to: Qualify for more competitive remote work Get expert feedback on your code Work with well-trained teams on real projects Bring more value to the team Provide better code reviews for colleagues Take on more challenging roles Learn better development processes Become a great tech leader This program is for you. Are You Ready to Move Up? https://devanywhere.io/ Eric Elliott is the author of “Programming JavaScript Applications” (O’Reilly), and “Learn JavaScript with Eric Elliott”. He has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He works anywhere he wants with the most beautiful woman in the world. JavaScript Scene JavaScript, software leadership, software development, and related technologies. Follow 891

  • Anonymous  mạo danh  ( TDD Changed My Life )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:14Link chia sẻ

    It’s 7:15 am and customer support is swamped. We just got featured on Good Morning America, and a whole bunch of first time customers are bumping into bugs. It’s all-hands-on-deck. We’re going to ship a hot fix NOW before the opportunity to convert more new users is gone. One of the developers has implemented a change he thinks will fix the issue. We paste the staging link in company chat and ask everybody to go test the fix before we push it live to production. It works! Our ops superhero fires up his deploy scripts, and minutes later, the change is live. Suddenly, customer support call volume doubles. Our hot-fix broke something else, and the developers erupt in synchronized git blame while the ops hero reverts the change. Why TDD? It’s been a while since I’ve had to deal with that situation. Not because developers stopped making mistakes, but because for years now, every team I’ve led and worked on has had a policy of using TDD. Bugs still happen, of course, but the release of show-stopping bugs to production has dropped to near zero, even though the rate of software change and upgrade maintenance burden has increased exponentially since then. Whenever somebody asks me why they should bother with TDD, I’m reminded of this story — and dozens more like it. One of the primary reasons I switched to TDD is for improved test coverage, which leads to 40%-80% fewer bugs in production. This is my favorite benefit of TDD. It’s like a giant weight lifting off your shoulders. TDD eradicates fear of change. On my projects, our suites of automated unit and functional tests prevent disastrous breaking changes from happening on a near-daily basis. For example, I’m currently looking at 10 automated library upgrades from the past week that I used to be paranoid about merging because what if it broke something? All of those upgrades integrated automatically, and they’re already live in production. I didn’t look at a single one of them manually, and I’m not worried at all about them. I didn’t have to go hunting to come up with this example. I popped open GitHub, looked at recent merges, and there they were. What was once manual maintenance (or worse, neglect) is now automated background process. You could try that without good test coverage, but I wouldn’t recommend it. What is TDD? TDD stands for Test Driven Development. The process is simple: Red, Green, Refactor Before you write implementation code, write some code that proves that the implementation works or fails. Watch the test fail before moving to the next step (this is how we know that a passing test is not a false positive — how we test our tests). Write the implementation code and watch the test pass. Refactor if needed. You should feel confident refactoring your code now that you have a test to tell you if you’ve broken something. How TDD Can Save You Development Time On the surface, it may seem that writing all those tests is a lot of extra code, and all that extra code takes extra time. At first, this was true for me, as I struggled to understand how to write testable code in the first place, and struggled to understand how to add tests to code that was already written. TDD has a learning curve, and while you’re climbing that learning curve, it can and frequently does add 15% — 35% to implementation times. But somewhere around the 2-years in mark, something magical started to happen: I started coding faster with unit tests than I ever did without them. Several years ago I was building a video clip range feature in a UI. The idea was that you’d set a starting point and an ending point for a video, and when the user links to it, it would link to that precise clip rather than the whole video. But it wasn’t working. The player would reach the end of the clip and keep on playing, and I had no idea why. I kept thinking it had to do with the event listener not getting hooked up properly. My code look something like this: video.addEventListener('timeupdate', () => { if (video.currentTime >= clip.stopTime) { video.pause(); } }); Change. Compile. Reload. Click. Wait. Repeat. Each change took almost a minute to test, and I tried a hilariously large number of things (most of them 2–3 times). Did I misspell timeupdate? Did I get the API right? Is the video.pause() call working? I’d make a change, add a console.log(), jump back into the browser, hit refresh, click to a moment before the end of the clip, and then wait patiently for it to hit the end. Logging inside the if statement did nothing. OK, that’s a clue. Copy and paste timeupdate from the API docs to be absolutely sure it wasn’t a typo. Refresh, click, wait. No luck! Finally, I placed a console.log() outside the if statement. “This can’t help,” I thought. After all, that if statement was so simple, there’s no way I could have screwed up the logic. It logged. I spit my coffee on the keyboard. WTF?! Murphy’s Law of Debugging: The thing you believe so deeply can’t possibly be wrong so you never bother testing it is definitely where you’ll find the bug after you pound your head on your desk and change it only because you’ve tried everything else you can possibly think of. I set a breakpoint to figure out what was going on. I inspected the value of clip.stopTime. undefined??? I looked back at my code. When the user clicks to select the stop time, it places the little stop cursor icon, but never sets clip.stopTime. “OMG I’m a gigantic idiot and nobody should ever let me anywhere near a computer again for as long as I live.” Years later I still remember this because of that feeling. You know exactly what I’m talking about. We’ve all been there. We’re all living memes. Actual photos of me while I’m coding. If I was writing that UI today, I’d start with something like this: describe('clipReducer/setClipStopTime', async assert => { const stopTime = 5; const clipState = { startTime: 2, stopTime: Infinity }; assert({ given: 'clip stop time', should: 'set clip stop time in state', actual: clipReducer(clipState, setClipStopTime(stopTime)), expected: { ...clipState, stopTime } }); }); Granted, superficially, that looks like a whole lot more code than clip.stopTime = video.currentTime. But that’s the point. This code acts like a specification. Documentation, along with proof that the code works as documented. And because it exists, if I change the way I position the stop time cursor on the x, y axis, I don’t have to worry about whether or not I’m breaking the clip stop time code in the process. Note: Want to write unit tests like this? Check out “Rethinking Unit Test Assertions”. The point is not how long it takes to type this code. The point is how long it takes to debug it if something goes wrong. If this code broke, this test would give me a great bug report. I’d know right away that the problem is not the event handler. I’d know it’s in setClipStopTime() or the clipReducer() which implements the state mutation. I’d know what it’s supposed to do, the actual output, and the expected output — and more importantly — so would a coworker, 6-months into the future who’s trying to add features to the code I built. One of the first things I do in every project is set up a watch script that automatically runs my unit tests on every file change. I often code with two monitors side-by-side and keep my dev console with the watch script running on one monitor while I code on the other. When I make a change, I usually know within 3 seconds whether or not that change worked. For me, TDD is far more than a safety net. It’s also constant, fast, realtime feedback. Instant gratification when I get it right. Instant, descriptive bug report when I get it wrong. TDD Taught Me How to Write Better Code I’m going to admit something embarrassing: I had no idea how to build apps before I learned TDD with unit testing. How I ever got hired would be beyond me, but after interviewing hundreds and hundreds of developers, I can tell you with great confidence: there are a lot of developers in the same boat. TDD taught me almost everything I know about effective decoupling and composition of software components (meaning modules, functions, objects, UI components, etc.) The reason for that is because unit tests force you to test components in isolation from each other, and from I/O. Given some input, the unit under test should produce some known output. If it doesn’t, the test fails. If it does, it passes. The key is that it should do so independent of the rest of the application. If you’re testing state logic, you should be able to test it without rendering anything to the screen or saving anything to a database. If you’re testing UI rendering, you should be able to test it without loading the page in a browser or hitting the network. Among other things, TDD taught me that life gets a lot simpler when you keep UI components as minimal as you can. Isolate business logic and side-effects from UI. In practical terms, that means that if you’re using a component-based UI framework like React or Angular, it may be advantageous to create display components and container components, and keep them separate. For display components, given some props, always render the same state. Those components can be easily unit tested to be sure that props are correctly wired up, and that any conditional logic in the UI layout works correctly (for example, maybe a list component shouldn’t render at all if the list is empty, and it should instead render an invitation to add some things to the list). I knew about separation of concerns long before I learned TDD, but I didn’t know how to separate concerns. Unit testing taught me about using mocks to test things, and then it taught me that mocking is a code smell, and that blew my mind and completely changed how I approach software composition. All software development is composition: the process of breaking large problems down into lots of small, easy-to-solve problems, and then composing solutions to those problems to form the application. Mocking for the sake of unit tests is an indication that your atomic units of composition are not really atomic, and learning how to eradicate mocks without sacrificing test coverage taught me how to spot a myriad of sneaky sources of tight coupling. That has made me a much better developer, and taught me how to write much simpler code that is easier to extend, maintain, and scale, both in complexity, and across large distributed systems like cloud infrastructure. How TDD Saves Whole Teams Time I mentioned before that testing first leads to improved test coverage. The reason for that is that we don’t start writing the implementation code until we’ve written a test to ensure that it works. First, write the test. Then watch it fail. Then write the implementation code. Fail, pass, refactor, repeat. That process builds a safety net that few bugs will slip through, and that safety net has a magical impact on the whole team. It eliminates fear of the merge button. That reassuring coverage number gives your whole team the confidence to stop gatekeeping every little change to the codebase and let changes thrive. Removing fear of change is like oiling a machine. If you don’t do it, the machine grinds to a halt until you clean it up and crank it, squeaking and grinding back into motion. Without that fear, the development cadence runs a lot smoother. Pull requests stop backing up. Your CI/CD is running your tests — it will halt if your tests fail. It will fail loudly, and point out what went wrong when it does. And that has made all the difference. Want to Learn More About TDD? TDD Day is an all-day live webinar recorded Friday June 14, 2019. You can still register to watch the recording. You’ll learn: Why TDD has taken over Economics of software quality Unit vs functional vs integration tests 5 questions every unit test must answer TDD the RITE way Mocking is a code smell Why testable software leads to better architecture Causes of tight coupling How to do more with pure functions Unit testing React components Register now. Eric Elliott is the author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of EricElliottJS.com and DevAnywhere.io, he teaches developers essential software development skills. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He enjoys a remote lifestyle with the most beautiful woman in the world.

  • Anonymous  mạo danh  ( Master the JavaScript Interview: What is a Closure? )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:14Link chia sẻ

    Master the JavaScript Interview” is a series of posts designed to prepare candidates for common questions they are likely to encounter when applying for a mid to senior-level JavaScript position. These are questions I frequently use in real interviews. I’m launching the series with the $40k question. If you answer this question wrong, there’s a good chance you won’t get hired. If you do get hired, there’s a good chance you’ll be hired as a junior developer, regardless of how long you’ve been working as a software developer. On average, junior developers get paid $40k/year less USD than more experienced software engineers. Closures are important because they control what is and isn’t in scope in a particular function, along with which variables are shared between sibling functions in the same containing scope. Understanding how variables and functions relate to each other is critical to understanding what’s going on in your code, in both functional and object oriented programming styles. The reason that missing this question is so disadvantageous in an interview is that misunderstandings about how closures work are a pretty clear red flag that can reveal a lack of deep experience, not just in JavaScript, but in any language that relies a lot on closures (Haskell, C#, Python, etc…). Coding in JavaScript without an understanding of closures is like trying to speak English without an understanding of grammar rules — you might be able to get your ideas across, but probably a bit awkwardly. You’ll also be vulnerable to misunderstandings when you’re trying to understand what somebody else wrote. Not only should you know what a closure is, you should know why it matters, and be able to easily answer several possible use-cases for closures. Closures are frequently used in JavaScript for object data privacy, in event handlers and callback functions, and in partial applications, currying, and other functional programming patterns. If you can’t answer this question, it could cost you the job, or ~$40k/year. Be prepared for a quick follow-up: “Can you name two common uses for closures?” What is a Closure? A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time. To use a closure, define a function inside another function and expose it. To expose a function, return it or pass it to another function. The inner function will have access to the variables in the outer function scope, even after the outer function has returned. Using Closures (Examples) Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us program to an interface, not an implementation. This is an important concept that helps us build more robust software because implementation details are more likely to change in breaking ways than interface contracts. “Program to an interface, not an implementation.” Design Patterns: Elements of Reusable Object Oriented Software In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods. In JavaScript, any exposed method defined within the closure scope is privileged. For example: Play with this in JSBin. (Don’t see any output? Copy and paste this HTML into the HTML pane.) In the example above, the `.get()` method is defined inside the scope of `getSecret()`, which gives it access to any variables from `getSecret()`, and makes it a privileged method. In this case, the parameter, `secret`. Objects are not the only way to produce data privacy. Closures can also be used to create stateful functions whose return values may be influenced by their internal state, e.g.: const secret = msg => () => msg; Available on JSBin. (Don’t see any output? Copy and paste this HTML into the HTML pane.) In functional programming, closures are frequently used for partial application & currying. This requires some definitions: Application: The process of applying a function to its arguments in order to produce a return value. Partial Application: The process of applying a function to some of its arguments. The partially applied function gets returned for later use. Partial application fixes (partially applies the function to) one or more arguments inside the returned function, and the returned function takes the remaining parameters as arguments in order to complete the function application. Partial application takes advantage of closure scope in order to fix parameters. You can write a generic function that will partially apply arguments to the target function. It will have the following signature: partialApply(targetFunction: Function, ...fixedArgs: Any[]) => functionWithFewerParams(...remainingArgs: Any[]) If you need help reading the signature above, check out Rtype: Reading Function Signatures. It will take a function that takes any number of arguments, followed by arguments we want to partially apply to the function, and returns a function that will take the remaining arguments. An example will help. Say you have a function that adds two numbers: const add = (a, b) => a + b; Now you want a function that adds 10 to any number. We’ll call it `add10()`. The result of `add10(5)` should be `15`. Our `partialApply()` function can make that happen: const add10 = partialApply(add, 10); add10(5); In this example, the argument, `10` becomes a fixed parameter remembered inside the `add10()` closure scope. Let’s look at a possible `partialApply()` implementation: Available on JSBin. (Don’t see any output? Copy and paste this HTML into the HTML pane.) As you can see, it simply returns a function which retains access to the `fixedArgs` arguments that were passed into the `partialApply()` function. Your Turn This post has a companion video post and practice assignments for members of EricElliottJS.com. If you’re already a member, sign in and practice now. If you’re not a member, sign up today. Explore the Series What is a Closure? What is the Difference Between Class and Prototypal Inheritance? What is a Pure Function? What is Function Composition? What is Functional Programming? What is a Promise? Soft Skills Updates: July 2019 — Clarified intro to explain why answering this question wrong could cost you a job or a lot of money in salary. Start your free lesson on EricElliottJS.com Eric Elliott is the author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of EricElliottJS.com and DevAnywhere.io, he teaches developers essential software development skills. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall StreetJournal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more. He enjoys a remote lifestyle with the most beautiful woman in the world. JavaScript Scene JavaScript, software leadership, software development, and related technologies. Follow

  • Anonymous  mạo danh  ( How To Ace the Coding Interview, by an Ex-Facebook Interviewer )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:15Link chia sẻ

    Last year, I spent countless hours interviewing engineering candidates for positions at Facebook. Having now been on both sides of the interview process, I’d like to help you. Maybe you’re a college student looking for your first software engineering internship. Maybe you’re already a software engineer looking to jump to a new company. Or maybe you’re none of the above and are trying to break into the software engineering world from a completely different industry. This post highlights the top lessons I learned during my time as a software engineering interviewer at Facebook. I hope they will provide some enlightenment for a process that is frustrating for so many people. The Format Coding interviews are typically 45-minute long conversations meant to test your knowledge of data structures and algorithms. Intern candidates at most companies will only be required to do coding interviews. Senior candidates, however, will likely be required to do two to three coding interviews, one to two system design interviews, and a behavioral interview. This article solely covers advice for the coding interview. I was recently asked, “What should I do if I don’t know how to approach the problem right off the bat?” My response: “Well, you won’t know what to do if it’s a good interview question. ” If you did, what would be the point? The goal of a coding interview is to get a grasp of your coding abilities. At Facebook, we referred to this as signal. Our goal as the interviewer is always to extract as much signal as possible. This means if we detect that you’ve heard the problem before, it’s our job to switch questions. We want to know how you handle adversity. If you happen to recite a solution that you memorized from “Cracking the Coding interview,” we’ve learned nothing about your problem-solving skills. Coding Interview Best Practices The absolute best candidates lead interviews. They require very little guidance from the interviewer. They’re the ones who drive the conversation, not the interviewer. These candidates will usually go through these steps by themselves with little to no prompting from the interviewer: Ask clarifying questions. Analyze various solutions and tradeoffs. Plan solution with pseudocode. Implement solution. Test. Leading ≠ Rushing Leading doesn’t mean that you rush into writing code. In fact, starting to write code within the first five minutes of an interview can often be a very bad sign. The first step in leading a great interview is to ask great clarifying questions. Ask great clarifying questions Before you can start to tackle the problem, you need to understand the problem. Asking a few clarifying questions can go a long way in setting you up for success. Here are some great clarifying questions to ask: Should this be done be in place? (No additional memory) Can we make any assumptions about the input? Do we care more about performance or saving memory? This will allow you to focus on what’s important and ignore the rest. Knowing what to ignore is equally as important as knowing what to focus on. Don’t make assumptions Too often, candidates make assumptions about the problem (i.e., all integers are positive, arrays are not empty, all input is safe) … big red flag. Never assume that the conditions of the problem are aligned as is convenient for you to solve the problem. Instead, just ask. “Are the integers passed into this problem all positive?” It’s that simple. If yes, then great. You don’t have to check for that. If not, then a simple if-statement is all you need to make your code safe. Often, asking these questions can provide you great hints as to which direction to move in. Talk about tradeoffs We interviewers love to see when candidates discuss various approaches to a problem. It shows that you understand that there are always multiple approaches to a problem but, more importantly, pressures the interviewer into giving you a hint without you explicitly asking for it. Booyah! We can’t just give you the right answer, but if you propose two options, A and B, and ask, “Which approach do you think I should take?” we’ll sure as hell pick the one that’s closer to the answer we want to see. Plan your solution with pseudocode Usually, during these interviews, you’ll be working off a whiteboard. This means you can’t easily insert statements wherever you want. You have to know what you’re going to do before writing code. Take a deep breath and plan out your code. It could be pseudocode, or it could be a simple drawing, but make sure you know what data structures you’ll be using and what variables you’ll need to keep track of. I’m sure that you don’t want your final solution to look something like this: Yikes Implement your solution This is the step that everyone gets hung up on but really shouldn’t. Implementing your solution should be the easy part. You’ve asked great clarifying questions, you’ve considered various different approaches, you’ve planned out your algorithm; now all you have to do is code it up. But while you are doing this, remember to … Communicate! Talk out loud. It’s hard to help steer you in the right direction if I can’t tell what you’re thinking. If you’re going in the wrong direction, I can interject. If you’re in the right direction, I’ll most likely let you keep going. Small note: This is where interviewer style can be a factor. Some interviewers are more proactive than others when it comes to interjecting. Testing For some reason, this is the most overlooked step. I’d say 98% of the candidates that I interviewed could have benefited from better testing. At the start of an interview, candidates are often given their interview problem alongside a sample test case. When candidates finish writing their solution, they will run through the given test case. The only problem? We give you the simplest possible test case. Likely a test case with no edge cases nor with the capability to properly test your code. Just because your algorithm can provide the correct output for this test case does not mean it can provide the correct output for every case. The easiest way to stand out in a coding interview is to … write more tests. Write harder tests. Write comprehensive tests. More often than not, this will help you catch the bugs without needing me to interject. And that looks very good for you. What to Do When You Don’t Know What to Do So what should you do when you’re asked a question that you don’t know right off the bat? Take it one step at a time. Think back and see if this question reminds you of another one you’ve heard before. Many of the coding interview questions I asked were basic algorithm questions that are taught in most data structures and algorithms classes with a twist. If nothing comes to mind, don’t panic. This is perfectly normal. Don’t overwhelm yourself trying to come up with the most efficient solution right off the bat. Start with the simplest solution. From there, think about what’s the bottleneck? What aspect of the algorithm is the most inefficient? What can you do to minimize those inefficiencies? Align the weakness of a solution to the strength of a data structure When trying to improve an algorithm’s efficiency, you can sometimes (not always) use data structures to help you. Each data structure has its strengths and weaknesses (i.e., Hashmaps—lookup speed, BST—ordering, etc.). Some of the best problem solving happens when you can align the strength of a specific data structure to a problem’s bottleneck. For example: Given a sentence, return the number of occurrences for each letter in the alphabet. A brute force solution would have you count the occurrences of each letter at a time, then output the result. Here, the bottleneck is storing/looking up information. We need to store the occurrences of each letter in the sentence and look up the final result at the end. If we then take a look at all the data structures we have available to us, there is one that stands out: Binary Search Tree Array Hashmap AVL Tree Stack Queue The data structure that most efficiently stores and retrieve data is a hash table. So if we use a hash table for this problem, we wouldn’t need to run through the sentence 26 times. We’d just need to run through it once. Look for the twist Often, interview questions have a twist that allows you to solve them more efficiently. Something subtle that creates a unique condition that allows you to do something more efficiently than normally. Look for these. Here’s an example: Given two sorted integer arrays A and B, merge B into A as one sorted array. You may assume that A has enough space to hold additional elements from B. The number of elements initialized in A and B are m and n respectively. This is a question pulled straight from Cracking the Coding Interview. Notice the twist here? We could have been given this problem such that we are required to merge two sorted arrays, but no. We’re given two arrays where one can fit entirely in the other. That’s the twist I’m talking about. And when you see something like this, notice that it is there for a reason. Those empty slots actually provide you an opportunity to solve this problem more efficiently than if they weren’t there. You can read the full solution here. Ask for help Sometimes even after going through all these steps, you’ll have no idea where to go. In that case, you should just ask for help. Standing in silence for ten minutes doesn’t do either of us any good. If you truly don’t know what to do, asking for a hint is the right step. Everyone needs a hint every once in a while. It’s what you do with that hint that really matters. Closing Remarks The technical interview is a standardized test, just like the ACT, SAT, GRE, and so many others. While the details of a question may vary, the main concepts and strategies used to solve them are quite standardized. Many candidates shoot themselves in the foot by slipping up on the simple things. Making assumptions. Not communicating their thoughts. Writing poor tests. These are mistakes that can be fixed and ultimately make the difference between a no-hire and a hire decision. Follow the framework that I’ve outlined in this post and you’ll be in pretty good shape.

  • Anonymous  mạo danh  ( Accessibility: Addresses, Telephones )  với tư cách là:
    Mức lương:   -  Đánh giá: Bánh bèo
    18/10/2019 14:18Link chia sẻ

    Accessibility: Addresses, Telephones, and Other Inaccessible Links and Where to Find Them Links are the main element of the web but many websites don’t use them to their full potential. Providing links to emails or telephones, or even places or addresses will increase the usability of your website, but more importantly, it will increase the accessibility of your page! People won’t need to copy and paste text using their screen reader, they will be able to automatically follow the link to get to the right place without more input. Famous Websites With Inaccessible Links These examples are from some of the most famous websites in the world, used every day by millions or even billions of people. No accessible address or Whatsapp number on Al Jazeera No accessible phone numbers on CNN No accessible address on ABC News No accessible telephones number and addresses on Stack Overflow No accessible email on Craigslist After this brief introduction, we will discuss all the different types of links you should try to use to improve the accessibility of your HTML content or pages. The Basic Links Links to an internal anchor or to an external page. You can read more about the correct usage of links and buttons here. <a href="domain.com/page">Let's go to an external link!</a> <a href="#internalAnchor">Let's go to a page anchor link!</a> Email Link It’s the second most used type of link to provide a simple way to send an email, it’s known by most developers already, but in any case: <a href="myname@domain.com">Send me an email!</a> Telephone Link Here’s the quickest way to make a telephone number accessible to mobile users or to PC users with Skype or similar software to make calls. The prefix tel means telephone-uri or telephone subscriber ID. You just need to remember to add the prefix tel:. <a href="tel:+447700900328">Call me at this number!</a> SMS Link This link has the same format as the telephone links but it’s for sending text SMS. You can even add some text to the body of the SMS automatically! <a href="sms:+447700900328">Send me an SMS like the old times!</a> Whatsapp Link Whatsapp provides a direct link through their subdomain wa.me with your phone number without the “+”, in this case, an Italian number with prefix “39". <a href="https://wa.me/390123456789">Send me a message on Whatsapp!</a> Address or Place Link For addresses or locations, we still don’t have a proper standard but providing a link to Google Map’s web page will be enough for many occasions, and for countries where you can’t use this service, like China, you can provide alternative links like Baidu Maps. The standard way is to use latitude and longitude coordinates, because they can be used on all usual maps providers. Google Maps uses latitude and longitude: <a href="https://www.google.com/maps/place/80.145752,33.390435"> Came visit me on Svalbard! </a> And for Baidu, we can’t use latitude and longitude due to different standards used inside mainland China, with strange offsets still related to the Cold War. I suggest you open Baidu Maps, find a location and copy the URL you will see in the address bar, something like: “https://map.baidu.com/@1580909.4439028562,5303807.420056639,6.99z”. <a href="https://map.baidu.com/@1580909.4439028562,5303807.420056639,6.99z"> Came visit me in China! </a> References and Resources https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_link_mailto https://tools.ietf.org/html/rfc2806 http://thenewcode.com/856/Send-a-SMS-Text-From-A-Link https://www.google.com/maps/place/80.145752,33.390435 https://map.baidu.com/@1580909.4439028562,5303807.420056639,6.99z Accessibility: web links should be links and web buttons should be buttons. Better Programming Advice for programmers. Why Coding Your Own Makes You a Better Developer Photo by Jon Cartagena on Unsplash The other day I interviewed for a senior developer position with a JavaScript developer. My colleague, who was also in the interview, asked the interviewee to write a function that would perform an HTTP call and retry it a number of times if it failed. Since he was writing it on a whiteboard, pseudo-code would have been enough. If he had just demonstrated a good understanding of the matter we would have been happy. But unfortunately, he wasn’t able to come up with a good solution. Thinking he may have just been nervous, we decided to make it a bit easier and asked him to convert a callback-based function to a Promise-based function. No luck. Yes, I could tell he had seen similar code before. He more or less knew how it worked. A solution in pseudo-code that demonstrated he understood the concept would have been fine. But the code he wrote on the whiteboard made no sense at all. He only had a vague understanding of the concept of a JavaScript Promise and couldn’t explain it well. You may get away with that if you’re a junior developer, but if you’re applying for a senior position it’s not enough. How would he debug a complex Promise chain and then explain what he did to others? Developers Take Abstractions For Granted As developers, we work with abstractions. We abstract code that we would otherwise have to repeat. So when we focus on more important parts, we take the abstractions we work with for granted and just assuming that they work. Usually, they do, but when things get complicated it pays to really know how these abstractions work. The candidate for the senior developer position took the promise abstraction for granted. He probably knew how to work with it if he found it in a piece of code somewhere, but he didn’t truly understand the concept and so he wasn’t able to reproduce it in a job interview. He could have just memorized the code. It’s really not that complicated: return new Promise((resolve, reject) => { functionWithCallback((err, result) => { return err ? reject(err) : resolve(result); }); }); I did that. Probably, we all do that. You just memorize a piece of code so you can work with it. You understand more or less how it works. But if he had truly understood the concept he wouldn’t need to memorize it. He would just know it and have no trouble reproducing it. Know Your Source Back in 2012, before front-end framework dominance, jQuery ruled the world and I was reading “Secrets of the JavaScript Ninja” by John Resig, the creator of jQuery. This book teaches you how to create your own jQuery from scratch, giving you a unique insight into the thought processes behind the creation of this library. Although jQuery has faded into the background over the past years, I highly recommend reading this book. What struck me the most about the book, was the constant feeling that I could have thought of this myself. The steps as described were so logical and straightforward that I really got the feeling that I could have built jQuery if I had set myself to it. Of course, in reality, I would never be able to do that — I would consider it to be far too complicated. I would believe my solutions to be too simple and naive to work and I would just give up. I would just take jQuery for granted and trust it to work. After that I would probably not take the time to figure out how it works. I would just use it as a black box. But reading this book changed me. I started reading source code and found out that many implementations of solutions were pretty straightforward, even obvious. Now, coming up with these solutions yourself is of course an entirely different thing. But reading source code and reimplementing existing solutions yourself is exactly what helps you come up with your own. The inspiration you get and patterns you discover will change you as a developer. You will find that this great library you use and think of as magic is really not magical, but just a simple and smart solution. You may take time understanding code, step by step, but it will also make you go through the same small, incremental steps the authors took to create it. This gives you more insight into the process of coding and more confidence to code your own solutions. When I started using JavaScript Promises I thought they were magic. Then I learned they’re just based on callbacks and my vision of programming was changed forever. This pattern that was meant to get rid of callbacks was implemented using… callbacks? This changed me. It made me realize that these are not incredibly complex pieces of code that were far too complicated for me to understand. They are patterns that I could easily understand if I had the curiosity and will to dive into them. That’s how you really learn how to program. That’s how you become a better developer. Reinvent That Wheel So go ahead and reinvent that wheel. Code your own data binding, code your own Promise or even your own state management solution. It doesn’t matter if no one will ever use it. You will have learned. And if you could use it in one of your own projects, that would already be great. You’ll develop it further and learn even more. The point is not to use your solution in production but to learn. Coding your own implementation of an existing solution is a great way to learn from the best. It’s how you become a better developer. Better Programming