談React框架難以維護的問題

這篇聊一下過去在寫React實作上遇到的問題,以及本篇重點為什麼難以維護。
以下:

  1. React如果選擇純Javascript,專案越大越難維護
  2. 維護的前人是高手,接手的人是新手
  3. 過度抽象的邏輯
  4. JSX不好了解全局
  5. 每個都元件,但不寫文件
  6. 過度封裝的巢狀元件
  7. 無固定寫法,套件選擇難以控制

1.React如果選擇純Javascript,專案越大越難維護

因為javascript本身就有很多雷坑
1.await、async
2.javascript reference的問題
3.函式參數型態不明確,比如不知道傳進來的參數是陣列、物件、物件屬性的內容又是什麼。因為大多數React專案都是直接原生Javascript,造成容易犯原生的錯。

1
const getOrderReceiptData({order}) => order?.detail?.receipt?.data

解決方法
請使用Typescript、ESLint可以避免。

2. 維護的前人是高手,接手的人是新手

因為React很自由,所以可能前人會ES6、React Hook、React Class、各種bind用法,並把它發揮的非常透徹。
這時接手的人必須每遇到一個就去查用法,直到補完所有用法才知道在寫什麼。

解決方法
限制Code統一寫法。且至少要兩人,不然好懂難懂只有寫的人知道。

3. 過度抽象的邏輯

1
2
3
const getData({pid,od,o}) => { 
//略 以下作一些複雜的pid、od、o的資料處理
}

添加一些自己覺得合理但其實超難讀的簡寫參數。
然後getData因為最後要取得data所以就抽象叫做getData,但不寫註解,讓人要盤完內容才能知道做什麼。一個還好,當A call B、B call C時,就會很可怕。

解決方法
解決方法:Typescript、ESLint。

4. JSX不好了解全局

因為需使用原生寫法造成三元運算子大量使用。
難以看懂原本畫面、動態變更後結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div>
{
<div>
A
</div>?
<span>
<div>
A
</div>?
<span>
B
</span>:
<div>
C
</div>
</span>:
<div>
C
</div>
}
</div>

解決方法
無解

5. 每個都元件,但不寫文件

封裝的套件又沒說明文件時。
一個套件外面傳入N個參數,前往實作看到1000行js,很可怕。
要改一個小東西,要重寫也無法,因為全部吃那一套。
寫React真的別閉門造車,特別是不寫說明文件的人,請去用開源套件謝謝…。

1
2
3
4
5
6
7
8
9
10
11
12
<CustomTable
data={data}
key={id}
isDeleted={checkedList}
...
/>
<Dn
isDeleted={checkedList}
/>
<RSpan
data={data}
/>

解決方法
寫說明文件、範例檔案

6. 過度封裝的巢狀元件

當你一直前往發現套件裡面還有更多套件,像是俄羅斯娃娃,而這些俄羅斯娃娃又拆的很散。
解決方法
無解,現行前端的通病。

7. 無固定寫法,套件選擇難以控制

React官方沒有固定範例寫法,只提供基本library,就是基礎ES6 JS去寫,所以每個人寫出的code都不一樣,如果又是新手剛學所寫的,一開始架構沒規劃好,後面就是建立一個歪掉的建築。
在套件依賴上也很多選擇,造成版本依賴性問題。
所以React…維護的專案會很可怕。
相比Vue,Vue官方做的很好,完整的範例可以參考,大家寫法也99%一致。

解決方法
無解。

結論

其實很多人鼓吹JQuery淘汰,都改去寫React是有問題的,因為React容易要改一個東西要讀前人的一串技術債,改法絕對沒JQuery輕鬆而且會改到很崩潰。
不是元件化了?那前提是元件化是合理的…當發現一些不合理參數傳進去、設計奇怪的元件、客製化又封裝…,如果你是接手的,JQuery還痛快些。

綜合上述,寫React會遇到上述的這些機率超高,所以難以維護,塊陶…。

那Vue呢?
Vue有官方完整應用範例,像人在看的HTML Template不像React的jsx,畫面好上手、包好的語法糖,後面接手的人都不會太有壓力。即使Vue是用js寫不是Typescript,因為他不用像React過度抽象化,很多官方語法糖都包好了。

然後如果是大專案,Typescript是必須的,否則你的js會在多人改來改去下炸鍋。

以上是個人體驗後的結論。

SQL Server 建立複合鍵(composite primary key)

在這篇簡易紀錄一下SQL複合鍵的做法。

1
2
3
4
5
6
7
8
9
CREATE TABLE Orders(
OrderNumber NVARCHAR(50),
OrderType TINYINT,
CreatedOn DATETIME,
UpdatedOn DATETIME,
IsValid BIT,
Remarks NVARCHAR(100) NULL
PRIMARY KEY (OrderNumber, OrderType)
)

就是在PRIMARY KEY加入兩個鍵值即可。
在此以OrderNumber、OrderType,表示同一訂單類型的編號不可重複。

如果是在SQL Server的介面設計上,就是點CTRL把需要設定的PK給匡列,之後再右鍵設定PK即可。

