เชฌเซ‡เชš เช•เซเชตเซ‡เชฐเซ€ เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช—เชจเซ€ เชธเชฎเชธเซเชฏเชพเช“ เช…เชจเซ‡ เชคเซ‡เชจเชพ เช‰เช•เซ‡เชฒเซ‹ (เชญเชพเช— 1)

เชฌเซ‡เชš เช•เซเชตเซ‡เชฐเซ€ เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช—เชจเซ€ เชธเชฎเชธเซเชฏเชพเช“ เช…เชจเซ‡ เชคเซ‡เชจเชพ เช‰เช•เซ‡เชฒเซ‹ (เชญเชพเช— 1)เชฒเช—เชญเช— เชคเชฎเชพเชฎ เช†เชงเซเชจเชฟเช• เชธเซ‹เชซเซเชŸเชตเซ‡เชฐ เช‰เชคเซเชชเชพเชฆเชจเซ‹เชฎเชพเช‚ เช˜เชฃเซ€ เชธเซ‡เชตเชพเช“เชจเซ‹ เชธเชฎเชพเชตเซ‡เชถ เชฅเชพเชฏ เช›เซ‡. เช˜เชฃเซ€เชตเชพเชฐ, เช‡เชจเซเชŸเชฐเชธเชฐเซเชตเชฟเชธ เชšเซ‡เชจเชฒเซ‹เชจเซ‹ เชฒเชพเช‚เชฌเซ‹ เชชเซเชฐเชคเชฟเชธเชพเชฆ เชธเชฎเชฏ เชชเซเชฐเชฆเชฐเซเชถเชจ เชธเชฎเชธเซเชฏเชพเช“เชจเซ‹ เชธเซเชคเซเชฐเซ‹เชค เชฌเชจเซ€ เชœเชพเชฏ เช›เซ‡. เช† เชชเซเชฐเช•เชพเชฐเชจเซ€ เชธเชฎเชธเซเชฏเชพเชจเซ‹ เชชเซเชฐเชฎเชพเชฃเชญเซ‚เชค เช‰เช•เซ‡เชฒ เช เชเช• เชชเซ‡เช•เซ‡เชœเชฎเชพเช‚ เชฌเชนเซเชตเชฟเชง เช‡เชจเซเชŸเชฐเชธเชฐเซเชตเชฟเชธ เชตเชฟเชจเช‚เชคเซ€เช“เชจเซ‡ เชชเซ‡เช• เช•เชฐเชตเชพเชจเซ‹ เช›เซ‡, เชœเซ‡เชจเซ‡ เชฌเซ‡เชšเชฟเช‚เช— เช•เชนเซ‡เชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡.

เชœเซ‹ เชคเชฎเซ‡ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช—เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‹ เช›เซ‹, เชคเซ‹ เชคเชฎเซ‡ เชชเซเชฐเชฆเชฐเซเชถเชจ เช…เชฅเชตเชพ เช•เซ‹เชก เชธเซเชชเชทเซเชŸเชคเชพเชจเชพ เชธเช‚เชฆเชฐเซเชญเชฎเชพเช‚ เชชเชฐเชฟเชฃเชพเชฎเซ‹เชฅเซ€ เช–เซเชถ เชจ เชนเซ‹เชˆ เชถเช•เซ‹. เช† เชชเชฆเซเชงเชคเชฟ เช•เซ‰เชฒเชฐ เชชเชฐ เชเชŸเชฒเซ€ เชธเชฐเชณ เชจเชฅเซ€ เชœเซ‡เชŸเชฒเซ€ เชคเชฎเซ‡ เชตเชฟเชšเชพเชฐเซ€ เชถเช•เซ‹ เช›เซ‹. เชตเชฟเชตเชฟเชง เชนเซ‡เชคเซเช“ เชฎเชพเชŸเซ‡ เช…เชจเซ‡ เชตเชฟเชตเชฟเชง เชชเชฐเชฟเชธเซเชฅเชฟเชคเชฟเช“เชฎเชพเช‚, เช‰เช•เซ‡เชฒเซ‹ เชฎเซ‹เชŸเชพ เชชเซเชฐเชฎเชพเชฃเชฎเชพเช‚ เชฌเชฆเชฒเชพเชˆ เชถเช•เซ‡ เช›เซ‡. เชšเซ‹เช•เซเช•เชธ เช‰เชฆเชพเชนเชฐเชฃเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡, เชนเซเช‚ เช…เชจเซ‡เช• เช…เชญเชฟเช—เชฎเซ‹เชจเชพ เช—เซเชฃเชฆเซ‹เชท เชฌเชคเชพเชตเซ€เชถ.

เชชเซเชฐเชฆเชฐเซเชถเชจ เชชเซเชฐเซ‹เชœเซ‡เช•เซเชŸ

เชธเซเชชเชทเซเชŸเชคเชพ เชฎเชพเชŸเซ‡, เชšเชพเชฒเซ‹ เชนเซเช‚ เชนเชพเชฒเชฎเชพเช‚ เชœเซ‡ เชเชชเซเชฒเชฟเช•เซ‡เชถเชจ เชชเชฐ เช•เชพเชฎ เช•เชฐเซเช‚ เช›เซเช‚ เชคเซ‡เชฎเชพเช‚เชจเซ€ เชเช• เชธเซ‡เชตเชพเชจเซเช‚ เช‰เชฆเชพเชนเชฐเชฃ เชœเซ‹เชˆเช.

เช‰เชฆเชพเชนเชฐเชฃเซ‹ เชฎเชพเชŸเซ‡ เชชเซเชฒเซ‡เชŸเชซเซ‹เชฐเซเชฎ เชชเชธเช‚เชฆเช—เซ€เชจเซ€ เชธเชฎเชœเซ‚เชคเซ€เชจเชฌเชณเชพ เชชเซเชฐเชฆเชฐเซเชถเชจเชจเซ€ เชธเชฎเชธเซเชฏเชพ เชเช•เชฆเชฎ เชธเชพเชฎเชพเชจเซเชฏ เช›เซ‡ เช…เชจเซ‡ เชคเซ‡ เช•เซ‹เชˆ เชšเซ‹เช•เซเช•เชธ เชญเชพเชทเชพเช“ เช…เชฅเชตเชพ เชชเซเชฒเซ‡เชŸเชซเซ‹เชฐเซเชฎเชจเซ‡ เช…เชธเชฐ เช•เชฐเชคเซ€ เชจเชฅเซ€. เชธเชฎเชธเซเชฏเชพเช“ เช…เชจเซ‡ เช‰เช•เซ‡เชฒเซ‹ เชฆเชฐเซเชถเชพเชตเชตเชพ เชฎเชพเชŸเซ‡ เช† เชฒเซ‡เช– เชธเซเชชเซเชฐเชฟเช‚เช— + เช•เซ‹เชŸเชฒเชฟเชจ เช•เซ‹เชก เช‰เชฆเชพเชนเชฐเชฃเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชถเซ‡. เช•เซ‹เชŸเชฒเชฟเชจ Java เช…เชจเซ‡ C# เชตเชฟเช•เชพเชธเช•เชฐเซเชคเชพเช“ เชฎเชพเชŸเซ‡ เชธเชฎเชพเชจ เชฐเซ€เชคเซ‡ เชธเชฎเชœเซ€ เชถเช•เชพเชฏ เชคเซ‡เชตเซเช‚ (เช…เชฅเชตเชพ เช…เช—เชฎเซเชฏ) เช›เซ‡, เชตเชงเซเชฎเชพเช‚, เช•เซ‹เชก เชœเชพเชตเชพ เช•เชฐเชคเชพเช‚ เชตเชงเซ เช•เซ‹เชฎเซเชชเซ‡เช•เซเชŸ เช…เชจเซ‡ เชธเชฎเชœเซ€ เชถเช•เชพเชฏ เชคเซ‡เชตเซเช‚ เช›เซ‡. เชถเซเชฆเซเชง Java เชตเชฟเช•เชพเชธเช•เชฐเซเชคเชพเช“ เชฎเชพเชŸเซ‡ เชธเชฎเชœเชตเชพเชฎเชพเช‚ เชธเชฐเชณเชคเชพ เชฌเชจเชพเชตเชตเชพ เชฎเชพเชŸเซ‡, เชนเซเช‚ เช•เซ‹เชŸเชฒเชฟเชจเชจเชพ เช•เชพเชณเชพ เชœเชพเชฆเซเชจเซ‡ เชŸเชพเชณเซ€เชถ เช…เชจเซ‡ เชฎเชพเชคเซเชฐ เชธเชซเซ‡เชฆ เชœเชพเชฆเซเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถ (เชฒเซ‹เชฎเซเชฌเซ‹เช•เชจเซ€ เชญเชพเชตเชจเชพเชฎเชพเช‚). เชคเซเชฏเชพเช‚ เชฅเซ‹เชกเซ€ เชเช•เซเชธเซเชŸเซ‡เช‚เชถเชจ เชชเชฆเซเชงเชคเชฟเช“ เชนเชถเซ‡, เชชเชฐเช‚เชคเซ เชคเซ‡ เชตเชพเชธเซเชคเชตเชฎเชพเช‚ เชœเชพเชตเชพ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชฐเซ‹เชจเซ‡ เชธเซเชฅเชฟเชฐ เชชเชฆเซเชงเชคเชฟเช“ เชคเชฐเซ€เช•เซ‡ เชชเชฐเชฟเชšเชฟเชค เช›เซ‡, เชคเซ‡เชฅเซ€ เช† เชเช• เชจเชพเชจเซ€ เช–เชพเช‚เชก เชนเชถเซ‡ เชœเซ‡ เชตเชพเชจเช—เซ€เชจเซ‹ เชธเซเชตเชพเชฆ เชฌเช—เชพเชกเซ‡ เชจเชนเซ€เช‚.
เชฆเชธเซเชคเชพเชตเซ‡เชœ เชฎเช‚เชœเซ‚เชฐเซ€ เชธเซ‡เชตเชพ เช›เซ‡. เช•เซ‹เชˆ เชตเซเชฏเช•เซเชคเชฟ เชฆเชธเซเชคเชพเชตเซ‡เชœ เชฌเชจเชพเชตเซ‡ เช›เซ‡ เช…เชจเซ‡ เชคเซ‡เชจเซ‡ เชšเชฐเซเชšเชพ เชฎเชพเชŸเซ‡ เชธเชฌเชฎเชฟเชŸ เช•เชฐเซ‡ เช›เซ‡, เชœเซ‡ เชฆเชฐเชฎเชฟเชฏเชพเชจ เชธเช‚เชชเชพเชฆเชจเซ‹ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡, เช…เชจเซ‡ เช†เช–เชฐเซ‡ เชฆเชธเซเชคเชพเชตเซ‡เชœ เชชเชฐ เชธเช‚เชฎเชค เชฅเชพเชฏ เช›เซ‡. เชฎเช‚เชœเซ‚เชฐเซ€ เชธเซ‡เชตเชพ เชชเซ‹เชคเซ‡ เชฆเชธเซเชคเชพเชตเซ‡เชœเซ‹ เชตเชฟเชถเซ‡ เช•เช‚เชˆเชชเชฃ เชœเชพเชฃเชคเซ€ เชจเชฅเซ€: เชคเซ‡ เชซเช•เซเชค เชจเชพเชจเชพ เชตเชงเชพเชฐเชพเชจเชพ เช•เชพเชฐเซเชฏเซ‹ เชธเชพเชฅเซ‡ เชฎเช‚เชœเซ‚เชฐเซ€ เช†เชชเชจเชพเชฐเชพเช“เชจเซ€ เชšเซ‡เชŸ เช›เซ‡ เชœเซ‡เชจเซ‡ เช…เชฎเซ‡ เช…เชนเซ€เช‚ เชงเซเชฏเชพเชจเชฎเชพเช‚ เชฒเชˆเชถเซเช‚ เชจเชนเซ€เช‚.

