Slide 1

Slide 1 text

Refactoring Domain Objects with Scalafix 2023/04/15 ScalaMatsuri 2023 - Day1 Naoki Aoyama / @aoiroaoino

Slide 2

Slide 2 text

❖ Naoki Aoyama ❖ Twitter/GitHub: @aoiroaoino ❖ Working at: $ whoami

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Agenda ❖ Introduction ❖ What / Why using Scalafix? ❖ Case studies ➢ Leakage of behavior through the copy method ➢ Merging inherited class and typed patterns ❖ How to refactoring with Scalafix ❖ Conclusion アジェンダ。Scalafix を使うモチベーション、事例、実際にリファクタリングを行 う際のコツなどをお話しします。

Slide 5

Slide 5 text

> Introduction

Slide 6

Slide 6 text

Challenge in modifying domain object ドメインモデルを表現し、ビジネスルールが実装されたアプリケーションの中 心とも言えるのがドメイン層やユースケース層です。 Entities Use Cases

Slide 7

Slide 7 text

Challenge in modifying domain object Entities Use Cases ただし、中心であるが故に様々なレイヤーから依存され、利用されるため、 ちょっとした修正でも広範囲に影響が出る可能性があります

Slide 8

Slide 8 text

Challenge in modifying domain object We’re developing using DDD. Several years have passed since the release, and domain objects are being reviewed and modified. The domain layer code is used from many places. A single modification often affects dozens to hundreds of places. However, we cannot stop making modifications just because they have a wide scope of impact. 弊社のアプリケーションも例外ではありません。しかし、影響範囲が広いから といって修正の手を止める訳にはいきません。

Slide 9

Slide 9 text

Challenge in modifying domain object It is always important to maintain code quality through refactoring of domain objects. We want tools that can give warnings through static analysis and perform safe and quick rewrites. いつだってドメインオブジェクトのリファクタリングを通してコードの品質を保つ ことが重要です。素早く安全に行えるようにしたい。

Slide 10

Slide 10 text

> What / Why using Scalafix?

Slide 11

Slide 11 text

Scalafix はリファクタリング&静的解析ツールです。公式が提供する ルール以外にも、ユーザー独自のルールも実装できます。 What / Why using Scalafix? Scalafix はリファクタリング&静的解析ツール。

Slide 12

Slide 12 text

What / Why using Scalafix? ❖ I often see discussions about adding or creating custom rules for Linting functionality, whether provided by official or third-party sources. ❖ Regarding Refactoring functionality, I often see discussions about providing migration tools for library-side changes that are incompatible. => Today, the main topic is writing disposable rules for Refactoring. 静的解析ルールやライブラリのマイグレに関する話題も多いですが、今日は 特にリファクタリング機能に注目します。

Slide 13

Slide 13 text

What / Why using Scalafix? IDE's refactoring feature is very capable. ❖ It's incredibly convenient to work with just mouse clicks or keyboard shortcuts without having to write any code. ❖ On the other hand, it can't handle corner cases that involve complex conditions. Using scripting languages to apply methods such as regular expressions or string replacement is also convenient. ❖ Bulk replacement for specific patterns is very powerful. ❖ However, there is a risk of incorrect rewriting due to the inability to interpret the semantics. IDE のリファクタリング機能は優秀だが複雑なケースには対応できない。文字 列置換は強力だが意味論を解釈できず誤った書き換えが不安。

Slide 14

Slide 14 text

What / Why using Scalafix? ❖ Matching for the rewriting target can be done against the abstract syntax tree provided by Scalameta. ❖ With sbt plugins, it is possible to integrate seamlessly with the build tool. ❖ The convenience of Patch objects that integrate refactoring and static analysis result notification. Scalafix は書き換え対象のマッチングを AST に対して行う。sbt とのシーム レスな連携、Patch オブジェクトの使いやすさ。

Slide 15

Slide 15 text

What / Why using Scalafix? コード例 case 節で対象となる AST をマッチさせて Patch オブジェクトを返す

Slide 16

Slide 16 text

What / Why using Scalafix? コード例 case 節で対象となる AST をマッチさせて Patch オブジェクトを返す

Slide 17

Slide 17 text

What / Why using Scalafix? コード例 case 節で対象となる AST をマッチさせて Patch オブジェクトを返す

Slide 18

Slide 18 text

What / Why using Scalafix? Scalafix is suitable for refactoring domain layers including domain objects. ❖ Manually rewriting many places carries the risk of degradation or omissions and should be avoided. ❖ In reality, knowledge of domain objects tends to leak out and become boilerplate code. ❖ Since it is widely used, writing rules and performing bulk replacements is cost-effective. Scalafix はドメインオブジェクトのリファクタリングと相性がよい。構文(意味論) での絞り込みによる安心安全、一括置換のコスパなど。

Slide 19

Slide 19 text

> Case studies

Slide 20

Slide 20 text

>> 1. Leakage of behavior through the copy method

Slide 21

Slide 21 text

1. Leakage of behavior through the copy method ケースクラスで実装されたドメインオブジェクト。複数フィールドを一つにまとめ た新しいドメインオブジェクトにまとめる必要が出てきた。

Slide 22

Slide 22 text

1. Leakage of behavior through the copy method copy メソッドも変更する必要がある。この変更をコンパイルとテストが通るよ う一括で行うのは難しい。

Slide 23

Slide 23 text

