1. 程式人生 > >How To Refactor A Public Interface

How To Refactor A Public Interface

When the team struggles to reuse a public function, it’s very common to hear this:

This public API is too hard to reuse, let's refactor it.

Before getting into why that statement is wrong, let's understand what "refactoring" means.

According to Martin Fowler, the act of refactoring is:

[…] to restructure software by applying a series of refactorings without changing
its observable behavior

Now, what's "observable behavior"? Fowler also has a definition of what that means:

[…] it means that the software still does what it did before

Well… still not very useful.

Ok, let’s look at some examples.

Imagine an existing public library to validate an Australian address in NodeJS. It receives an Object Literal

as an argument named input that contains the property value of type String representing the address to validate:

The simplified running code example of an Australian address validation function. The function is named “validate Australian address” which is called with an argument named “input”. The “input” is expected to be an "Object Literal" with the property “value” of type String.

After some time, you realize the API is confusing. You decide to change it to be called with a simple String as the argument which represents the address to validate.

This is the first step to change the public interface:

The diff for the first step change. The "input" has changed from accepting an "Object Literal" to accept a "String". The internal functions still accept an "Object Literal" with the property "value".

This is the second step to rename the input argument to address for the purpose of code clarity:

The diff for the second step change. The "input" of the public facing API has been renamed to "address" and passed through to the internal functions inside of an "Object Literal" with the property "value".

Here's the final running code:

The simplified running code example for the Australian address validation function with the first two steps applied.

The first step is NOT refactoring. The API is from a public library, which means changing the interface introduces an incompatible breaking change. It will change the observable behavior for consumers of the public library.

The second step IS refactoring. You're not changing any observable behavior, just renaming the argument.

Ok, let’s look at one more example from another perspective.

After the changes from before, you notice the internal functions are still using the old contract of accepting an Object Literal and a value property. Now you decide to change the interface for the internal functions.

This is the third step applied to 1 of the 2 internal functions:

The diff for the third step change. The "input" of the internal function to validate the suburb has changed from accepting an "Object Literal" with the property "value" to accept a single "String".

Here’s the running code with the third step applied:

The simplified running code example for the Australian address validation function with the third step applied.

From the point of view of the validate Australian Address function, the interface change for has Suburb is NOT refactoring. After all, the change requires the function validate Australian Address to modify how it calls the suburb validation.

From the point of view of the public consumers of the validate Australian Address function, the API change for has Suburb IS refactoring. After all, nothing has to change on their end.

Given that, you could also define refactoring like this:

Refactoring is to apply a series of small code change [1] steps [2] affecting the structure of the code without affectingthe observable behavior [3] for consumers [4].

[1]: The checkpoint to define when something has "changed" is after any command that can be used to apply a change: a commit, file save, git add, etc.

[2]: A step is small as long as it doesn't leave the application on a broken state (syntax error, failing test).

[3]: The "no change in behavior" aspect of refactoring is very important to validate the use of TDD. If the code was created using TDD, changes should make a test break, unless they’re refactoring. If a test doesn’t break when changing the code that represents behavior, then the code was not created using TDD.

Speaking of which, can you look at this JSFiddle example? You might find something interesting :)

[4]: Consumers of the code can be internal or external.

So going back to the initial statement:

This public API is too hard to reuse, let’s refactor it.

If the interface of the API is public and hard to use, then when you change it, it’s not gonna be refactoring. It’s gonna be a redesign.

This public API is too hard to reuse, let’s redesign it.

As I've written in 2016, due to Wittgenstein’s Beetle, it is possible that in a real conversation two individuals believe they are talking about the same “thing”, but in reality, they are talking about things that are totally different.

Refactoring is one example of that.

Only when you make a code change that doesn't modify behavior or the public interface between APIs that you can call refactoring. However, even if you change the interface, it may still be considered refactoring if the change is invisible.

Is it a refactoring or not?

As almost everything in software, there’s no simple response.

The answer depends on who's asking.

It just… depends.

相關推薦

How To Refactor A Public Interface

When the team struggles to reuse a public function, it’s very common to hear this:This public API is too hard to reuse, let's refactor it.Before getting in

How to Remove A Service Entry From Win10 Service List