เชคเซ‡เชฅเซ€, เชคเซ‡เชฎเชพเช‚เชจเชพ เชฆเชฐเซ‡เช•เชฎเชพเช‚ เชธเชนเชญเชพเช—เซ€เช“เชจเชพ เชชเซ‚เชฐเซเชตเชตเซเชฏเชพเช–เซเชฏเชพเชฏเชฟเชค เชธเชฎเซ‚เชน เชธเชพเชฅเซ‡ เชšเซ‡เชŸ เชฐเซ‚เชฎ (เชฆเชธเซเชคเชพเชตเซ‡เชœเซ‹เชจเซ‡ เช…เชจเซเชฐเซ‚เชช) เช›เซ‡. เชจเชฟเชฏเชฎเชฟเชค เชšเซ‡เชŸเซเชธเชจเซ€ เชœเซ‡เชฎ, เชธเช‚เชฆเซ‡เชถเชพเชฎเชพเช‚ เชŸเซ‡เช•เซเชธเซเชŸ เช…เชจเซ‡ เชซเชพเช‡เชฒเซ‹ เชนเซ‹เชฏ เช›เซ‡ เช…เชจเซ‡ เชคเซ‡ เชœเชตเชพเชฌเซ‹ เช…เชฅเชตเชพ เชซเซ‹เชฐเชตเชฐเซเชก เชนเซ‹เชˆ เชถเช•เซ‡ เช›เซ‡:

data class ChatMessage(
  // nullable ั‚ะฐะบ ะบะฐะบ ะฟะพัะฒะปัะตั‚ัั ั‚ะพะปัŒะบะพ ะฟะพัะปะต persist
  val id: Long? = null,
  /** ะกัั‹ะปะบะฐ ะฝะฐ ะฐะฒั‚ะพั€ะฐ */
  val author: UserReference,
  /** ะกะพะพะฑั‰ะตะฝะธะต */
  val message: String,
  /** ะกัั‹ะปะบะธ ะฝะฐ ะฐั‚ั‚ะฐั‡ะธ */
  // ะธะท-ะทะฐ ะพัะพะฑะตะฝะฝะพัั‚ะตะน ัะฒัะทะบะธ JPA+ะกะฃะ‘ะ” ะฟั€ะพั‰ะต ะฟะพะดะดะตั€ะถะธะฒะฐั‚ัŒ ะธ null, ะธ ะฟัƒัั‚ั‹ะต ัะฟะธัะบะธ
  val files: List<FileReference>? = null,
  /** ะ•ัะปะธ ัะฒะปัะตั‚ัั ะพั‚ะฒะตั‚ะพะผ, ั‚ะพ ะทะดะตััŒ ะฑัƒะดะตั‚ ะพั€ะธะณะธะฝะฐะป */
  val replyTo: ChatMessage? = null,
  /** ะ•ัะปะธ ัะฒะปัะตั‚ัั ะฟะตั€ะตัั‹ะปะบะพะน, ั‚ะพ ะทะดะตััŒ ะฑัƒะดะตั‚ ะพั€ะธะณะธะฝะฐะป */
  val forwardFrom: ChatMessage? = null
)

เชซเชพเช‡เชฒ เช…เชจเซ‡ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชฒเชฟเช‚เช•เซเชธ เช เช…เชจเซเชฏ เชกเซ‹เชฎเซ‡เชจเซเชธเชจเซ€ เชฒเชฟเช‚เช•เซเชธ เช›เซ‡. เช…เชนเซ€เช‚ เช†เชชเชฃเซ‡ เช† เชฐเซ€เชคเซ‡ เชœเซ€เชตเซ€เช เช›เซ€เช:

typealias FileReference Long
typealias UserReference Long

เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชกเซ‡เชŸเชพ เช•เซ€เช•เซเชฒเซ‹เช•เชฎเชพเช‚ เชธเช‚เช—เซเชฐเชนเชฟเชค เชฅเชพเชฏ เช›เซ‡ เช…เชจเซ‡ REST เชฆเซเชตเชพเชฐเชพ เชชเซเชจเชƒเชชเซเชฐเชพเชชเซเชค เชฅเชพเชฏ เช›เซ‡. เชซเชพเช‡เชฒเซ‹ เชฎเชพเชŸเซ‡ เชชเชฃ เช† เชœ เช›เซ‡: เชซเชพเช‡เชฒเซ‹ เช…เชจเซ‡ เชคเซ‡เชฎเชจเชพ เชตเชฟเชถเซ‡เชจเซ€ เชฎเชพเชนเชฟเชคเซ€ เชเช• เช…เชฒเช— เชซเชพเช‡เชฒ เชธเซเชŸเซ‹เชฐเซ‡เชœ เชธเซ‡เชตเชพเชฎเชพเช‚ เชฐเชนเซ‡ เช›เซ‡.

เช† เชธเซ‡เชตเชพเช“ เชฎเชพเชŸเซ‡เชจเชพ เชคเชฎเชพเชฎ เช•เซ‹เชฒเซเชธ เช›เซ‡ เชญเชพเชฐเซ‡ เชตเชฟเชจเช‚เชคเซ€เช“. เช†เชจเซ‹ เช…เชฐเซเชฅ เช เช›เซ‡ เช•เซ‡ เช† เชตเชฟเชจเช‚เชคเซ€เช“เชจเชพ เชชเชฐเชฟเชตเชนเชจเชจเซ‹ เช“เชตเชฐเชนเซ‡เชก เชคเซƒเชคเซ€เชฏ-เชชเช•เซเชท เชธเซ‡เชตเชพ เชฆเซเชตเชพเชฐเชพ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชตเชพเชฎเชพเช‚ เชœเซ‡ เชธเชฎเชฏ เชฒเซ‡ เช›เซ‡ เชคเซ‡เชจเชพ เช•เชฐเชคเชพเช‚ เช˜เชฃเซ‹ เชตเชงเชพเชฐเซ‡ เช›เซ‡. เช…เชฎเชพเชฐเซ€ เชŸเซ‡เชธเซเชŸ เชฌเซ‡เชจเซเชš เชชเชฐ, เช†เชตเซ€ เชธเซ‡เชตเชพเช“ เชฎเชพเชŸเซ‡เชจเซ‹ เชธเชพเชฎเชพเชจเซเชฏ เช•เซ‰เชฒ เชธเชฎเชฏ 100 ms เช›เซ‡, เชคเซ‡เชฅเซ€ เช…เชฎเซ‡ เชญเชตเชฟเชทเซเชฏเชฎเชพเช‚ เช† เชจเช‚เชฌเชฐเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถเซเช‚.