1. Leakage of behavior through the copy method まずは手順を検討。二段階に分けてリファクタリングすることにした。 deprecatedCopy を追加し、一括で対象の copy メソッドをリネーム。

Slide 24

Slide 24 text

1. Leakage of behavior through the copy method 追加された deprecatedCopy へ、一括で対象となる旧シグネチャの copy メ ソッドをリネーム。

Slide 25

Slide 25 text

1. Leakage of behavior through the copy method deprecatedCopy に置き換える自作ルール。SemanticRule を用いてレシー バの型を特定し、対象の copy メソッドを確実に判定している。

Slide 26

Slide 26 text

1. Leakage of behavior through the copy method Foo クラスのフィールド修正後、deprecatedCopy から新シグネチャの copy へマイグレーション。

Slide 27

Slide 27 text

1. Leakage of behavior through the copy method deprecatedCopy を書き換える自作ルール。引数からドメインオブジェクトを 生成しつつ、新シグネチャの copy メソッドに書き換える。

Slide 28

Slide 28 text

1. Leakage of behavior through the copy method 結果的に after のコードへ修正することができた。

Slide 29

Slide 29 text

1. Leakage of behavior through the copy method おおよそ変更されたファイル数と行数。数十行の自作ルールからこれだけの 変更が行えるのはとても効率的で気持ちがいい。

Slide 30

Slide 30 text

1. Leakage of behavior through the copy method ➔ It feels good that so many changes can be made from just a few dozen lines of custom rules, including some manual changes. ➔ Refactoring while maintaining a state where compilation and testing are successful can be quite challenging. ➔ If possible, let's keep the copy method private. 😂 コンパイル/テストが成功する状態を維持しつつ書き換えるのはなかなか大 変。できれば copy メソッドは隠そう。

Slide 31

Slide 31 text

>> 2. Merging inherited class and typed patterns

Slide 32

Slide 32 text

2. Merging inherited class and typed patterns FooItem, BarItem は Item の子クラスで、それぞれ異なる振る舞いを持って いたがドメインモデルの変更に伴い Item に統合されることに。 abstract class Item class BarItem class FooItem

Slide 33

Slide 33 text

2. Merging inherited class and typed patterns まずは手順を検討し Item を具象クラスにすることを目標とした。FooItem, BarItem が持つメソッドを Item へ移動し単なるデータ型に。

Slide 34

Slide 34 text

2. Merging inherited class and typed patterns 単なる型エイリアスに変更したので、このままでは Item クラスをパターンマッ チし Typed pattern で分岐していた箇所が壊れてしまう。

Slide 35

Slide 35 text

2. Merging inherited class and typed patterns アイディア勝負? FooItem, BarItem オブジェクトを作り unapply メソッドを追 加。Extractor pattern に書き換えた。

Slide 36

Slide 36 text

2. Merging inherited class and typed patterns 対象の Typed pattern を Extractor pattern に書き換える自作ルール。この ままでは再び Typed pattern が追加されてしまう可能性が残る。

Slide 37

Slide 37 text

2. Merging inherited class and typed patterns Patch.replaceTree を Patch.lint に書き換え、対象だったコードが今後追加 されたらエラーにするようなルールとして追加した。

Slide 38

Slide 38 text

2. Merging inherited class and typed patterns ➔ The code that was originally written and discarded became a rule for Lint as is. ➔ We added background information and reference links to the error messages to guide users. ➔ It is one of my favorite examples in this project. 😆 Patch オブジェクトが上手く抽象化されてるおかげで実現。書き捨てコードが そのまま Lint ルールに。お気に入りのケース。

Slide 39

Slide 39 text

> How to refactoring with Scalafix

Slide 40

Slide 40 text

How to refactoring with Scalafix ❖ Imagine the final completed code. ❖ Imagining patterns becomes easier by manually rewriting the code once. ❖ Deepen your understanding of the AST. Tools like explorer or scalameta-ast are useful. ➢ https://astexplorer.net/ ➢ https://xuwei-k.github.io/scalameta-ast/ リファクタリング後の最終系をイメージする。一箇所でも手で書き換えると対 象範囲やパターンが掴みやすい。AST の理解も深めよう。

Slide 41

Slide 41 text

How to refactoring with Scalafix ❖ Plan the order of rewrites carefully. ❖ Always maintain a state where compilation and testing are successful. ❖ Efficient progress depends on how many targets for bulk changes can be created. 最終系に至るまでの手順を検討する。各ステップで常にコンパイル/テスト可 能を維持。どうしたらより多く一括書き換えできるかのパズル。

Slide 42

Slide 42 text

How to refactoring with Scalafix ❖ Keep custom rules for rewriting simple. ❖ Avoid complex rewrites and break them down into steps. ❖ It is important to make the rules themselves easy to review. ルールはできるだけ簡素にし、煩雑な条件でのマッチや複雑な書き換えは手 順を分けるなどして避ける。ルール自体もレビューしやすくする。

Slide 43

Slide 43 text

> Conclusion

Slide 44

Slide 44 text

Conclusion ❖ Scalafix is a highly suitable tool for refactoring domain objects. ❖ Introduced an example of using Scalafix for refactoring domain objects. ❖ Writing custom rules on the fly is convenient for refactoring. ❖ The learning curve is not cheap, but it is an incredibly useful tool for maintaining Scala applications. 弊社でのリファクタリング事例を紹介し、上手く進めるための Tips をまとめ た。Scalafix は最高のツールなので積極的に活用しましょう。