Upgrade to Pro — share decks privately, control downloads, hide ads and more …

KotlinのLinter まなびなおし2024

KotlinのLinter まなびなおし2024

Linter導入していますか?
Linterはコーディング規約を遵守しているかを検査したり、潜在的なバグのにおいを検知してくれたりと開発をするうえでとても頼りになる存在です。
また非常に多くのルールが標準で用意されているためこれらを利用するだけでも有用ですが、自分たちで適用するルールを選択したりカスタムルールを作成することもでき、柔軟な設定をすることができます。
一方でその柔軟さのあまり、使いこなせていないと感じたり、実は形骸化してしまっていてるといったケースもあるのではないでしょうか。

本セッションでは、ktlintやdetekt、Release1.0間近のKonsistといったKotlin向けのLinterの特徴や活用シーンなどを再履修し、「なんとなく」から「意識的に選択・活用できる」ようになることを目指したいと思います。

nyafunta9858

June 22, 2024
Tweet

More Decks by nyafunta9858

Other Decks in Programming

Transcript

  1. 小林 慶弘 (Yoshihiro Kobayashi) a.k.a nyafunta9858 • Android Engineer @

    Yappli, Inc. • 趣味:ガジェット集め、ゲーム、カメラ ...
  2. Linterとは Lint is the computer science term for a static

    code analysis tool used to flag programming errors, bugs, stylistic errors and suspicious constructs. The term originates from a Unix utility that examined C language source code. A program which performs this function is also known as a "linter". Wikipedia “Lint”
  3. 目次 • 本セッションについて • Linterとは • ktlint • detekt •

    サンプルケースでの導入を考えてみる • Konsist
  4. ktlint • 目的:コードスタイル・フォーマットの準拠 ◦ Kotlinのコーディング規約、 Android Kotlin Style Guideへの準拠 •

    フォーマッタ(ソースコードの自動で整える機能)がビルトイン • 標準で93種類のルールセットを用意 • IntelliJ Plugin、Gradleほか複数のセットアップ環境を提供
  5. ktlint -標準ルールセット- Annotation formatting Binary expression wrapping Blank line before

    declarations Block comment initial star alignment Chain method continuation Class signature Enum entry File name Final newline Function expression body Function literal Function signature Function type modifier spacing If else bracing Import ordering Indentation Naming Backing property naming Class naming Function naming Package name Property naming No blank lines in list No consecutive comments No empty file No empty first line at start in class body No single line block comment Ktlint-suppression rule Max line length Modifier order Multiline if-else Multiline loop No blank lines before } No blank lines in chained method calls No consecutive blank lines No empty ({}) class bodies No leading empty lines in method blocks No line break after else No line break before assignment No multi spaces No semicolons No trailing whitespaces No Unit as return type No unused imports No wildcard imports Spacing Angle bracket spacing Annotation spacing Blank line between declarations with annotations Blank line between declaration with comments Colon spacing Comma spacing Comment spacing Curly spacing Dot spacing Double colon spacing Function return type spacing Function start of body spacing Function type reference spacing Fun keyword spacing Kdoc wrapping Keyword spacing Modifier list spacing Nullable type spacing Operator spacing Parameter list spacing Parenthesis spacing Range spacing Spacing between function name and opening parenthesis Try catch finally spacing Type argument list spacing Type parameter list spacing Unary operator spacing String template String template indent Trailing comma on call site Trailing comma on declaration site Type argument comment Type parameter comment Unnecessary parenthesis before trailing lambda Value argument comment Value parameter comment Wrapping Argument list wrapping Chain wrapping Comment wrapping Condition wrapping Content receiver wrapping Enum wrapping If else wrapping Multiline expression wrapping Parameter list wrapping Parameter wrapping Property wrapping Statement wrapping Wrapping
  6. ktlint -セットアップ- jlleitschuh/ktlint-gradle • チェック・フォーマットタスクを自動生成、 Gradle Build Cacheサポートなど jeremymailen/kotlinter-gradle •

    インクリメンタルビルドのサポート、 ktsファイルのサポート diffplug/spotless • Kotlinに依らず広範な言語をサポートする Linter autostyle/autostyle • spotlessからforkされたプロジェクト、 spotlessとは異なる機能追加
  7. detekt -標準ルールセット- Comments Rule Set AbsentOrWrongFileLicense CommentOverPrivateFunction CommentOverPrivateProperty DeprecatedBlockTag EndOfSentenceFormat

    KDocReferencesNonPublicProperty OutdatedDocumentation UndocumentedPublicClass UndocumentedPublicFunction UndocumentedPublicProperty Complexity Rule Set CognitiveComplexMethod ComplexCondition ComplexInterface CyclomaticComplexMethod LabeledExpression LargeClass LongMethod LongParameterList MethodOverloading NamedArguments NestedBlockDepth NestedScopeFunctions ReplaceSafeCallChainWithRun StringLiteralDuplication TooManyFunctions Coroutines Rule Set GlobalCoroutineUsage InjectDispatcher RedundantSuspendModifier SleepInsteadOfDelay SuspendFunSwallowedCancellation SuspendFunWithCoroutineScopeReceiver SuspendFunWithFlowReturnType Empty-blocks Rule Set EmptyCatchBlock EmptyClassBlock EmptyDefaultConstructor EmptyDoWhileBlock EmptyElseBlock EmptyFinallyBlock EmptyForBlock EmptyFunctionBlock EmptyIfBlock EmptyInitBlock EmptyKtFile EmptySecondaryConstructor EmptyTryBlock EmptyWhenBlock EmptyWhileBlock Exceptions Rule Set ExceptionRaisedInUnexpectedLocation InstanceOfCheckForException NotImplementedDeclaration ObjectExtendsThrowable PrintStackTrace RethrowCaughtException ReturnFromFinally SwallowedException ThrowingExceptionFromFinally ThrowingExceptionInMain ThrowingExceptionsWithoutMessageOrCause ThrowingNewInstanceOfSameException TooGenericExceptionCaught TooGenericExceptionThrown Formatting Rule Set AnnotationOnSeparateLine AnnotationSpacing ArgumentListWrapping BlockCommentInitialStarAlignment ChainWrapping ClassName CommentSpacing CommentWrapping ContextReceiverMapping DiscouragedCommentLocation EnumEntryNameCase EnumWrapping Filename FinalNewline FunKeywordSpacing FunctionName FunctionReturnTypeSpacing FunctionSignature FunctionStartOfBodySpacing FunctionTypeReferenceSpacing IfElseBracing IfElseWrapping ImportOrdering Indentation KdocWrapping MaximumLineLength ModifierListSpacing ModifierOrdering MultiLineIfElse MultilineExpressionWrapping NoBlankLineBeforeRbrace NoBlankLineInList NoBlankLinesInChainedMethodCalls Naming Rule Set BooleanPropertyNaming ClassNaming ConstructorParameterNaming EnumNaming ForbiddenClassName FunctionMaxLength FunctionMinLength FunctionNaming FunctionParameterNaming InvalidPackageDeclaration LambdaParameterNaming MatchingDeclarationName MemberNameEqualsClassName NoNameShadowing NonBooleanPropertyPrefixedWithIs ObjectPropertyNaming PackageNaming TopLevelPropertyNaming VariableMaxLength VariableMinLength VariableNaming Performance Rule Set ArrayPrimitive CouldBeSequence ForEachOnRange SpreadOperator UnnecessaryPartOfBinaryExpression UnnecessaryTemporaryInstantiation Potential-bugs Rule Set AvoidReferentialEquality CastNullableToNonNullableType CastToNullableType Deprecation DontDowncastCollectionTypes DoubleMutabilityForCollection DuplicateCaseInWhenExpression ElseCaseInsteadOfExhaustiveWhen EqualsAlwaysReturnsTrueOrFalse EqualsWithHashCodeExist ExitOutsideMain ExplicitGarbageCollectionCall HasPlatformType IgnoredReturnValue ImplicitDefaultLocale ImplicitUnitReturnType InvalidRange IteratorHasNextCallsNextMethod IteratorNotThrowingNoSuchElementException LateinitUsage MapGetWithNotNullAssertionOperator MissingPackageDeclaration MissingWhenCase NullCheckOnMutableProperty NullableToStringCall PropertyUsedBeforeDeclaration NoConsecutiveBlankLines NoConsecutiveComments NoEmptyClassBody NoEmptyFirstLineInClassBody NoEmptyFirstLineInMethodBlock NoLineBreakAfterElse NoLineBreakBeforeAssignment NoMultipleSpaces NoSemicolons NoSingleLineBlockComment NoTrailingSpaces NoUnitReturn NoUnusedImports NoWildcardImports NullableTypeSpacing PackageName ParameterListSpacing ParameterListWrapping ParameterWrapping PropertyName PropertyWrapping SpacingAroundAngleBrackets SpacingAroundColon SpacingAroundComma SpacingAroundCurly SpacingAroundDot SpacingAroundDoubleColon SpacingAroundKeyword SpacingAroundOperators SpacingAroundParens SpacingAroundRangeOperator SpacingAroundUnaryOperator SpacingBetweenDeclarationsWithAnnotations SpacingBetweenDeclarationsWithComments SpacingBetweenFunctionNameAndOpeningParenthesis StringTemplate StringTemplateIndent TrailingCommaOnCallSite TrailingCommaOnDeclarationSite TryCatchFinallySpacing TypeArgumentListSpacing TypeParameterListSpacing UnnecessaryParenthesesBeforeTrailingLambda Wrapping Libraries Rule Set ForbiddenPublicDataClass LibraryCodeMustSpecifyReturnType LibraryEntitiesShouldNotBePublic RedundantElseInWhen UnconditionalJumpStatementInLoop UnnecessaryNotNullCheck UnnecessaryNotNullOperator UnnecessarySafeCall UnreachableCatchBlock UnreachableCode UnsafeCallOnNullableType UnsafeCast UnusedUnaryOperator UselessPostfixExpression WrongEqualsTypeParameter Ruleauthors Rule Set UseEntityAtName ViolatesTypeResolutionRequirements Style Rule Set AlsoCouldBeApply BracesOnIfStatements BracesOnWhenStatements CanBeNonNullable CascadingCallWrapping ClassOrdering CollapsibleIfStatements DataClassContainsFunctions DataClassShouldBeImmutable DestructuringDeclarationWithTooManyEntries DoubleNegativeLambda EqualsNullCall EqualsOnSignatureLine ExplicitCollectionElementAccessMethod ExplicitItLambdaParameter ExpressionBodySyntax ForbiddenAnnotation ForbiddenComment ForbiddenImport ForbiddenMethodCall ForbiddenSuppress ForbiddenVoid FunctionOnlyReturningConstant LoopWithTooManyJumpStatements MagicNumber MandatoryBracesLoops MaxChainedCallsOnSameLine MaxLineLength MayBeConst ModifierOrder MultilineLambdaItParameter MultilineRawStringIndentation NestedClassesVisibility NewLineAtEndOfFile NoTabs NullableBooleanCheck ObjectLiteralToLambda OptionalAbstractKeyword OptionalUnit OptionalWhenBraces PreferToOverPairSyntax ProtectedMemberInFinalClass RedundantExplicitType RedundantHigherOrderMapUsage RedundantVisibilityModifierRule ReturnCount SafeCast SerialVersionUIDInSerializableClass SpacingBetweenPackageAndImports StringShouldBeRawString ThrowsCount TrailingWhitespace TrimMultilineRawString UnderscoresInNumericLiterals UnnecessaryAbstractClass UnnecessaryAnnotationUseSiteTarget UnnecessaryApply UnnecessaryBackticks UnnecessaryBracesAroundTrailingLambda UnnecessaryFilter UnnecessaryInheritance UnnecessaryInnerClass UnnecessaryLet UnnecessaryParentheses UntilInsteadOfRangeTo UnusedImports UnusedParameter UnusedPrivateClass UnusedPrivateMember UnusedPrivateProperty UseAnyOrNoneInsteadOfFind UseArrayLiteralsInAnnotations UseCheckNotNull UseCheckOrError UseDataClass UseEmptyCounterpart UseIfEmptyOrIfBlank UseIfInsteadOfWhen UseIsNullOrEmpty UseLet UseOrEmpty UseRequire UseRequireNotNull UseSumOfInsteadOfFlatMapSize UselessCallOnNotNull UtilityClassWithPublicConstructor VarCouldBeVal WildcardImport Configuration for Compose FunctionNaming for Compose TopLevelPropertyNaming for Compose LongParameterList for Compose MagicNumber for Compose UnusedPrivateMember for Compose TooManyFunctions for Compose
  8. Jetpack Compose Rules State Hoist all the things State should

    be remembered in composables Use Immutable annotation whenever possible Use mutableStateOf type-specific variants when possible Composables Do not use inherently mutable types as parameters Do not use MutableState as a parameter Be mindful of the arguments you use inside of a restarting effect Do not emit content and return a result Do not emit multiple pieces of content Slots for main content should be the trailing lambda Naming CompositionLocals properly Naming multipreview annotations properly Naming @Composable functions properly Naming Composable annotations properly Ordering @Composable parameters properly Naming parameters properly Movable content should be remembered Make dependencies explicit ViewModels CompositionLocals Preview composables should not be public Modifiers When should I expose modifier parameters? Modifier order matters Modifiers should be used at the top-most layout of the component Don't re-use modifiers Modifiers should have default parameters Naming modifiers properly Avoid Modifier extension factory functions ComponentDefaults ComponentDefaults object should match the composable visibility Opt-in rules Don't use Material 2 Avoid using unstable collections
  9. ここまでのまとめ ktlint • コードスタイル・フォーマットの準拠 • フォーマッタがビルトイン • 標準で93種類のルールセットを用意 • IntelliJ

    Plugin、Gradleほか複数のセット アップ環境を提供 detekt • コード品質の向上や潜在的なバグの検出 • フォーマッタは拡張機能として提供 • 標準で302種類のルールセットを用意 • IntelliJ Plugin、Gradleほか複数のセット アップ環境を提供
  10. Konsist • Architectural Checks / Declarative Checks • ユニットテスト環境で実行 ◦

    JUnit4、JUnit5、Kotestなどのテスティングフレームワーク上で実行可能 • 標準ルールセットはなし
  11. Konsist However, there are no industry standards when comes to

    application architecture. Every code base is different - different class names, different package structures, different application layers, etc. As the project grows code base evolves as well - it tends to have more layers, more modules, and a more complex code structure. These "rules" are hard to capture by generic linter, because they are often specific to the given project. https://docs.konsist.lemonappdev.com/
  12. Konsist UseCaseクラスの定義とは? • ❌GetUserData / ⭕GetUserDataUseCase • UseCaseがUseCaseを持つことを許容する / しない

    • UseCaseは operator fun invoke のみを持つ • suspend fun / Flow • UseCaseには@UseCaseをつける ほか 🤔
  13. Konsist -セットアップ- Typically, it's advisable to consolidate all Konsist tests

    in a unified location. This approach is preferred because these tests are often designed to validate the structure of the entire project's codebase. There are three potential options for storing Konsist tests: https://docs.konsist.lemonappdev.com/
  14. Konsist -まとめ- • Architectural Checks / Declarative Checks • ユニットテスト環境で実行

    • シンプルで強力なAPI • ファイルレベルの検査であるktlint、detektに対して Konsistはプロダクト全体をスコープにできる • ktlint、detektでは検査しにくいルールもカバーする柔軟さ • 汎用的なルールセット(検討中) など
  15. まとめ ktlint • コードスタイル・フォーマットの準拠向け Linter • 約90種類の標準ルールセット搭載 • フォーマッタはビルトイン detekt

    • コード品質の向上や潜在的なバグの検出向け Linter • 標準で302種類のルールセットを用意 • フォーマッタは拡張機能 Konsist • アーキテクチャ・宣言を検査可能な Linter • アーキテクチャ・設計の一貫性の準拠、コード品質の保証 • 標準ルールセットはないが柔軟な設定が可能
  16. Appendix • https://pinterest.github.io/ktlint/latest/ • https://github.com/pinterest/ktlint • https://github.com/diffplug/spotless/tree/main/plugin-gradle#quickstart • https://github.com/diffplug/spotless/issues/615 •

    https://detekt.dev/ • https://detekt.dev/marketplace/ • https://github.com/detekt/detekt • https://github.com/detekt/detekt/discussions/5997 • https://github.com/detekt/detekt-intellij-plugin • https://github.com/twitter/compose-rules • https://twitter.github.io/compose-rules/ • https://mrmans0n.github.io/compose-rules/ • https://github.com/mrmans0n/compose-rules/tree/main • https://docs.konsist.lemonappdev.com/ • https://github.com/DroidKaigi/conference-app-2022/tree/main • https://github.com/DroidKaigi/conference-app-2023/tree/main • https://speakerdeck.com/kgmyshin/kotlin-linter • https://en.wikipedia.org/wiki/Lint_(software)