เชคเชฎเชพเชฎ เชœเชฐเซ‚เชฐเซ€ เชฎเชพเชนเชฟเชคเซ€ เชธเชพเชฅเซ‡ เช›เซ‡เชฒเซเชฒเชพ N เชธเช‚เชฆเซ‡เชถเชพเช“ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เช…เชฎเชพเชฐเซ‡ เชเช• เชธเชฐเชณ REST เชจเชฟเชฏเช‚เชคเซเชฐเช• เชฌเชจเชพเชตเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เชเชŸเชฒเซ‡ เช•เซ‡, เช…เชฎเซ‡ เชฎเชพเชจเซ€เช เช›เซ€เช เช•เซ‡ เชซเซเชฐเชจเซเชŸเชเชจเซเชกเชฎเชพเช‚ เชฎเซ‡เชธเซ‡เชœ เชฎเซ‹เชกเชฒ เชฒเช—เชญเช— เชธเชฎเชพเชจ เช›เซ‡ เช…เชจเซ‡ เชคเชฎเชพเชฎ เชกเซ‡เชŸเชพ เชฎเซ‹เช•เชฒเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เชซเซเชฐเชจเซเชŸ-เชเชจเซเชก เชฎเซ‰เชกเชฒ เชตเชšเซเชšเซ‡เชจเซ‹ เชคเชซเชพเชตเชค เช เช›เซ‡ เช•เซ‡ เชซเชพเช‡เชฒ เช…เชจเซ‡ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพเชจเซ‡ เชฒเชฟเช‚เช• เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชคเซ‡เชฎเชจเซ‡ เชธเชนเซ‡เชœ เชกเชฟเช•เซเชฐเชฟเชชเซเชŸเซ‡เชก เชธเซเชตเชฐเซ‚เชชเชฎเชพเช‚ เชฐเชœเซ‚ เช•เชฐเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡:

/** ะ’ ั‚ะฐะบะพะผ ะฒะธะดะต ะพั‚ะดะฐัŽั‚ัั ััั‹ะปะบะธ ะฝะฐ ััƒั‰ะฝะพัั‚ะธ ะดะปั ั„ั€ะพะฝั‚ะฐ */
data class ReferenceUI(
  /** ะ˜ะดะตะฝั‚ะธั„ะธะบะฐั‚ะพั€ ะดะปั url */
  val ref: String,
  /** ะ’ะธะดะธะผะพะต ะฟะพะปัŒะทะพะฒะฐั‚ะตะปัŽ ะฝะฐะทะฒะฐะฝะธะต ััั‹ะปะบะธ */
  val name: String
)
data class ChatMessageUI(
  val id: Long,
  /** ะกัั‹ะปะบะฐ ะฝะฐ ะฐะฒั‚ะพั€ะฐ */
  val author: ReferenceUI,
  /** ะกะพะพะฑั‰ะตะฝะธะต */
  val message: String,
  /** ะกัั‹ะปะบะธ ะฝะฐ ะฐั‚ั‚ะฐั‡ะธ */
  val files: List<ReferenceUI>,
  /** ะ•ัะปะธ ัะฒะปัั‚ัั ะพั‚ะฒะตั‚ะพะผ, ั‚ะพ ะทะดะตััŒ ะฑัƒะดะตั‚ ะพั€ะธะณะธะฝะฐะป */
  val replyTo: ChatMessageUI? = null,
  /** ะ•ัะปะธ ัะฒะปัั‚ัั ะฟะตั€ะตัั‹ะปะบะพะน, ั‚ะพ ะทะดะตััŒ ะฑัƒะดะตั‚ ะพั€ะธะณะธะฝะฐะป */
  val forwardFrom: ChatMessageUI? = null
)

เช†เชชเชฃเซ‡ เชจเซ€เชšเซ‡เชจเชพเชจเซ‡ เช…เชฎเชฒเชฎเชพเช‚ เชฎเซ‚เช•เชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡:

interface ChatRestApi {
  fun getLast(nInt): List<ChatMessageUI>
}

UI เชชเซ‹เชธเซเชŸเชซเชฟเช•เซเชธ เชเชŸเชฒเซ‡ เชซเซเชฐเชจเซเชŸ เชเชจเซเชก เชฎเชพเชŸเซ‡ DTO เชฎเซ‹เชกเชฒเซเชธ, เชเชŸเชฒเซ‡ เช•เซ‡, เช†เชชเชฃเซ‡ REST เชฆเซเชตเชพเชฐเชพ เชถเซเช‚ เชธเซ‡เชตเชพ เช†เชชเชตเซ€ เชœเซ‹เชˆเช.

เช…เชนเซ€เช‚ เชจเชตเชพเชˆเชจเซ€ เชตเชพเชค เช เช›เซ‡ เช•เซ‡ เช…เชฎเซ‡ เช•เซ‹เชˆเชชเชฃ เชšเซ‡เชŸ เช†เชˆเชกเซ€ เชชเชพเชธ เช•เชฐเซ€ เชฐเชนเซเชฏเชพ เชจเชฅเซ€ เช…เชจเซ‡ เชšเซ‡เชŸเชฎเซ‡เชธเซ‡เชœ/เชšเซ‡เชŸเชฎเซ‡เชธเซ‡เชœเชฏเซเช†เชˆ เชฎเซ‹เชกเชฒ เชชเชพเชธเซ‡ เชชเชฃ เชจเชฅเซ€. เชฎเซ‡เช‚ เช† เช‡เชฐเชพเชฆเชพเชชเซ‚เชฐเซเชตเช• เช•เชฐเซเชฏเซเช‚ เช›เซ‡ เชœเซ‡เชฅเซ€ เช‰เชฆเชพเชนเชฐเชฃเซ‹เชจเชพ เช•เซ‹เชกเชฎเชพเช‚ เช—เชกเชฌเชก เชจ เชฅเชพเชฏ (เชšเซ‡เชŸเซเชธ เช…เชฒเช— เช›เซ‡, เชคเซ‡เชฅเซ€ เช…เชฎเซ‡ เชงเชพเชฐเซ€ เชถเช•เซ€เช เช•เซ‡ เช…เชฎเชพเชฐเซ€ เชชเชพเชธเซ‡ เชซเช•เซเชค เชเช• เชœ เช›เซ‡).

เชซเชฟเชฒเซ‹เชธเซ‹เชซเชฟเช•เชฒ เชกเชฟเช—เซเชฐเซ‡เชถเชจChatMessageUI เช•เซเชฒเชพเชธ เช…เชจเซ‡ ChatRestApi.getLast เชฎเซ‡เชฅเชก เชฌเช‚เชจเซ‡ เชฒเชฟเชธเซเชŸ เชกเซ‡เชŸเชพ เชชเซเชฐเช•เชพเชฐเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‡ เช›เซ‡ เชœเซเชฏเชพเชฐเซ‡ เชนเช•เซ€เช•เชคเชฎเชพเช‚ เชคเซ‡ เช“เชฐเซเชกเชฐ เช•เชฐเซ‡เชฒ เชธเซ‡เชŸ เชนเซ‹เชฏ. JDK เชฎเชพเช‚ เช† เช–เชฐเชพเชฌ เช›เซ‡, เชคเซ‡เชฅเซ€ เช‡เชจเซเชŸเชฐเชซเซ‡เชธ เชธเซเชคเชฐเซ‡ เชคเชคเซเชตเซ‹เชจเซ‹ เช•เซเชฐเชฎ เชœเชพเชนเซ‡เชฐ เช•เชฐเชตเซ‹ (เช‰เชฎเซ‡เชฐเซ‹ เช…เชจเซ‡ เชฆเซ‚เชฐ เช•เชฐเชคเซ€ เชตเช–เชคเซ‡ เช“เชฐเซเชกเชฐ เชธเชพเชšเชตเชตเซ‹) เช•เชพเชฎ เช•เชฐเชถเซ‡ เชจเชนเซ€เช‚. เชคเซ‡เชฅเซ€ เชœเซเชฏเชพเช‚ เช“เชฐเซเชกเชฐ เช•เชฐเซ‡เชฒ เชธเซ‡เชŸเชจเซ€ เชœเชฐเซ‚เชฐ เชนเซ‹เชฏ เชคเซ‡เชตเชพ เช•เชฟเชธเซเชธเชพเช“เชฎเชพเช‚ เชธเซ‚เชšเชฟเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเซ‹ เชคเซ‡ เชธเชพเชฎเชพเชจเซเชฏ เชชเซเชฐเชฅเชพ เชฌเชจเซ€ เช—เชˆ เช›เซ‡ (เชคเซเชฏเชพเช‚ เชเช• LinkedHashSet เชชเชฃ เช›เซ‡, เชชเชฐเช‚เชคเซ เช† เช‡เชจเซเชŸเชฐเชซเซ‡เชธ เชจเชฅเซ€).
เชฎเชนเชคเซเชตเชชเซ‚เชฐเซเชฃ เชฎเชฐเซเชฏเชพเชฆเชพ: เช…เชฎเซ‡ เชฎเชพเชจเซ€ เชฒเชˆเชถเซเช‚ เช•เซ‡ เชœเชตเชพเชฌเซ‹ เช…เชฅเชตเชพ เชŸเซเชฐเชพเชจเซเชธเชซเชฐเชจเซ€ เช•เซ‹เชˆ เชฒเชพเช‚เชฌเซ€ เชธเชพเช‚เช•เชณเซ‹ เชจเชฅเซ€. เชเชŸเชฒเซ‡ เช•เซ‡, เชคเซ‡เช“ เช…เชธเซเชคเชฟเชคเซเชตเชฎเชพเช‚ เช›เซ‡, เชชเชฐเช‚เชคเซ เชคเซ‡เชฎเชจเซ€ เชฒเช‚เชฌเชพเชˆ เชคเซเชฐเชฃ เชธเช‚เชฆเซ‡เชถเชพเช“ เช•เชฐเชคเชพเช‚ เชตเชงเซ€ เชจเชฅเซ€. เชธเช‚เชฆเซ‡เชถเชพเช“เชจเซ€ เช†เช–เซ€ เชธเชพเช‚เช•เชณ เช…เช—เซเชฐเชญเชพเช— เชชเชฐ เชชเซเชฐเชธเชพเชฐเชฟเชค เชฅเชตเซ€ เชœเซ‹เชˆเช.

เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพเช“เชฎเชพเช‚เชฅเซ€ เชกเซ‡เชŸเชพ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชจเซ€เชšเซ‡เชจเชพ APIs เช›เซ‡:

interface ChatMessageRepository {
  fun findLast(nInt): List<ChatMessage>
}
data class FileHeadRemote(
  val id: FileReference,
  val name: String
)
interface FileRemoteApi {
  fun getHeadById(idFileReference): FileHeadRemote
  fun getHeadsByIds(idSet<FileReference>): Set<FileHeadRemote>
  fun getHeadsByIds(idList<FileReference>): List<FileHeadRemote>
  fun getHeadsByChat(): List<FileHeadRemote>
}
data class UserRemote(
  val id: UserReference,
  val name: String
)
interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote>
  fun getUsersByIds(idList<UserReference>): List<UserRemote>
}

เชคเซ‡ เชœเซ‹เชˆ เชถเช•เชพเชฏ เช›เซ‡ เช•เซ‡ เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพเช“ เชถเชฐเซ‚เช†เชคเชฎเชพเช‚ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เชฎเชพเชŸเซ‡ เชชเซเชฐเชฆเชพเชจ เช•เชฐเซ‡ เช›เซ‡, เช…เชจเซ‡ เชฌเช‚เชจเซ‡ เชธเช‚เชธเซเช•เชฐเชฃเซ‹เชฎเชพเช‚: เชธเซ‡เชŸ เชฆเซเชตเชพเชฐเชพ (เชคเชคเซเชตเซ‹เชจเชพ เช•เซเชฐเชฎเชจเซ‡ เชธเชพเชšเชตเซเชฏเชพ เชตเชฟเชจเชพ, เช…เชจเชจเซเชฏ เช•เซ€ เชธเชพเชฅเซ‡) เช…เชจเซ‡ เชธเซ‚เชšเชฟ เชฆเซเชตเชพเชฐเชพ (เชคเซเชฏเชพเช‚ เชกเซเชชเซเชฒเชฟเช•เซ‡เชŸเซเชธ เชนเซ‹เชˆ เชถเช•เซ‡ เช›เซ‡ - เช“เชฐเซเชกเชฐ เชธเชพเชšเชตเซ‡เชฒ เช›เซ‡).

เชธเชฐเชณ เช…เชฎเชฒเซ€เช•เชฐเชฃเซ‹

เชจเชฟเชทเซเช•เชชเชŸ เช…เชฎเชฒเซ€เช•เชฐเชฃ

เช…เชฎเชพเชฐเชพ REST เชจเชฟเชฏเช‚เชคเซเชฐเช•เชจเซเช‚ เชชเซเชฐเชฅเชฎ เชจเชฟเชทเซเช•เชชเชŸ เช…เชฎเชฒเซ€เช•เชฐเชฃ เชฎเซ‹เชŸเชพเชญเชพเช—เชจเชพ เช•เชฟเชธเซเชธเชพเช“เชฎเชพเช‚ เช†เชจเชพ เชœเซ‡เชตเซเช‚ เชฆเซ‡เช–เชพเชถเซ‡:

class ChatRestController(
  private val messageRepository: ChatMessageRepository,
  private val userRepository: UserRemoteApi,
  private val fileRepository: FileRemoteApi
) : ChatRestApi {
  override fun getLast(nInt) =
    messageRepository.findLast(n)
      .map it.toFrontModel() }
  
  private fun ChatMessage.toFrontModel(): ChatMessageUI =
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = userRepository.getUserById(author).toFrontReference(),
      message = message,
      files = files?.let files ->
        fileRepository.getHeadsByIds(files)
          .map it.toFrontReference() }
      } ?: listOf(),
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
}

เชฌเชงเซเช‚ เช–เซ‚เชฌ เชœ เชธเซเชชเชทเซเชŸ เช›เซ‡, เช…เชจเซ‡ เช† เชเช• เชฎเซ‹เชŸเซ‹ เชตเชคเซเชคเชพ เช›เซ‡.

เช…เชฎเซ‡ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช—เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เช เช›เซ€เช เช…เชจเซ‡ เชฌเซ‡เชšเชฎเชพเช‚ เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพเชฎเชพเช‚เชฅเซ€ เชกเซ‡เชŸเชพ เชชเซเชฐเชพเชชเซเชค เช•เชฐเซ€เช เช›เซ€เช. เชชเชฐเช‚เชคเซ เช†เชชเชฃเซ€ เช‰เชคเซเชชเชพเชฆเช•เชคเชพเชจเซเช‚ เชถเซเช‚ เชฅเชพเชฏ เช›เซ‡?

เชฆเชฐเซ‡เช• เชธเช‚เชฆเซ‡เชถ เชฎเชพเชŸเซ‡, เชฒเซ‡เช–เช• เชซเซ€เชฒเซเชก เชชเชฐ เชกเซ‡เชŸเชพ เชฎเซ‡เชณเชตเชตเชพ เชฎเชพเชŸเซ‡ UserRemoteApi เชชเชฐ เชเช• เช•เซ‰เชฒ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡ เช…เชจเซ‡ เชฌเชงเซ€ เชœเซ‹เชกเชพเชฏเซ‡เชฒ เชซเชพเช‡เชฒเซ‹ เชฎเซ‡เชณเชตเชตเชพ เชฎเชพเชŸเซ‡ FileRemoteApi เชชเชฐ เชเช• เช•เซ‰เชฒ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡. เชเชตเซเช‚ เชฒเชพเช—เซ‡ เช›เซ‡. เชœเชฃเชพเชตเซ€ เชฆเชˆเช เช•เซ‡ ChatMessage เชฎเชพเชŸเซ‡ เชซเซ‹เชฐเชตเชฐเซเชกเชซเซเชฐเซ‹เชฎ เช…เชจเซ‡ เชฐเชฟเชชเซเชฒเชพเชฏ เชŸเซ เชซเซ€เชฒเซเชกเซเชธ เชเชตเซ€ เชฐเซ€เชคเซ‡ เชฎเซ‡เชณเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ เช•เซ‡ เช†เชจเชพ เชฎเชพเชŸเซ‡ เชฌเชฟเชจเชœเชฐเซ‚เชฐเซ€ เช•เซ‹เชฒเชจเซ€ เชœเชฐเซ‚เชฐ เชจเชฅเซ€. เชชเชฐเช‚เชคเซ เชคเซ‡เชฎเชจเซ‡ ChatMessageUI เชฎเชพเช‚ เชซเซ‡เชฐเชตเชตเชพเชฅเซ€ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชฟเชค เชฅเชถเซ‡, เชเชŸเชฒเซ‡ เช•เซ‡, เช•เซ‰เชฒ เช•เชพเช‰เชจเซเชŸเชฐเซเชธ เชจเซ‹เช‚เชงเชชเชพเชคเซเชฐ เชฐเซ€เชคเซ‡ เชตเชงเซ€ เชถเช•เซ‡ เช›เซ‡. เชœเซ‡เชฎ เช†เชชเชฃเซ‡ เช…เช—เชพเช‰ เชจเซ‹เช‚เชงเซเชฏเซเช‚ เช›เซ‡ เชคเซ‡เชฎ, เชšเชพเชฒเซ‹ เชงเชพเชฐเซ€เช เช•เซ‡ เช†เชชเชฃเซ€ เชชเชพเชธเซ‡ เชตเชงเซ เชฎเชพเชณเซ‹ เชจเชฅเซ€ เช…เชจเซ‡ เชธเชพเช‚เช•เชณ เชคเซเชฐเชฃ เชธเช‚เชฆเซ‡เชถเชพเช“ เชธเซเชงเซ€ เชฎเชฐเซเชฏเชพเชฆเชฟเชค เช›เซ‡.

