Problèmes oubliés,
Course arrêtée
Injecté par des robots
Homme heureux!
Du film "Terminator de l'enfance" "Adventure Electronics"
Bonjour, nous reparlerons aujourd'hui des performances. À propos de la productivité des développeurs.
Je vais parler de la façon de pomper cette compétence à travers les idées. J'espère que mes conseils vous seront utiles, les commentaires et améliorations sont les bienvenus. C'est parti!
Un développeur ordinaire consacre une partie considérable de sa journée de travail à des activités de routine. Jusqu'à récemment, j'agissais également. Et puis quelques pensées simples et évidentes ont surgi dans ma tête:
- rarement nous écrivons vraiment quelque chose de nouveau et inhabituel
- une partie importante du temps de travail, le développeur écrit le code du modèle
- bon nombre des constructions simples que nous utilisons sont facilement formalisables, et dans nos têtes, nous les exprimons en quelques mots
La majeure partie du temps où je travaille avec Spring Booth / Hibernate, la plupart de la génération de code et des modèles les concernent, bien que l'approche soit universelle et que vous puissiez facilement apporter des améliorations similaires à vos projets.
Le théâtre commence par un cintre et l'application Spring Booth commence par les paramètres. Habituellement, ils sont signés dans le fichier application.yml
/ application.properties
, mais il arrive également que certains beans / configurations doivent être décrits avec du code:
@Configuration @EnableSwagger2 class SwaggerConfig { @Bean Docket documentationApi() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } }
Ce paramètre inclut Swagger (un élément utile sur la ferme). Pensez à ce qui peut être automatisé? Les développeurs savent que @Configuration
est placé au-dessus de la classe des paramètres. C'est-à-dire vous pouvez créer une sorte de blanc - un modèle de la classe de configuration et le créer en un clin d'œil. Prêt à l'emploi, «Idée» donne à l'utilisateur la possibilité de personnaliser lui-même les modèles existants:

Ce que nous utiliserons:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end import org.springframework.context.annotation.Configuration; @Configuration class ${NAME} { }
Pour les développeurs expérimentés, tout est clair ici, pour les débutants je vais vous expliquer:
Ligne 1: une ligne comme celle-ci sera ajoutée au code de la classe nouvellement créée
package com.example.-;
Ligne 2: connectez l'annotation souhaitée
Ligne 3: classe de corps.
Notez que la variable ${NAME}
se transformera en une fenêtre pop-up où nous devrons entrer le nom de la classe.
Total:

Ce modèle nous évite d'avoir à écrire @Configuration
sur une classe de nos @Configuration
mains et à résoudre l'importation. Pas grand-chose, mais il est important pour nous de commencer et d'acquérir de l'expérience.
Une classe de paramètres vide vaut à elle seule peu. Apprenons à créer des beans sans effort supplémentaire. Pour ce faire, dans Éditeur> Modèles de fichiers et de codes , accédez à Éditeur> Modèles dynamiques . Ici, vous pouvez décrire des modèles reconnus en tapant. Dans mon environnement de développement, j'ai défini une sous-espèce distincte à utiliser avec Spring. Nous y créons un modèle:
@Bean public $CLASS_NAME$ $mthdName$() { return new $CLASS_NAME$($END$); }
La variable CLASS_NAME
est définie par l'utilisateur dans une fenêtre contextuelle et, en plus de l'affectation directe, est utilisée pour créer un nom de méthode:

La variable mthdName
utilise la méthode camelCase()
, à laquelle est transmise la valeur de CLASS_NAME
. Le réglage a lieu dans Modifier les variables :

La variable $END$
signifie la position du pointeur après le rendu. Notre bean a probablement des dépendances (implémentées via le constructeur), vous devez donc en faire des arguments à la méthode qui retourne notre bean:

Passons maintenant en revue l'application de haut en bas et voyons quelles autres tâches quotidiennes peuvent être accélérées d'une manière aussi simple.
Le service
Le bon sens suggère que cette méthode sera très utile dans les cas où nous avons une grande quantité de code qui erre d'un endroit à l'autre. Par exemple, un service Spring régulier dépend probablement des référentiels (ce qui signifie que les transactions sont nécessaires), effectue une sorte de journalisation et les dépendances sont implémentées via le constructeur. Afin de ne pas répertorier à chaque fois toutes les annotations sur la classe nouvellement créée, nous décrivons le modèle:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 @Service @Transactional @RequiredArgsConstructor public class ${NAME} { }
En action:

Vient ensuite la liste haineuse des dépendances. Ci-dessus, nous avons utilisé la méthode camelCase()
pour décrire le nom de la méthode qui renvoie le bean. Ils peuvent également créer des noms de champs:

private final $CLASS_NAME$ $fieldName$; $END$
Afin de ne pas appuyer à chaque fois sur Ctrl + Alt + L (alignement), cochez la case Reformater selon le style et l'environnement fera tout pour vous:

Référentiels et entités
Même dans les entités les plus simples, nous avons de nombreuses annotations d'importation. Vous pouvez créer un modèle très efficace pour eux:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") import lombok.Getter; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Getter @Table @Entity public class ${NAME} { @Id private Long id; }

