12月 18, 2019 Programming
### Config File

設計 Config File 在寫程式時是一個必定會出現的事情,在 Javascript 的世界裏我們可以使用 JSON 檔案來儲存系統的 Config。而在使用 JSON 時又一定會使用到 Tree 的方法來儲存資料。看看以下的例子 `Config.json` : 

```json
{
	"app":{
		"port":80,
		"db":{
			"host":"db.abc.com",
			"port":3306,
			"user":"myuser",
			"password":"mypassword",
			"database":"myproject"
		}
	}
}
```

大概有 80% 的系統都會有以下的設定了,最基本的 Database 連線設定檔。

當我們要使用參數時,可以直接匯入要 JSON 檔案然後經 Object 存取資料。

```js
import Config from 'Config.json';

// connect to db
const connectDB = () => {
	
	var host = Config.app.db.host || 'default host name';
	var port = Config.app.db.port || 3306;
	var user = Config.app.db.user || 'default user';
	var password = Config.app.db.password || 'default password';
	var database = Config.app.db.database || 'default database';
};
```

以上的方法可以把資料從 Config 中讀取出來,還可以設定他們的預設值。但是有一個問題,就是如果 Config 的路徑內有其中一個環節斷掉,程式就會 throw error。例如 : 

```js
// config
const Config = {
	"port":80,
	"db":{
		"host":"db.abc.com",
		"port":3306,
		"user":"myuser",
		"password":"mypassword",
		"database":"myproject"
	}
}

// connect db
const connectDB = () => {
	
	var host = Config.app.db.host || 'default host name';
	var port = Config.app.db.port || 3306;
	var user = Config.app.db.user || 'default user';
	var password = Config.app.db.password || 'default password';
	var database = Config.app.db.database || 'default database';	
};
```

因為 Config 中沒有 app 這個屬性存在,所以當運行到 assign host 那句時,就會 throw error 了 !!!

### 解決方法

要解決問題,可以加入檢查就可以了 :

```js
// check every node of config path
var host = (Config && Config.app && Config.app.db && Config.app.db.host? Config.app.db.host: undefined);
```

以上方法可以確保萬無一失,不過又好像寫得太長 !!

### Configuration File 平整化

平整化就是把一個立體的 model 變成為一個單純的 array。我們可以通過 Database First Normalization Form 來達成目的。以下為例 :

```json
{
	"app":{
		"port":80,
		"db":{
			"host":"db.abc.com",
			"port":3306,
			"user":"myuser",
			"password":"mypassword",
			"database":"myproject"
		}
	}
}
```

平整化後可以變成為 :

```json
{
	"app":{
		"port":80,
		"db":{
			"host":"db.abc.com",
			"port":3306,
			"user":"myuser",
			"password":"mypassword",
			"database":"myproject"
		}
	},
	"app.port":80,
	"app.db":{
		"host":"db.abc.com",
		"port":3306,
		"user":"myuser",
		"password":"mypassword",
		"database":"myproject"
	},
	"app.db.host":"db.abc.com",
	"app.db.port":3306,
	"app.db.user":"myuser",
	"app.db.password":"mypassword",
	"app.db.database":"myproject"
}
```

處理好後像 Config 的 Route 檔案,一個 KEY 可以對應到一個 VALUE。在使用上便簡單得多了。

```js
import Config from 'Config.json';

// connect to db
const connectDB = () => {
	
	var host = Config['app.db.host'] || 'default host name';
	var port = Config['app.db.port'] || 3306;
	var user = Config['app.db.user'] || 'default user';
	var password = Config['app.db.password'] || 'default password';
	var database = Config['app.db.database'] || 'default database';
};
```

這樣就算其中的一層參數繼掉了,也不會 throw error,而是回傳 `undefined`。

### 如何實作平整化

由於 Config 是一種不轉變的資料,所以我們在 Build 時可以使用 Script 產生 Config 檔案。另一個方法是在 Runtime 是進行。而當然前者的效能會較為好,而後者就有更大的彈性。

```js
import Config from 'config';

/**
 * flat config
 */
const flatConfig = (config, path) => {

	// result
	var result = {};

	// init config
	config = config || Config;

	// init path
	path = path || 'Config.';

	// each config attribute
	for( var i in config ) {

		result[path + i] = config[i];

		if( typeof config[i] === 'object' ) {

			result = { 

				...result, 

				...flatConfig(config[i], path + i + '.')
			};
		}
	}

	// return
	return result;
};

/**
 * read config attribute
 */
const readConfig = path => {

	// get config
	var config = flatConfig();

	// return
	return config[path];
};

// get host
var host = readConfig('Config.app.db.host');
```

上面使用了 Recursion 的方法來處理整個 tree model。大家可以使用自己的方法來實作也可以的喔 !
過去文章
2025 (9)
4 (5)
3 (1)
2 (3)
2024 (25)
11 (3)
10 (3)
9 (1)
3 (18)
2022 (6)
10 (1)
6 (2)
5 (1)
3 (1)
1 (1)
2021 (21)
11 (7)
7 (1)
6 (2)
5 (2)
4 (6)
3 (2)
2 (1)
2020 (92)
12 (1)
11 (2)
10 (4)
9 (10)
8 (5)
7 (1)
6 (3)
5 (1)
4 (4)
3 (25)
2 (7)
1 (29)
2019 (57)
12 (25)
11 (7)
9 (25)