เชชเชฐเชฟเชฃเชพเชฎเซ‡, เช…เชฎเชจเซ‡ เชธเช‚เชฆเซ‡เชถ เชฆเซ€เช  เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพเช“ เชฎเชพเชŸเซ‡ เชฌเซ‡ เชฅเซ€ เช› เช•เซ‰เชฒเซเชธ เช…เชจเซ‡ เชธเช‚เชฆเซ‡เชถเชพเชจเชพ เชธเชฎเช—เซเชฐ เชชเซ‡เช•เซ‡เชœ เชฎเชพเชŸเซ‡ เชเช• JPA เช•เซ‰เชฒ เชฎเชณเชถเซ‡. เช•เซ‰เชฒเซเชธเชจเซ€ เช•เซเชฒ เชธเช‚เช–เซเชฏเชพ 2*N+1 เชฅเซ€ 6*N+1 เชธเซเชงเซ€ เชฌเชฆเชฒเชพเชถเซ‡. เชตเชพเชธเซเชคเชตเชฟเช• เชเช•เชฎเซ‹เชฎเชพเช‚ เช† เช•เซ‡เชŸเชฒเซเช‚ เช›เซ‡? เชšเชพเชฒเซ‹ เช•เชนเซ€เช เช•เซ‡ เชเช• เชชเซƒเชทเซเช เชจเซ‡ เชฐเซ‡เชจเซเชกเชฐ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ 20 เชธเช‚เชฆเซ‡เชถเชพเช“ เชฒเซ‡ เช›เซ‡. เชคเซ‡เชฎเชจเซ‡ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เชคเซ‡ 4 เชฅเซ€ 10 เชธเซ‡เช•เช‚เชก เชธเซเชงเซ€ เชฒเซ‡เชถเซ‡. เชญเชฏเช‚เช•เชฐ! เชนเซเช‚ เชคเซ‡เชจเซ‡ 500 ms เชจเซ€ เช…เช‚เชฆเชฐ เชฐเชพเช–เชตเชพ เชฎเชพเช‚เช—เซ เช›เซเช‚. เช…เชจเซ‡ เชคเซ‡เช“ เชซเซเชฐเชจเซเชŸเชเชจเซเชกเชฎเชพเช‚ เชธเซ€เชฎเชฒเซ‡เชธ เชธเซเช•เซเชฐเซ‹เชฒเชฟเช‚เช— เชฌเชจเชพเชตเชตเชพเชจเซเช‚ เชธเชชเชจเซเช‚ เชœเซ‹เชคเชพ เชนเซ‹เชตเชพเชฅเซ€, เช† เชเชจเซเชกเชชเซ‹เช‡เชจเซเชŸ เชฎเชพเชŸเซ‡เชจเซ€ เช•เชพเชฎเช—เซ€เชฐเซ€เชจเซ€ เชœเชฐเซ‚เชฐเชฟเชฏเชพเชคเซ‹ เชฌเชฎเชฃเซ€ เช•เชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡.

เช—เซเชฃ:

  1. เช•เซ‹เชก เชธเช‚เช•เซเชทเชฟเชชเซเชค เช…เชจเซ‡ เชธเซเชต-เชฆเชธเซเชคเชพเชตเซ‡เชœเซ€เช•เซƒเชค เช›เซ‡ (เชธเชชเซ‹เชฐเซเชŸ เชŸเซ€เชฎเชจเซเช‚ เชธเซเชตเชชเซเชจ).
  2. เช•เซ‹เชก เชธเชฐเชณ เช›เซ‡, เชคเซ‡เชฅเซ€ เชคเชฎเชพเชฐเซ€ เชœเชพเชคเชจเซ‡ เชชเช—เชฎเชพเช‚ เชฎเชพเชฐเชตเชพเชจเซ€ เชฒเช—เชญเช— เช•เซ‹เชˆ เชคเช•เซ‹ เชจเชฅเซ€.
  3. เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เช เชเชฒเชฟเชฏเชจ เชœเซ‡เชตเซเช‚ เชฒเชพเช—เชคเซเช‚ เชจเชฅเซ€ เช…เชจเซ‡ เชคเซ‡ เชคเชฐเซเช•เชฎเชพเช‚ เช“เชฐเซเช—เซ‡เชจเชฟเช•เชฒเซ€ เชเช•เซ€เช•เซƒเชค เช›เซ‡.
  4. เชคเชฐเซเช•เชฎเชพเช‚ เชซเซ‡เชฐเชซเชพเชฐ เชธเชฐเชณเชคเชพเชฅเซ€ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡ เช…เชจเซ‡ เชคเซ‡ เชธเซเชฅเชพเชจเชฟเช• เชนเชถเซ‡.

เชฎเชพเชˆเชจเชธ:

เช–เซ‚เชฌ เชœ เชจเชพเชจเชพ เชชเซ‡เช•เซ‡เชŸเซ‹เชจเซ‡ เช•เชพเชฐเชฃเซ‡ เชญเชฏเชพเชจเช• เช•เชพเชฎเช—เซ€เชฐเซ€.

เช† เช…เชญเชฟเช—เชฎ เชธเชพเชฎเชพเชจเซเชฏ เชธเซ‡เชตเชพเช“ เช…เชฅเชตเชพ เชชเซเชฐเซ‹เชŸเซ‹เชŸเชพเช‡เชชเซเชธเชฎเชพเช‚ เช˜เชฃเซ€ เชตเชพเชฐ เชœเซ‹เช‡ เชถเช•เชพเชฏ เช›เซ‡. เชœเซ‹ เชซเซ‡เชฐเชซเชพเชฐเซ‹ เช•เชฐเชตเชพเชจเซ€ เช—เชคเชฟ เชฎเชนเชคเซเชตเชชเซ‚เชฐเซเชฃ เช›เซ‡, เชคเซ‹ เชคเซ‡ เชธเชฟเชธเซเชŸเชฎเชจเซ‡ เชœเชŸเชฟเชฒ เชฌเชจเชพเชตเชตเชพ เชฎเชพเชŸเซ‡ เชญเชพเช—เซเชฏเซ‡ เชœ เชฏเซ‹เช—เซเชฏ เช›เซ‡. เชคเซ‡ เชœ เชธเชฎเชฏเซ‡, เช…เชฎเชพเชฐเซ€ เช–เซ‚เชฌ เชœ เชธเชฐเชณ เชธเซ‡เชตเชพ เชฎเชพเชŸเซ‡ เชชเซเชฐเชฆเชฐเซเชถเชจ เชญเชฏเช‚เช•เชฐ เช›เซ‡, เชคเซ‡เชฅเซ€ เช† เช…เชญเชฟเช—เชฎเชจเซ€ เชฒเชพเช—เซ เชฅเชตเชพเชจเซ‹ เช…เชตเช•เชพเชถ เช–เซ‚เชฌ เชœ เชธเชพเช‚เช•เชกเซ‹ เช›เซ‡.

เชจเชฟเชทเซเช•เชชเชŸ เชธเชฎเชพเช‚เชคเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ

เชคเชฎเซ‡ เชฌเชงเชพ เชธเช‚เชฆเซ‡เชถเชพเช“ เชชเชฐ เชธเชฎเชพเช‚เชคเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชตเชพเชจเซเช‚ เชถเชฐเซ‚ เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹ - เช† เชคเชฎเชจเซ‡ เชธเช‚เชฆเซ‡เชถเชพเช“เชจเซ€ เชธเช‚เช–เซเชฏเชพเชจเชพ เช†เชงเชพเชฐเซ‡ เชธเชฎเชฏเชจเชพ เชฐเซ‡เช–เซ€เชฏ เชตเชงเชพเชฐเชพเชฅเซ€ เช›เซเชŸเช•เชพเชฐเซ‹ เชฎเซ‡เชณเชตเชตเชพเชจเซ€ เชฎเช‚เชœเซ‚เชฐเซ€ เช†เชชเชถเซ‡. เช† เช–เชพเชธ เช•เชฐเซ€เชจเซ‡ เชธเชพเชฐเซ‹ เชฐเชธเซเชคเซ‹ เชจเชฅเซ€ เช•เชพเชฐเชฃ เช•เซ‡ เชคเซ‡ เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพ เชชเชฐ เชฎเซ‹เชŸเชพ เชชเซ€เช• เชฒเซ‹เชกเชฎเชพเช‚ เชชเชฐเชฟเชฃเชฎเชถเซ‡.

เชธเชฎเชพเช‚เชคเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช…เชฎเชฒเชฎเชพเช‚ เชฎเซ‚เช•เชตเซ€ เช–เซ‚เชฌ เชœ เชธเชฐเชณ เช›เซ‡:

override fun getLast(nInt) =
  messageRepository.findLast(n).parallelStream()
    .map it.toFrontModel() }
    .collect(toList())

