Je développe une lib en Kotlin (jusque là normal) et disposant de deux PC, il m'arrive de démarrer le travail sur l'un et de le finir sur l'autre (encore une fois normal). Sauf que... Sur mon PC portable, que nous appellerons le PC-P, impossible de compiler la même lib au même numéro de commit (une erreur obscure émane du JDK lui-même) alors que sur mon PC fixe, que nous appellerons PC-F, aucun problème.
C'est partie pour l'enquête ! #StoryTime
1) Mes outils ne sont pas à jour sur l'un des deux postes
Le PC-P ayant les dernières versions mais pas le PC-F, j'aligne le tout (OpenJDK, Intellij, OS, Maven, etc) dans les dernières versions disponibles et non, même résultat. PC-F ça marche, PC-P ça plante !
2) J'accuse le répo local de Maven.
Je drop l'intégralité du répo sur les deux machines, je rebuild avec les mêmes lignes de commande, rien n'y fait.
3) J'accuse le compilateur Kotlin.
Ayant fait une montée de version vers la 1.3.72 je me dis que cette toute dernière version est peut-être instable. Du coup je décrémente sa version à la 1.3.41. Toujours ce fichu problème (il s'agit un JVM access FileNotFound au passage - erreur que je n'avais jamais vu de ma vie).
4) J'accuse mon code
Aparté : oui seulement au bout de 4 étapes mais les trois premières ne me demandaient pas beauoup d'effort.
Je reviens en arrière surun commit, deux commits, cinq commits, 17 commits plus loin et ça marche enfin sur les deux... Sachant que tous mes commits ont été stashés et squashés vous n’imaginez pas le nombre de lignes modifiées... #Pleur
Après investigation, j'arrive au point où j'identifie une classe de test mais plante-t-elle à la compile ou au run ? Je commence à lancer un mvn test-compile
et ça marche. Je lance un mvn test
et ça pète mais toujours pas d'indice.
#FastForward Il se passe une nuit et j'en parle à @Lenny le lendemain. Il teste sur son poste et lui-aussi sa plante. Sauf qu'ayant une version plus ancienne de Mint mais aussi du JDK il voit un message différent du mien : un FileNotFound qui indique une classe, précisément classDeTest$NomDeMethod.class (ce sont les classes virtuelles que créé Java).
Je lui demande de prendre tout le chemin de fichier et d'effectuer un touch (car le chemin à l'air assez long) et le touch pète ! #PremièreVictoire
=> Conclusion rapide : le chemin de fichier est trop long. Mais alors pourquoi est-ce que ça marche sur mon PC-F et pas sur mon PC-P !!? #WTF
... Petit moment de suspense... Ur ur ur (^__^)
Réponse :
Le PC-P de @Lenny tout comme le mien ont une partition Ext4 chiffrée ! Or mon PC Fixe a une partition en clair et il faut savoir qu'une partoche Ext4 en claire permet des chemins de fichiers de 255 caractères tandis qu'une Ext4 chiffrée est limitée à 143 caractères ! Le voilà notre coupable...
Vous n'avez pas idée des heures que j'ai perdues à cause de ce comportement mais je suis tellement contente d'avoir trouvé !
Pour @Chlouchloutte, un tuto simple montrant comment mocker l'objet Context
des routes de JavaLin avec MockK. Mais normalement Mockito en direct devrait aussi faire le café.
Concept :
- Vous démarrez une
main()
vide (enfin qui contient juste le point suivant). - Vous charger un class-loader dynamique qui lui va charger vos JARS ou les répertoires de vos classes directement.
- A chaque mise à jour de ces fichiers, les classes et ressources du classpath seront rechargées à chaud dans l'espace mémoire de la JVM.
Je vais me coder une petite lib qui va se charger de charger l'application à la place de la main()
et permettre les démarrages à chaud. #Luv
Objectifs :
- Trouver un framework qui soit une abstraction du langage SQL
- Ce framework doit être orienté objet (dans la mesure du possible), type-safe et thread-safe et gérer les transactions (autant dire que pour l'OOP, je sais déjà que je repasserai).
- Ce framework ne nécessite pas de créer des entités à la Hibernate.
Ma sélection :
Oh my my, la citation du jour sur Scala et Kotlin :
Kotlin is much like Scala, just without the shitty parts... Whiiiich I guess makes Kotlin nothing like Scala.
Quand vous avez fait du Scala et du Kotlin, vous ne pouvez pas vous empêcher de rire tellement c'est vrai.
Kotlin progresse magistralement sur l'indice de popularité des langages de programmation : PyPL. Soit 4 places de gagnées et 12ième position sur le podium !
Vous avez lu le titre ?
Je veux dire
Vous avez lu le titre ???
I'm sooooooo happy ! Déjà parce que j'avais misé sur Kotlin il y bientôt 4 ans maintenant mais ce n'est pas tout ! Kotlin dispose de l'un des compilateurs les plus restrictifs du marché (avec celui de Rust) et cela signifie que plus ces langages se développeront et moins il sera possible à des non-dev de se faire passer pour des développeurs car il ne leur sera plus possible de passer la barrière du compilateur sans comprendre tous les mécanismes qui se passent derrière (et donc devenir de "vrais devs").
Pourquoi cet élitisme me direz-vous ?
Tout simplement parce que je suis à mon compte et que voir des sous-traitants qui mentent sur un CV et conséquemment tirent mes tarifs vers le bas alors que nous ne proposons pas du tout le même niveau de prestation, bah ça m'agace. Et je ne travaille pas pour être gentille avec le reste du monde, je suis en concurrence directe et brutale avec ceux qui ne m'aident pas à augmenter mon bénéfice. C'est ça, le "libre-marché", ce n'est pas quelque chose j'approuve dans le fond (ceux qui me lisent connaissent mon point de vue sur l'ignominie capitaliste), mais je ne vais pas nier la réalité du terrain et me priver des outils que les règles du jeu fabriquent et permettent.
Bref, non seulement Kotlin est un outil formidable du point de vue de l'ingénierie mais en plus Kotlin sera un outil formidable du point de vue du recrutement et de la sélection. Et ce n'est qu'un début, vous verrez :D
Un bel exemple d'exécution parallèle et de résultat synchrone en Kotlin.
@Animal je te recommande cet article pour mieux comprendre le travail que tu feras avec @Milk et @Sigmund.
Remarque :
- Le concept de cache ici pose problème puisque des méthodes qui transforment (à base de verbes) retournent en réalité quelque chose.
- Les méthodes avec des boolean ont des verbes, c'est une exception à la Yegorification du code.
// Usage :
object Main {
fun regularUseCase() {
// Given
val christmas = LocalDate(2019, 12, 25)
val calendar:HolidaysCalendar = HolidaysCalendarForYear(Year(2019))
// When
val daysOff:DateSet = calendar.daysOff()
// Then
println(daysOffs.contains(christmas)) // print true
}
fun cachedUseCase() {
// Given
val christmas = LocalDate(2019, 12, 25)
val cache:Cache = HolidaysCalendarCache()
// When
val daysOff2:HolidaysCalendar = cache.value(Year(2019))
val daysOff3:HolidaysCalendar = cache.value(Year(2019))
// Then
println(daysOff2.contains(christmas)) // print true
println(daysOff2 === daysOff3) // print true (same instance)
}
@JvmStatic
fun main() {
val main = Main()
main.regularUseCase()
main.cachedUseCase()
}
}
// Interfaces
interface DateSet {
/**
* Determine whether or not the specified date is in this set.
*
* @param date
* The date to research.
*
* @return true if the date exists in this set, false otherwise.
*/
fun contains(date:LocalDate):Boolean
/**
* Determine whether or not the specified date is in this set.
*
* @param date
* The date to research.
*
* @return true if the date exists in this set, false otherwise.
*/
fun contains(date:Calendar):Boolean
/**
* Return the current set of date as an iterable collection.
*
* @return A collection having all the date stored in this set.
*/
fun asCollection():Collection<LocalDate>
}
interface HolidaysCalendar {
/**
* Return a set of holiday dates.
*
* @return All holidays for a period (see implementation for more detail).
*/
fun daysOff():DateSet
/**
* The period covered by this calendar.
*
* @return Something in the CalenadrPeriod enumeration.
*/
fun range():CalenadrPeriod
}
class Cache<K, V> {
/**
* Determine whether or not the specified value exists in this cache.
*
* @param value
* The value to search.
*
* @return true if the value has been found, false otherwise.
*/
fun contains(value:V):Boolean
/**
* Determine whether or not a key exists in this cache.
*
* @param key
* The key to search.
*
* @return true if the key exists, false otherwise (reminder: a key cannot exists if linked to nothing).
*/
fun containsKey(key:K):Boolean
/**
* Retrieve the value related to the specified key.
*
* @param key
* The key related to the researched value.
*
* @return The value related to the given key.
*
* @throw UnexistingEntryException
* When the subsystem cached by this object is not able to restitute a value using the specified key.
*/
fun value(key:K):V
/**
* The list of keys used by this cache.
*
* @return The list of keys used by this cache.
*/
fun keys():List<K>
/**
* Remove the specified key in order to force an update.
*
* @param key
* The key of the cache entry to remove.
*/
fun remove(key:K)
/**
* Clear all entry is the current cache.
*/
fun reset()
}
// Implementation of HolidaysCalendar
class HolidaysCalendarForYear(private val year:Year):HolidaysCalendar
class HolidaysCalendarForMonth(private val year:Year, private val month:Month):HolidaysCalendar
// Implementation of Cache
class HolidaysCalendarCache:Cache<Year, HolidaysCalendar>
J'abonde dans le sens de l'article. Le design pattern Builder est totalement obsolète en Kotlin puisque ce langage intègre les "defaulted method parameters" ce qui fait que si un paramètre venait à manquer, alors il prendrait automatiquement la valeur par défaut, par exemple :
class SocketJavaX(
private val port:Int = 0,
private val host:String? = null,
private val ssl:Boolean = false
)
Quand je vous disais que Kotlin a une multitude de petites choses qui rendent le dev facile et magique.
Quand j'évoque Kotlin, je sais que comme beaucoup je mets en avant un langage en donnant une impression de fanatisme... Mais faut bien comprendre que je suis une grande fan !
Un exemple, la différence entre la @Deprecated
de Java et la @Deprecated
de Kotlin.
// En java nous déclarons une méthode dépréciée soit sans commentaire
@Deprecated
public void vieuxProut() {
// ...
}
// Soit avec
@Deprecated("Cette implémentation sera abandonnée dans la future 1.2. Utilisez Toto.petDansLaSoie() à la place")
public void vieuxProut() {
// ...
}
Mais en Kotlin nous avons bien plus !
@Deprecated(
"Cette implémentation sera abandonnée dans la future 1.2. Utilisez Toto.petDansLaSoie() à la place",
replaceWith = ReplaceWith(
"petDansLaSoie(x)",
"com.maboite.monprojet.Toto.petDansLaSoie"
)
)
fun vieuxProut() {
// ...
}
Et à cet instant IntelliJ va automatiquement proposer d'utiliser la nouvelle implémentation, par exemple :
Et ce langage est BARDÉ de petits détails comme ça qui vous facilitent la vie.
Bon ça fait deux années maintenant et je sais où j'en suis niveau langage de programmation : de toutes les syntaxes, ma préférée est sans aucun doute et de trèèès loin celle de Kotlin (sauf pour les get / set).
Par contre, le meilleur compilateur du marché est celui de Rust, il n'y a pas photo. J'ai vraiment hâte que Kotlin Native décolle 😉 !
Via Riduidel.
Spoiler de l'article : Kotlin gagne quasiment partout.
Par contre Kotlin n'est pas que pour Android mais aussi pour tout ce qui cible la JVM ou la compilation du byte-code de JVM en natif. Chez nous il est côté serveur depuis plus de deux ans maintenant et a TOTALEMENT REMPLACÉ JAVA !
Nouvelle version mineure de Kotlin apportant une pléthore de correctifs ! La release note générale est très bien faite (les animations aident vraiment comprendre) ! Bref un modèle à suivre.
En plus de tout ceci je vous mets :
- Le lien vers le change log JVM.
- Le lien vers le change log Kotlin Native.
J'étais complètement passée à côté de cela ! L'API time a été repensée en Kotlin pour éviter la confusion de passer une durée en Long et de ne pas savoir s'il s'agit de secondes, de millisecondes, de nanosecondes, etc.
L'idée est d'utiliser les inline-classes (ie. l'enrichissement d'un type existant par un sous-type) et c'est très astucieux regardez :
import kotlinx.coroutines.delay
import kotlin.time.*
@ExperimentalTime
suspend fun greetAfterTimeout(duration: Duration) {
delay(duration.toLongMilliseconds())
println("Hi!")
}
@UseExperimental(ExperimentalTime::class)
suspend fun main() {
greetAfterTimeout(100.milliseconds)
greetAfterTimeout(1.seconds)
}
Les Integer contiennent des classes internes qui vont retourner un objet de type Duration
et contenant la valeur de l'Integer. De cette manière nous avons la valeur et son type en une seule fois.
Ce langage est tellement réfléchi c'est incroyable.
Cela avait le don de me frustrer qu'une feature aussi standard ne soit toujours pas implémentée dans un IDE qui sait le faire dans d'autres langages depuis des années. Et après une courte recherche, il y a une raison plus que pertinente : l'ordre des imports en Kotlin influe sur la façon dont le code sera compilé.
Dit autrement, pour une même classe, ordonnancer ses imports différemment ne produira pas le même bytecode. De ce fait, j'ai désactivé le check dans Ktlint pour éviter tout problème.
P.S : IntelliJ semble importer les éléments "dans le bon ordre par défaut".
La documentation en Kotlin est produite à partir de Dokka et non le maven-javadoc-plugin (normal puisqu'il s'agit de parler/lexer un autre langage).
Cette page décrit les différences de syntaxe entre la JavaDoc et la KDoc.
La page est très limpide sur les Do et les Don't. Je suis en train d'intégrer le plugin à nos builds.
lol @Doudou qui parle des coroutines et qui ne lit pas mes posts.
En vrai, c'est trop cool les coroutines tu verras !
Ohhhh ce benchmark sur Kotlin ! Sur certains points Kotlin est plus rapide que Java mais pas tout le temps et il y a des choses à éviter absolument comme les varargs
.
Pour résumer l'article :
Plus rapide que Java | Mois rapide que Java |
---|---|
✅ Higher-order functions | ⛔️ Varargs + Spread Operator |
✅ Lambda expressions | ⛔️ Delegate Properties |
✅ Companion Objects | ⛔️ Ranges (forEach function) |
✅ Local Functions | |
✅ Null safety | |
✅ Indirect access to Range | |
✅ Ranges (local, non-primitive types) | |
✅ Ranges (iteration with explicit step) | |
✅ Use of indices on custom collection |