PostgreSQL get the start and end dates of prev month query

My table has below data, and I want to get the previous data of month,and today is 2022-05-04.

1
2
3
4
2022-03-01
2022-04-01
2022-04-01
2022-05-03

This is the answer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
WITH TEMP_TABLE AS
(
SELECT '2022-03-01'::TIMESTAMP WITHOUT TIME ZONE AS MYDATE
UNION ALL
SELECT '2022-04-01'::TIMESTAMP WITHOUT TIME ZONE AS MYDATE
UNION ALL
SELECT '2022-04-02'::TIMESTAMP WITHOUT TIME ZONE AS MYDATE
UNION ALL
SELECT '2022-05-03'::TIMESTAMP WITHOUT TIME ZONE AS MYDATE
)
SELECT
*
FROM
TEMP_TABLE TT
WHERE
TT.MYDATE >= DATE_TRUNC('MONTH',NOW()) - INTERVEL '1 MONTH'
AND TT.MYDATE < DATE_TRUNC('MONTH',NOW())

explain
The function DATE_TRUNC will help us convert datetime to first date of month.
It’s like Now() is 2022-05-09, and function DATE_TRUNC(‘MONTH’,NOW()) will convert datetime to 2022-05-01.I use the DATE_TRUNC create a duration.

Example:
NOW() = 2022-05-09

1
2
x >= 2022-04-01 
x < 2022-05-01

So,the result is 2022-04-01~2022-04-30.

SQL Server資料庫版控設定

前言

在寫程式時我們都會有版本控制,以避免重大失誤無法回版,而在程式上作法很簡單就是使用git。
但資料庫要怎版控呢?如果遇到有人直接把資料庫欄位異動了,卻沒通知其他人,程式就會變得難以除錯,所以在這回要介紹如何在資料庫加入版本控制功能。
在這篇範例會以SQL Server搭配Visual Studio去達成版控。

主要以微軟官方提供的:SQL Server Data Tools 來實作。

實作

1.因為要模擬真實情景,先以Visual Studio建立任一個沒版控的專案,在此先以ASP NET CORE MVC為範例。

2.對解決方案點右鍵,為這專案用的資料庫加入”資料庫版控專案”

3.選擇 SQL Server 資料庫專案,如果找不到這個專案記得去這裡裝:https://docs.microsoft.com/zh-tw/sql/ssdt/download-sql-server-data-tools-ssdt?view=sql-server-ver15
就可以出現這範例專案了。

4.我取名叫MyDatabase

5.這時就有一個MyDatabase的資料庫管理專案放進來了

6.再來我們現有的資料庫叫做TodoDB,預計把這DB加入版控

7.選擇匯入>資料庫

8.再來就連DB選擇指定資料庫

9.在此我就選擇資料庫連線、選擇指定資料庫

10.再來點選啟動

11.這樣就匯入完成

12.如此一來就可以版控了也可以設計資料庫

完成!

模擬資料庫欄位變更

1.再來我們模擬資料表變更,新增了一個Email欄位

2.對資料庫專案右鍵點”結構描述比較”

3.之後會跳出這視窗,右邊選擇你遠端的資料庫

4.在這我就選遠端的TodoDB

5.選好後點擊”比較”

6.點完後點擊更新,底下會顯示更新狀態,顯示已經順利完成

7.這時去SQL Server看就成功被更新了

下面是我做的完整專案:
https://github.com/yuhsiang237/SQL-Server-Version-Control

參考資料

2022上半年改變了什麼

在2022的上半年我做了很多大膽的改變與嘗試,包括從待業轉回職場,再從職場下班兼職第二份工作。居所也從高雄來到台北。

「追從自己內心的想法,相信自己。」是我這半年來最有感的,能夠從無化變成有,到最後實際改變現況,讓自己不再徬徨。

在工作上,蠻順利的,至於為什麼呢?
可能是之前2年以上的實務經驗累積,在這先感謝之前公司了。整體來講,做做測試、寫寫程式,釐清業務邏輯,就是日常。

那回家後能不能再幹點什麼,讓自己充實點?
於是我就去找了第二份工作,當一下程式家教。在教人這方面,在大學時就有當過TA經驗,所以算順順的過了,總共教了2個月左右。

而在生活面就是自給自足了,自己三餐自煮,如果勉強來講,也算半個廚師了。在台北如果自己煮能少很多開銷,也比較能管控吃進去的食物。

而旅遊,因為疫情關係一隻手數的出來,就不談了。

整體上算是愜意的生活,但卻還是有不滿足的點就是「成就感」。因為過的很踏實,以致自己畏懼發夢,「夢」往往都是很難達成的事,因為怕失敗,而不敢豪賭。因此,我的2022年下半場將會嘗試這個心臟的能耐,我就敢作夢。

SQL Server 使用GUID當作PK範例

使用GUID需要將型別設定為uniqueidentifier。預設值通常會為NEWID(),即從資料庫生成時自動產生GUID帶入。

1.建立Table