เชธเชฎเชพเช‚เชคเชฐ เชฎเซ‡เชธเซ‡เชœ เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช—เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡, เช…เชฎเชจเซ‡ เช†เชฆเชฐเซเชถ เชฐเซ€เชคเซ‡ 300-700 ms เชฎเชณเซ‡ เช›เซ‡, เชœเซ‡ เชจเชฟเชทเซเช•เชชเชŸ เช…เชฎเชฒเซ€เช•เชฐเชฃ เช•เชฐเชคเชพเช‚ เช˜เชฃเซเช‚ เชธเชพเชฐเซเช‚ เช›เซ‡, เชชเชฐเช‚เชคเซ เชนเชœเซ เชชเชฃ เชชเซ‚เชฐเชคเซเช‚ เชเชกเชชเซ€ เชจเชฅเซ€.

เช† เช…เชญเชฟเช—เชฎ เชธเชพเชฅเซ‡, userRepository เช…เชจเซ‡ fileRepository เชจเซ€ เชตเชฟเชจเช‚เชคเซ€เช“ เชธเชฟเช‚เช•เซเชฐเชจเชธ เชฐเซ€เชคเซ‡ เชšเชฒเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡, เชœเซ‡ เช–เซ‚เชฌ เช•เชพเชฐเซเชฏเช•เซเชทเชฎ เชจเชฅเซ€. เช†เชจเซ‡ เช เซ€เช• เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เชคเชฎเชพเชฐเซ‡ เช•เซ‹เชฒ เชฒเซ‹เชœเซ€เช•เชฎเชพเช‚ เช˜เชฃเซ‹ เชซเซ‡เชฐเชซเชพเชฐ เช•เชฐเชตเซ‹ เชชเชกเชถเซ‡. เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, CompletionStage เชฆเซเชตเชพเชฐเชพ (เช‰เชฐเซเชซ Completable Future):

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  CompletableFuture.supplyAsync {
    userRepository.getUserById(author).toFrontReference()
  }.thenCombine(
    files?.let {
      CompletableFuture.supplyAsync {
        fileRepository.getHeadsByIds(files).map it.toFrontReference() }
      }
    } ?: CompletableFuture.completedFuture(listOf())
  ) authorfiles ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }.get()!!

เชคเซ‡ เชœเซ‹เชˆ เชถเช•เชพเชฏ เช›เซ‡ เช•เซ‡ เชถเชฐเซ‚เช†เชคเชฎเชพเช‚ เชธเชฐเชณ เชฎเซ‡เชชเชฟเช‚เช— เช•เซ‹เชก เช“เช›เชพ เชธเชฎเชœเซ€ เชถเช•เชพเชฏ เชคเซ‡เชตเซเช‚ เชฌเชจเซ€ เช—เชฏเซเช‚ เช›เซ‡. เช† เชเชŸเชฒเชพ เชฎเชพเชŸเซ‡ เช›เซ‡ เช•เชพเชฐเชฃ เช•เซ‡ เช…เชฎเชพเชฐเซ‡ เชœเซเชฏเชพเช‚เชฅเซ€ เชชเชฐเชฟเชฃเชพเชฎเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ เชคเซเชฏเชพเช‚เชฅเซ€ เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพเช“เชจเชพ เช•เซ‰เชฒเซเชธเชจเซ‡ เช…เชฒเช— เช•เชฐเชตเชพ เชชเชกเซเชฏเชพ เชนเชคเชพ. เช† เชชเซ‹เชคเซ‡ เช–เชฐเชพเชฌ เชจเชฅเซ€. เชชเชฐเช‚เชคเซ เช•เซ‹เชฒเซเชธเชจเซเช‚ เชธเช‚เชฏเซ‹เชœเชจ เช–เซ‚เชฌ เชญเชตเซเชฏ เชฒเชพเช—เชคเซเช‚ เชจเชฅเซ€ เช…เชจเซ‡ เชคเซ‡ เชเช• เชฒเชพเช•เซเชทเชฃเชฟเช• เชชเซเชฐเชคเชฟเช•เซเชฐเชฟเชฏเชพเชถเซ€เชฒ "เชจเซ‚เชกเชฒ" เชœเซ‡เชตเซเช‚ เชฒเชพเช—เซ‡ เช›เซ‡.

เชœเซ‹ เชคเชฎเซ‡ เช•เซ‹เชฐเซ‹เชŸเซ€เชจเซเชธเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‹ เช›เซ‹, เชคเซ‹ เชฌเชงเซเช‚ เชตเชงเซ เชฏเซ‹เช—เซเชฏ เชฆเซ‡เช–เชพเชถเซ‡:

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  join(
    userRepository.getUserById(author).toFrontReference() },
    files?.let fileRepository.getHeadsByIds(files)
      .map it.toFrontReference() } } ?: listOf() }
  ).let (author, files) ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }

เช•เซเชฏเชพเช‚:

fun <ABjoin(a: () -> Ab: () -> B) =
  runBlocking(IO{
    awaitAll(async a() }async b() })
  }.let {
    it[0as to it[1as B
  }

เชธเซˆเชฆเซเชงเชพเช‚เชคเชฟเช• เชฐเซ€เชคเซ‡, เช†เชตเซ€ เชธเชฎเชพเช‚เชคเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡, เช…เชฎเชจเซ‡ 200-400 ms เชฎเชณเชถเซ‡, เชœเซ‡ เชชเชนเซ‡เชฒเชพเชฅเซ€ เชœ เช…เชฎเชพเชฐเซ€ เช…เชชเซ‡เช•เซเชทเชพเช“เชจเซ€ เชจเชœเซ€เช• เช›เซ‡.

เช•เชฎเชจเชธเซ€เชฌเซ‡, เช†เชตเซ€ เชธเชพเชฐเซ€ เชธเชฎเชพเช‚เชคเชฐเชคเชพ เช…เชธเซเชคเชฟเชคเซเชตเชฎเชพเช‚ เชจเชฅเซ€, เช…เชจเซ‡ เชšเซ‚เช•เชตเชตเชพ เชฎเชพเชŸเซ‡เชจเซ€ เช•เชฟเช‚เชฎเชค เชเช•เชฆเชฎ เช•เซเชฐเซ‚เชฐ เช›เซ‡: เชเช• เชœ เชธเชฎเชฏเซ‡ เชฎเชพเชคเซเชฐ เชฅเซ‹เชกเชพ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพเช“ เช•เชพเชฎ เช•เชฐเซ‡ เช›เซ‡, เชคเซเชฏเชพเชฐเซ‡ เชตเชฟเชจเช‚เชคเซ€เช“เชจเซ‹ เชฌเซ‡เชฐเซ‡เชœ เชธเซ‡เชตเชพเช“ เชชเชฐ เช†เชตเชถเซ‡, เชœเซ‡ เช•เซ‹เชˆเชชเชฃ เชฐเซ€เชคเซ‡ เชธเชฎเชพเช‚เชคเชฐ เชฐเซ€เชคเซ‡ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡ เชจเชนเซ€เช‚, เชคเซ‡เชฅเซ€ เช…เชฎเซ‡ เช…เชฎเชพเชฐเชพ เช‰เชฆเชพเชธเซ€ 4 s เชชเชฐ เชชเชพเช›เชพ เช†เชตเชถเซ‡.

เช†เชตเซ€ เชธเซ‡เชตเชพเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชคเซ€ เชตเช–เชคเซ‡ เชฎเชพเชฐเซเช‚ เชชเชฐเชฟเชฃเชพเชฎ 1300 เชธเช‚เชฆเซ‡เชถเชพเช“เชจเซ€ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เชฎเชพเชŸเซ‡ 1700โ€“20 ms เช›เซ‡. เช† เชชเซเชฐเชฅเชฎ เช…เชฎเชฒเซ€เช•เชฐเชฃ เช•เชฐเชคเชพเช‚ เชตเชงเซ เชเชกเชชเซ€ เช›เซ‡, เชชเชฐเช‚เชคเซ เชนเชœเซ€ เชชเชฃ เชธเชฎเชธเซเชฏเชพ เชนเชฒ เช•เชฐเชคเซเช‚ เชจเชฅเซ€.

เชธเชฎเชพเช‚เชคเชฐ เชชเซเชฐเชถเซเชจเซ‹เชจเชพ เชตเซˆเช•เชฒเซเชชเชฟเช• เช‰เชชเชฏเซ‹เช—เซ‹เชœเซ‹ เชคเซƒเชคเซ€เชฏ-เชชเช•เซเชท เชธเซ‡เชตเชพเช“ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เชชเซเชฐเชฆเชพเชจ เช•เชฐเชคเซ€ เชจเชฅเซ€ เชคเซ‹ เชถเซเช‚? เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชคเชฎเซ‡ เช‡เชจเซเชŸเชฐเชซเซ‡เชธ เชชเชฆเซเชงเชคเชฟเช“เชจเซ€ เช…เช‚เชฆเชฐ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เช…เชฎเชฒเซ€เช•เชฐเชฃเชจเชพ เช…เชญเชพเชตเชจเซ‡ เช›เซเชชเชพเชตเซ€ เชถเช•เซ‹ เช›เซ‹:

interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toSet())
  fun getUsersByIds(idList<UserReference>): List<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toList())
}