console hot list warn oba tor div register ever .warnbanner { width: 600px; background-color: #FFEFCE } .warnbanner.border { border: 0px

WPF:How to display a Bitmap on Image control

bug con 另一個 spa and maps api 如果 reat 一個Bitmap文件,叫做screenShotFile, 你可以這樣顯示到Image控件上。 BitmapImage bi = new BitmapImage();

How to write a robust system level service - some key learning - 如何寫好一個健壯的系統級服務

set gic compute som com 服務 ant odin connect Scenario: Rewriting a quartz job service. Background: The existing service logic was hardcodi

【轉】How to initialize a two-dimensional array in Python?

use obj class amp example list tty address add 【wrong way:】 m=[[element] * numcols] * numrowsfor example: >>> m=[[‘a‘] *3] * 2&g

How to Have a Healthy Relationship --shanbei 為單身節寫

net stay represent lead ref uga pin first flow 我在扇貝發現一片好文。 Sometimes relationships can seem like a lot of work until you sit back and rea

How to force a log switch-強制切換日誌

適合 需要 nts art enable interval repeat sets sysdba 日誌切換通常是系統自動執行,不需要人為幹涉。但是在某些情況下,需要強制日誌切換,以下就幾種方法。 1、修改系統參數 The following initialization p

HOW TO BECOMING A FREELANCE ENGINEERING CONSULTANT.

Finding best freelance engineering consultant jobs If you happen to be a freelance engineering consultant looking for a new / better-paid job, you s

jquery ----> How to Create a Basic Plugin (翻譯)

app sed 設置 函數表 col 有變 動作 jquery對象 別名 http://learn.jquery.com/plugins/basic-plugin-creation/ 如何創建一個基本的插件 有時候你想在整個代碼中提供一些功能。 例如,也許你想要一個單一的方

How to Create a Perl Based Custom Monitor on NetScaler

serve 5.1 citrix prompt rst sym pri index web How to Create a Perl Based Custom Monitor on NetScaler https://support.citrix.com/article/C

How To Read A Paper

時間 記錄 文章 -s lar http split per 圖表 S. KeshavDavid R. Cheriton 科研工作者通常會花很多時間閱讀論文,然而研究者很少被閱讀技巧,浪費大量努力,作者在這篇文章裏介紹了他自己閱讀文獻的技巧,並可用來做文獻調研(litera

How to setup a slave for replication in 6 simple steps with Percona XtraBackup

second path binlog ica direct isam fetch owin value Data is, by far, the most valuable part of a system. Having a backup done systema

How to become a excellent programmer?

How to become a excellent programmer? Add comments to your code Do not complicate things Keep in Mind ----“Less is more” is not always

How To Order A New Tile Adhesive Manufacturing Plant

When placing tile within a bathroom or kitchen, you have got to use some form of adhesive. Among the more popular varieties of adhesive is mortar.

OpenPano: How to write a Panorama Stitcher

OpenPano: How to write a Panorama Stitcher This is a summary of the algorithms I used to write OpenPano: an open source panorama stitcher. You

如何使用KdTree進行搜尋(How to use a KdTree to search)

在本教程中,我們將詳細介紹如何使用KdTree來查詢特定點或位置的K個最近鄰居,然後我們將繼續介紹如何在使用者指定的半徑範圍內找到所有鄰居(在本例中為隨機) 。 #理論引入 kd樹或k維樹是電腦科學中用於在具有k維的空間中組織若干點的資料結構。這是一個二叉搜尋樹,其他約束條件是強加給

How to become a successful bug bounty hunter

如果你夢想成為賞金獵人,你的夢想就會成真 - 不要把你的名字變成“狗”或者在Mos Eisley酒吧面對Han Solo。 成為一個bug賞金獵人:一個有錢尋找軟體和網站漏洞的黑客。 任何具有計算機技能和高度好奇心的人都可以成為漏洞的成功者。 你開始時可以年輕或年老。 主要要求是你需要不斷學習。 此外,如果

How To Find A Fresh Tile Adhesive Manufacturing Plant

When placing tile in a bathroom or kitchen, you will have to use some form of adhesive. One of the more popular kinds of adhesive is mortar. There

RHEL7: How to configure a rc-local service

sys pts war pos ren def services The software 問題: linux7 /etc/rc.local 不生效: [root@bogon mysql3306]# uname -aLinux bogon 3.10.0-862.el7.x8

How to write a comparison and contrast essay?

The purpose of a compare and contrast essay is to analyze the differences and/or the similarities of two distinct subjects. A good compare/contr