1
2
3
4
5
CREATE TABLE Users (
[GUID] uniqueidentifier NOT NULL DEFAULT NEWID(),
[Name] NVARCHAR(50) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([GUID] ASC)
);

2.再來新增資料

1
2
3
4
5
6
7
INSERT INTO Users
(
[Name]
)
VALUES
('MC HOTDOG'),
('張震嶽')

3.查詢

1
SELECT * FROM Users

結果:

1
2
3
GUID	Name
FB5AFFC7-0802-47F7-AFB3-531BC83B6C26 張震嶽
F8122471-70AE-43C5-9C40-A65ED54FACD5 MC HOTDOG

總結

使用GUID優點:
1.不會讓資料庫造成依賴ex:產生唯一識別碼
2.不用擔心鍵值重複(機率極低)ex:不同時間產的多資料表合成一張資料表
3.不好被猜測ex:F8122471-70AE-43C5-9C40-A65ED54FACD5
缺點:
1.空間使用GUID 16Bytes比整數的4Bytes多。
2.效能(待釐清,似乎眾說紛紜)

參考資料

PostgreSQL INSERT INTO MULTIPLE

前言

在SQL有時需要手動建立測資,但又不想逐行insert into時可以使用。

語法:

1
2
3
4
5
6
INSERT INTO table_name (column_list)
VALUES
(value_list_1),
(value_list_2),
...
(value_list_n);

舉例:

1
2
3
4
5
6
7
8
INSERT INTO USER
(
NAME,
BIRTHDAY
)
VALUES
('胖虎','1993-1-1'),
('小夫','1993-2-1')

C# 文字組合的4種方式

前言

在此紀錄C#中常見的組字串方式。

實作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

namespace StringSol
{
internal class Program
{
static void Main(string[] args)
{
var name = "Yu Hsiang";
string str1 = "你好" + name;
string str2 = String.Concat("你好", name);
string str3 = String.Format("你好{0}", name);
// $是c# 6.0 的語言特性,功能類似string.format()
string str4 = $"你好{name}";

Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3);
Console.WriteLine(str4);
}
}
}

輸出結果:

1
2
3
4
你好Yu Hsiang
你好Yu Hsiang
你好Yu Hsiang
你好Yu Hsiang

C# LINQ GroupBy用法

前言

最近很常使用GroupBy去處理資料,因此稍作整理。
GroupBy主要用來分組,以”群”、”組”有關的都可以使用他。

實作

目標:使用GroupBy將每個班級的人數列出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Collections.Generic;
using System.Linq;

namespace linq_groupby
{
internal class Program
{
public class Student
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }

/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }

/// <summary>
/// 教室
/// </summary>
public char Classroom { get; set; }
}

static void Main(string[] args)
{
var students = new List<Student>
{
new Student {Id = 1, Name = "大雄",Classroom = 'A'},
new Student {Id = 2, Name = "多拉A夢",Classroom = 'B'},
new Student {Id = 3, Name = "胖虎",Classroom = 'A'},
};
var classRoomGroup = students
.GroupBy(x => x.Classroom)
.Select(x => new
{
ClassRoom = x.Key,
StudentCount = x.Count(),
}).ToList();

foreach (var item in classRoomGroup)
{
Console.WriteLine($"Classroom:{item.ClassRoom} - StudentCount:{item.StudentCount}");
}
}
}
}

輸出結果:

1
2
Classroom:A - StudentCount:2
Classroom:B - StudentCount:1

A班級2人,B班級1人。

總結

使用LINQ GroupBy能夠節省建立資料結構如字典、HashSet等,直接去做分組統計。

SQL Server PARTITION BY 分割分組語法

前言

最近處理到一些複雜需求,使用到了PARTITION BY。
於是記錄一下PARTITION BY的用法。
主要是能在分組時取得第一筆資料、與分組有關的操作。

PARTITION BY

Divides the query result set into partitions. The window function is applied to each partition separately and computation restarts for each partition.

PARTITION BY 可將查詢結果集分成幾個資料分割。

語法:

1
OVER ( [ PARTITION BY value_expression ] [ order_by_clause ] )  

實作

目標:要取得每個以UserId分組的第一筆資料

資料表:[DBO].[TODOS]

首先先使用PARTITION製造出分割出群組編號

1
2
3
4
5
SELECT 
ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY ID) ROW_ID,
*
FROM
[DBO].[TODOS]

可以見到ROW_ID出現在列表中,即代表這是這個UserId組的第幾筆資料。
依序為:
UserId為1的第1筆資料
UserId為3的第1筆資料
UserId為3的第2筆資料
UserId為3的第3筆資料
UserId為4的第1筆資料
UserId為5的第1筆資料

再來只要把這結果集外部包一個搜尋,使用條件就能拿到第一筆資料,如下設定:
ROW_ID為1代表取得每個分組的第一筆資料。

1
2
3
4
5
6
7
8
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY ID) ROW_ID,
*
FROM
[DBO].[TODOS]
) TEMP
WHERE TEMP.ROW_ID = 1

最終成功拿到每個UserId分組的第一筆資料

參考資料