เชœเซ‹ เชคเชฎเซ‡ เชญเชตเชฟเชทเซเชฏเชจเชพ เชธเช‚เชธเซเช•เชฐเชฃเซ‹เชฎเชพเช‚ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เชœเซ‹เชตเชพเชจเซ€ เช†เชถเชพ เชฐเชพเช–เชคเชพ เชนเซ‹เชต เชคเซ‹ เช†เชจเซ‹ เช…เชฐเซเชฅ เชฅเชพเชฏ เช›เซ‡.
เช—เซเชฃ:

  1. เชธเช‚เชฆเซ‡เชถ-เช†เชงเชพเชฐเชฟเชค เชธเชฎเชพเช‚เชคเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพเชจเซ‡ เชธเชฐเชณเชคเชพเชฅเซ€ เชฒเชพเช—เซ เช•เชฐเซ‹.
  2. เชธเชพเชฐเซ€ เชฎเชพเชชเชจเซ€เชฏเชคเชพ.

เชตเชฟเชชเช•เซเชท:

  1. เชธเชฎเชพเช‚เชคเชฐ เชตเชฟเชตเชฟเชง เชธเซ‡เชตเชพเช“เชจเซ€ เชตเชฟเชจเช‚เชคเซ€เช“ เชชเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชคเซ€ เชตเช–เชคเซ‡ เชคเซ‡เชจเซ€ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพเชฎเชพเช‚เชฅเซ€ เชกเซ‡เชŸเชพ เชธเช‚เชชเชพเชฆเชจเชจเซ‡ เช…เชฒเช— เช•เชฐเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐเชฟเชฏเชพเชค.
  2. เชคเซƒเชคเซ€เชฏ-เชชเช•เซเชท เชธเซ‡เชตเชพเช“ เชชเชฐ เชญเชพเชฐ เชตเชงเชพเชฐเซ‹.

เชคเซ‡ เชœเซ‹เชˆ เชถเช•เชพเชฏ เช›เซ‡ เช•เซ‡ เชฒเชพเช—เซ เชชเชกเชตเชพเชจเซ‹ เช…เชตเช•เชพเชถ เชฒเช—เชญเช— เชจเชฟเชทเซเช•เชชเชŸ เช…เชญเชฟเช—เชฎ เชœเซ‡เชŸเชฒเซ‹ เชœ เช›เซ‡. เชœเซ‹ เชคเชฎเซ‡ เช…เชจเซเชฏ เชฒเซ‹เช•เซ‹เชจเชพ เชจเชฟเชฐเซเชฆเชฏ เชถเซ‹เชทเชฃเชจเซ‡ เช•เชพเชฐเชฃเซ‡ เชคเชฎเชพเชฐเซ€ เชธเซ‡เชตเชพเชจเชพ เชชเซเชฐเชฆเชฐเซเชถเชจเชจเซ‡ เช˜เชฃเซ€ เชตเช–เชค เชตเชงเชพเชฐเชตเชพ เชฎเชพเช‚เช—เชคเชพ เชนเซ‹เชต เชคเซ‹ เชธเชฎเชพเช‚เชคเชฐ เชตเชฟเชจเช‚เชคเซ€ เชชเชฆเซเชงเชคเชฟเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเซ‹ เชคเซ‡ เช…เชฐเซเชฅเชชเซ‚เชฐเซเชฃ เช›เซ‡. เช…เชฎเชพเชฐเชพ เช‰เชฆเชพเชนเชฐเชฃเชฎเชพเช‚, เชชเซเชฐเชฆเชฐเซเชถเชจเชฎเชพเช‚ 2,5 เช—เชฃเซ‹ เชตเชงเชพเชฐเซ‹ เชฅเชฏเซ‹ เช›เซ‡, เชชเชฐเช‚เชคเซ เช† เชธเซเชชเชทเซเชŸเชชเชฃเซ‡ เชชเซ‚เชฐเชคเซเช‚ เชจเชฅเซ€.

เช•เซ‡เชถเซ€เช‚เช—

เชคเชฎเซ‡ เชฌเชพเชนเซเชฏ เชธเซ‡เชตเชพเช“ เชฎเชพเชŸเซ‡ JPA เชจเซ€ เชญเชพเชตเชจเชพเชฎเชพเช‚ เช•เซ‡เชถเซ€เช‚เช— เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹, เชเชŸเชฒเซ‡ เช•เซ‡, เชชเซเชฐเชพเชชเซเชค เชตเชธเซเชคเซเช“เชจเซ‡ เชธเชคเซเชฐเชจเซ€ เช…เช‚เชฆเชฐ เชธเซเชŸเซ‹เชฐ เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹ เชœเซ‡เชฅเซ€ เช•เชฐเซ€เชจเซ‡ เชคเซ‡เชจเซ‡ เชซเชฐเซ€เชฅเซ€ เชชเซเชฐเชพเชชเซเชค เชจ เชฅเชพเชฏ (เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เชฆเชฐเชฎเชฟเชฏเชพเชจ เชธเชนเชฟเชค). เชคเชฎเซ‡ เช†เชตเชพ เช•เซ‡เชถ เชœเชพเชคเซ‡ เชฌเชจเชพเชตเซ€ เชถเช•เซ‹ เช›เซ‹, เชคเชฎเซ‡ เชคเซ‡เชจเชพ @Cacheable เชธเชพเชฅเซ‡ เชธเซเชชเซเชฐเชฟเช‚เช—เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹, เช‰เชชเชฐเชพเช‚เชค เชคเชฎเซ‡ เชนเช‚เชฎเซ‡เชถเชพ EhCache เชœเซ‡เชตเซ€ เชคเซˆเชฏเชพเชฐ เช•เซ‡เชถเชจเซ‹ เชœเชพเชคเซ‡ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹.

เชเช• เชธเชพเชฎเชพเชจเซเชฏ เชธเชฎเชธเซเชฏเชพ เช เชนเชถเซ‡ เช•เซ‡ เช•เซ‡เชถ เชนเชฟเชŸ เชนเซ‹เชฏ เชคเซ‹ เชœ เช‰เชชเชฏเซ‹เช—เซ€ เช›เซ‡. เช…เชฎเชพเชฐเชพ เช•เชฟเชธเซเชธเชพเชฎเชพเช‚, เชฒเซ‡เช–เช• เช•เซเชทเซ‡เชคเซเชฐ เชชเชฐ เชนเชฟเชŸ เชฅเชตเชพเชจเซ€ เชธเช‚เชญเชพเชตเชจเชพ เช›เซ‡ (เชšเชพเชฒเซ‹ เช•เชนเซ€เช, 50%), เชชเชฐเช‚เชคเซ เชซเชพเช‡เชฒเซ‹ เชชเชฐ เชฌเชฟเชฒเช•เซเชฒ เชนเชฟเชŸ เชฅเชถเซ‡ เชจเชนเซ€เช‚. เช† เช…เชญเชฟเช—เชฎ เช•เซ‡เชŸเชฒเชพเช• เชธเซเชงเชพเชฐเชพเช“ เชชเซเชฐเชฆเชพเชจ เช•เชฐเชถเซ‡, เชชเชฐเช‚เชคเซ เชคเซ‡ เชชเซเชฐเชญเชพเชตเชฎเชพเช‚ เชงเชฐเชฎเซ‚เชณเชฅเซ€ เชซเซ‡เชฐเชซเชพเชฐ เช•เชฐเชถเซ‡ เชจเชนเซ€เช‚ (เช…เชจเซ‡ เช…เชฎเชจเซ‡ เชธเชซเชณเชคเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡).

เช‡เชจเซเชŸเชฐเชธเซ‡เชธเชจ (เชฒเชพเช‚เชฌเชพ) เช•เซ‡เชถเชจเซ‡ เชœเชŸเชฟเชฒ เช…เชฎเชพเชจเซเชฏเชคเชพ เชคเชฐเซเช•เชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เชธเชพเชฎเชพเชจเซเชฏ เชฐเซ€เชคเซ‡, เชคเชฎเซ‡ เชˆเชจเซเชŸเชฐเชธเซ‡เชธเชจ เช•เซ‡เชถเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชชเชฐเซเชซเซ‹เชฐเซเชฎเชจเซเชธ เชธเชฎเชธเซเชฏเชพเช“ เช‰เช•เซ‡เชฒเชตเชพ เชฎเชพเชŸเซ‡ เชœเซ‡เชŸเชฒเซ€ เชชเชพเช›เชณเชฅเซ€ เชจเซ€เชšเซ‡ เช†เชตเชถเซ‹, เชคเซ‡เชŸเชฒเซเช‚ เชธเชพเชฐเซเช‚.

เช—เซเชฃ:

  1. เช•เซ‹เชก เชฌเชฆเชฒเซเชฏเชพ เชตเชฟเชจเชพ เช•เซ‡เชถเซ€เช‚เช—เชจเซ‹ เช…เชฎเชฒ เช•เชฐเซ‹.
  2. เช‰เชคเซเชชเชพเชฆเช•เชคเชพเชฎเชพเช‚ เช˜เชฃเซ€ เชตเช–เชค เชตเชงเชพเชฐเซ‹ (เช•เซ‡เชŸเชฒเชพเช• เช•เชฟเชธเซเชธเชพเช“เชฎเชพเช‚).