En 2019, si vous utilisez Hibernate, vous utilisez sûrement également Spring Date, et si c'est le cas, vous devez créer des référentiels. Accélérons leur création:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") import org.springframework.data.jpa.repository.JpaRepository; public interface ${Entity_name}Repository extends JpaRepository<${Entity_name}, ${Key}>{ }

Ce serait formidable si, lorsque vous placez le curseur sur l'entité (la classe marquée @Entity
et @Table
) et que vous appuyez sur Alt + Entrée, l ' «Idée» suggère de créer immédiatement un référentiel, mais ce n'est pas si intelligent :). Actuellement, les utilisateurs n'ont pas la possibilité de changer / ajouter des intentions ( Editeur> Intentions ), mais vous pouvez écrire votre propre plugin:

Test
En général, plus il y a de constructions de modèles dans votre code, plus le gain d'automatisation est important. Les tests sont l'un des travaux les plus répétés. Ceux qui ont regardé le rapport de Cyril Tolkachev «La malédiction du test de printemps» savent qu'il existe un moyen facile de faire monter le contexte une seule fois pour tous les tests: créer une classe abstraite et en hériter tous les tests.
Décrire quelque chose comme
package com.example; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import org.springframework.test.context.junit.jupiter.SpringExtension; @Transactional @SpringBootTest @ExtendWith(SpringExtension.class) public abstract class BaseTest { }
nous pouvons facilement faire en sorte que tous les tests nouvellement créés héritent de BaseTest
. Pour ce faire, vous devez modifier le modèle qui crée le test par défaut:

Dans le code:
import com.example.BaseTest; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; #parse("File Header.java") class ${NAME} extends BaseTest { ${BODY} }
Nous décrivons ensuite les dépendances. Je ne veux pas composer à chaque fois
@Autowired private MyService service;
par conséquent, dans la section Editeur> Modèles dynamiques, écrivez
@Autowired private $CLASS_NAME$ $fieldName$; $END$
La variable $fieldName$
décrite exactement de la même manière que dans l'exemple de création d'un bean, à une exception près: pour immédiatement après avoir créé un champ, le curseur n'y passe pas, vous devez cocher Ignorer si défini :

Fondamentalement, @Autowired
nécessaire que pour les champs de classe, assurez-vous donc de définir la déclaration dans la liste déroulante Applicable dans :

Nous regardons:

Soit dit en passant, puisque nous créons un test pour une certaine classe, rien ne nous empêche d'introduire la dépendance nécessaire immédiatement lors de sa création ( toCamelCase()
ne fonctionne pas ici, donc Velocity est utilisé):
import com.example.demo.BaseTest; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; #parse("File Header.java") class ${NAME} extends BaseTest { #set($bodyLength = $NAME.length() - 4) #set($field = $NAME.substring(0, 1).toLowerCase() + $NAME.substring(1, $bodyLength)) @Autowired private ${CLASS_NAME} ${field}; ${BODY} }

D'après mon expérience, dans la mesure du possible, tous les tests devraient être transversaux. Même si un service est vérifié qui supprime l'entité et coupe une partie de l'un de ses champs, il est toujours préférable d'obtenir l'entité honnêtement, c'est-à-dire à partir de la base de données. Par conséquent, pour la plupart des tests, je prends des données honnêtes de l'un des environnements et les charge avant d'exécuter le test à l'aide de @Sql
.
L'échantillonnage des données doit être fait à la main pour chaque tâche, mais les relier au test souhaité peut être facilement automatisé. Encore une fois, allez dans Editor> Live templates , la section JUnit et écrivez:
@Sql("/sql/$CLASS_NAME$.sql") $END$

Maintenant, en tapant sql
, nous obtenons une liste déroulante avec 1 enregistrement, en sélectionnant celui que nous obtenons:
@Sql("/sql/MyEntityRepositoryTest.sql") class MyEntityRepositoryTest extends BaseTest { }
Veuillez noter que le fichier auquel nous faisons référence n'existe pas encore, donc lorsque vous exécutez le test sous forme brute, il se bloquera certainement. Cependant, à partir de la version 193.1617 , l'Idea met en évidence un fichier inexistant et, surtout, il suggère de le créer!

Postfixes
L'un des outils les plus puissants est la création / l'ajout de code à l'aide d'expressions postfixes (terminaisons). L'exemple le plus simple:

Il y a beaucoup de finitions, vous pouvez toutes les voir dans la section Editeur> Général> Achèvement de Postfix :

Il existe également des possibilités pour différents types d'expériences. Pour ma part, j'ai effectué un achèvement pour remplacer une variable dans une expression de test basée sur AssertJ :

Dans la vie, cela ressemble à ceci:

Liens utiles
Si vous souhaitez améliorer vos compétences avec l'idée, assurez-vous de consulter deux excellents rapports:
Anton Arkhipov - travail efficace avec IntelliJ IDEA
Tagir Valeev - Refactoring atomique dans IntelliJ IDEA: nous plions l'IDE pour nous-mêmes
C'est tout, soyez rarement distrait et souvenez-vous que le temps est notre seule ressource vraiment non renouvelable.