เชตเชฟเชชเช•เซเชท:

  1. เชœเซ‹ เช–เซ‹เชŸเซ€ เชฐเซ€เชคเซ‡ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เชคเซ‹ เช•เชพเชฎเช—เซ€เชฐเซ€เชฎเชพเช‚ เช˜เชŸเชพเชกเซ‹ เชฅเชตเชพเชจเซ€ เชถเช•เซเชฏเชคเชพ.
  2. เชฎเซ‹เชŸเซ€ เชฎเซ‡เชฎเชฐเซ€ เช“เชตเชฐเชนเซ‡เชก, เช–เชพเชธ เช•เชฐเซ€เชจเซ‡ เชฒเชพเช‚เชฌเชพ เช•เซ‡เชถ เชธเชพเชฅเซ‡.
  3. เชœเชŸเชฟเชฒ เช…เชฎเชพเชจเซเชฏเชคเชพ, เชญเซ‚เชฒเซ‹ เชœเซ‡เชฎเชพเช‚ เชฐเชจเชŸเชพเชˆเชฎเชฎเชพเช‚ เชชเซเชจเชƒเช‰เชคเซเชชเชพเชฆเชจ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชฎเซเชถเซเช•เซ‡เชฒ เชธเชฎเชธเซเชฏเชพเช“ เชคเชฐเชซ เชฆเซ‹เชฐเซ€ เชœเชถเซ‡.

เช˜เชฃเซ€ เชตเชพเชฐ, เช•เซ‡เชถเชจเซ‹ เช‰เชชเชฏเซ‹เช— เชซเช•เซเชค เชกเชฟเชเชพเช‡เชจ เชธเชฎเชธเซเชฏเชพเช“เชจเซ‡ เชเชกเชชเชฅเซ€ เชชเซ‡เชš เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชฅเชพเชฏ เช›เซ‡. เช†เชจเซ‹ เช…เชฐเซเชฅ เช เชจเชฅเซ€ เช•เซ‡ เชคเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เชฅเชตเซ‹ เชœเซ‹เชˆเช เชจเชนเซ€เช‚. เชœเซ‹ เช•เซ‡, เชคเชฎเชพเชฐเซ‡ เชนเช‚เชฎเซ‡เชถเชพ เชคเซ‡เชฎเชจเซ€ เชธเชพเชฅเซ‡ เชธเชพเชตเชงเชพเชจเซ€เชชเซ‚เชฐเซเชตเช• เชตเชฐเซเชคเชตเซเช‚ เชœเซ‹เชˆเช เช…เชจเซ‡ เชชเซเชฐเชฅเชฎ เชชเชฐเชฟเชฃเชพเชฎเซ€ เชชเชฐเชซเซ‹เชฐเซเชฎเชจเซเชธ เช—เซ‡เชˆเชจเชจเซเช‚ เชฎเซ‚เชฒเซเชฏเชพเช‚เช•เชจ เช•เชฐเชตเซเช‚ เชœเซ‹เชˆเช เช…เชจเซ‡ เชชเช›เซ€ เชœ เชจเชฟเชฐเซเชฃเชฏ เชฒเซ‡เชตเซ‹ เชœเซ‹เชˆเช.

เช…เชฎเชพเชฐเชพ เช‰เชฆเชพเชนเชฐเชฃเชฎเชพเช‚, เช•เซ‡เชถ เชฒเช—เชญเช— 25% เชจเซ‹ เชชเซเชฐเชญเชพเชต เชตเชงเชพเชฐเซ‹ เชชเซเชฐเชฆเชพเชจ เช•เชฐเชถเซ‡. เชคเซ‡ เชœ เชธเชฎเชฏเซ‡, เช•เซ‡เชถเชฎเชพเช‚ เช˜เชฃเชพ เชฌเชงเชพ เช—เซ‡เชฐเชซเชพเชฏเชฆเชพ เช›เซ‡, เชคเซ‡เชฅเซ€ เชนเซเช‚ เชคเซ‡เชจเซ‹ เช…เชนเซ€เช‚ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถ เชจเชนเซ€เช‚.

เชชเชฐเชฟเชฃเชพเชฎเซ‹

เชคเซ‡เชฅเซ€, เช…เชฎเซ‡ เชฌเซ‡เชš เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช—เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชคเซ€ เชธเซ‡เชตเชพเชจเชพ เชจเชฟเชทเซเช•เชชเชŸ เช…เชฎเชฒเซ€เช•เชฐเชฃ เช…เชจเซ‡ เชคเซ‡เชจเซ‡ เชเชกเชชเซ€ เชฌเชจเชพเชตเชตเชพเชจเซ€ เช•เซ‡เชŸเชฒเซ€เช• เชธเชฐเชณ เชฐเซ€เชคเซ‹ เชชเชฐ เชงเซเชฏเชพเชจ เช†เชชเซเชฏเซเช‚.

เช† เชฌเชงเซ€ เชชเชฆเซเชงเชคเชฟเช“เชจเซ‹ เชฎเซเช–เซเชฏ เชซเชพเชฏเชฆเซ‹ เช เชธเชฐเชณเชคเชพ เช›เซ‡, เชœเซ‡เชฎเชพเช‚เชฅเซ€ เช˜เชฃเชพ เชธเซเช–เชฆ เชชเชฐเชฟเชฃเชพเชฎเซ‹ เช›เซ‡.

เช† เชชเชฆเซเชงเชคเชฟเช“เชจเซ€ เชธเชพเชฎเชพเชจเซเชฏ เชธเชฎเชธเซเชฏเชพ เช เชจเชฌเชณเซ€ เช•เชพเชฎเช—เซ€เชฐเซ€ เช›เซ‡, เชฎเซเช–เซเชฏเชคเซเชตเซ‡ เชชเซ‡เช•เซ‡เชŸเซ‹เชจเชพ เช•เชฆเชจเซ‡ เช•เชพเชฐเชฃเซ‡. เชคเซ‡เชฅเซ€, เชœเซ‹ เช† เช‰เช•เซ‡เชฒเซ‹ เชคเชฎเชจเซ‡ เช…เชจเซเช•เซ‚เชณ เชจ เช†เชตเซ‡, เชคเซ‹ เชคเซ‡ เชตเชงเซ เช†เชฎเซ‚เชฒ เชชเชฆเซเชงเชคเชฟเช“ เชงเซเชฏเชพเชจเชฎเชพเช‚ เชฒเซ‡เชตเชพ เชฏเซ‹เช—เซเชฏ เช›เซ‡.

เชคเซเชฏเชพเช‚ เชฌเซ‡ เชฎเซเช–เซเชฏ เชฆเชฟเชถเชพเช“ เช›เซ‡ เชœเซ‡เชฎเชพเช‚ เชคเชฎเซ‡ เช‰เช•เซ‡เชฒเซ‹ เชถเซ‹เชงเซ€ เชถเช•เซ‹ เช›เซ‹:

  • เชกเซ‡เชŸเชพ เชธเชพเชฅเซ‡ เช…เชธเซเชฎเซ‡เชณ เช•เชพเชฐเซเชฏ (เชชเซ‡เชฐเชพเชกเชพเชˆเชฎ เชถเชฟเชซเซเชŸเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡, เชคเซ‡เชฅเซ€ เช† เชฒเซ‡เช–เชฎเชพเช‚ เชšเชฐเซเชšเชพ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ€ เชจเชฅเซ€);
  • เชธเชฟเช‚เช•เซเชฐเชจเชธ เชชเซเชฐเซ‹เชธเซ‡เชธเชฟเช‚เช— เชœเชพเชณเชตเซ€ เชฐเชพเช–เชคเซ€ เชตเช–เชคเซ‡ เชฌเซ‡เชšเชจเซเช‚ เชตเชฟเชธเซเชคเชฐเชฃ.

เชฌเซ…เชšเซ‡เชธเชจเซเช‚ เชตเชฟเชธเซเชคเชฐเชฃ เชฌเชพเชนเซเชฏ เช•เซ‰เชฒเซเชธเชจเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ เชฎเซ‹เชŸเชพ เชชเซเชฐเชฎเชพเชฃเชฎเชพเช‚ เช˜เชŸเชพเชกเซ‹ เช•เชฐเชถเซ‡ เช…เชจเซ‡ เชคเซ‡ เชœ เชธเชฎเชฏเซ‡ เช•เซ‹เชกเชจเซ‡ เชธเชฟเช‚เช•เซเชฐเชจเชธ เชฐเชพเช–เชถเซ‡. เชฒเซ‡เช–เชจเซ‹ เช†เช—เชณเชจเซ‹ เชญเชพเช— เช† เชตเชฟเชทเชฏเชจเซ‡ เชธเชฎเชฐเซเชชเชฟเชค เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡.

เชธเซ‹เชฐเซเชธ: www.habr.com

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