項目管理和命名方式都是“規范”的問題,部分公司會書寫這方面的規范文檔,以保證大家寫出來的代碼符合同一規范。這里只討論常用的規范方式。
項目管理
項目管理這一塊,涉及到解決方案中的各個概念,“解決方案”、“項目”、“文件夾”、“文件”(含說明性文檔)。其中,解決方案包含項目,項目包含文件夾,文件夾包含文件。
解決方案 && 項目
一般來說一個解決方案是一個產品(網站、APP、桌面程序、類庫等等)。
“項目”是一個個.csproj
,最簡單的就是一個解決方案、一個項目,完成開發。但大家並不會這樣做,我們會把一個項目拆分成多個項目,在不同的項目中完成不同的功能,然后通過引用
的方式完成不同項目之間的“粘連”。
為什么要這樣做呢?一個原因是提高代碼的可讀性。比如最傳統的三層架構,視圖(eg.網站)是一個項目,業務邏輯(BLL)是一個項目,數據庫操縱(DAL)是一個項目。將不同的職責放到不同的項目中,管理、優化起來更加方便,代碼更加清晰。
另一個原因是,一個龐大的項目往往由多個開發組、多個開發者去開發和維護。將項目拆解成一個個獨立的項目(甚至獨立的解決方案),有利於多個開發者的工作。可能產品的部分功能由開發組A完成,另一部分功能由開發組B完成,而兩個開發組的代碼對對方來說都是不可見的。
所以“拆解”項目不要吝嗇,根據業務、邏輯,最大化的去拆分項目,對未來產品的功能拓展和代碼維護都有很大好處。
解決方案的命名一般和產品息息相關,比如Taobao、Wechat。而項目的命名,可以在解決方案的基礎上加一些“說明”,比如Wechat.Mobile、Wechat.Tool,添加的內容概況項目的定位。
剛開始如果沒有辦法去很好的組織項目,可以參考其他優秀的項目,github上面有很多優秀的開源的項目,他們的項目是怎么組織的,代碼是怎么寫的,都非常值得學習,比如:vscode、aspnetboilerplate、Newtonsoft.Json。多看高Star的項目多學習。
對於產品名字過長的問題,在命名時,可以采用“縮寫”。比如“aspnetboilerplate”,項目名都是“Abp.xxx.xxx”,用“Abp”代替了“aspnetboilerplate”。這都還不算很長的產品名稱,業務系統很多都是“XXXXX系統”, 比如我之前開發的“生態監測管理系統”,英文翻譯為“Ecological Monitoring Management System”,如果我們不進行縮寫,解決方案的名稱為“EcologicalMonitoringManagementSystem”,項目的名稱是“EcologicalMonitoringManagementSystem.EntityFramework”,類名為“EcologicalMonitoringManagementSystem.EntityFramework.EntityMapper.Devices.DeviceCfg” ——————————哇,這簡直是個災難!又臭又長。
所以我們要進行縮寫,將“Ecological Monitoring Management System”寫成“EMMS”。
文件夾 && 文件
一個項目中可以有文件夾、文件,那它們又是怎樣擺放的呢?我一般將程序的入口、配置的內容放在根目錄,把“同一類型”的文件放在同一文件夾下。
比如控制台程序中的Program.cs、ASP .NET Core中的appsettings.json、Startup.cs,都適合放在項目的根目錄。
同一類型、同一功能的內容,比如“完成發送短信的功能”、“定義產品表”,涉及的所有內容,可以放在同一文件夾中。
“定義產品表”的文件夾中,可以包含產品表的定義、產品表的MapperConfiguration、數據庫Configuration、Dto等等。
“完成發送短信的功能”,可以包含發送短信的接口、發送短信的實現(多個短信服務平台)、發送短信的統一方法(包含業務邏輯)等。可能還會有一些README文件,用來備注一些關於發送短信信息。
文件夾的命名肯定以“貼近”其中的內容為目標。文件夾的命名的單復數,可以根據內容來判斷:如果文件夾像一個工廠一樣,整體完成一個零件,則可以取這個零件名稱的單數形式作為文件夾的命名,比如“定義產品表”-Product;如果文件夾完成了同一目的的不同實現,則可以取復數,比如“完成發送短信的功能”-SendMessages。
一般一個.cs文件放一個類,類的命名為單數,且文件和類同名。有些開發喜歡把接口和實現類、類和它包含的枚舉值放在一起,是個人習慣問題,我個人不推薦這樣做。
一些同功能的類使用同樣的命名結尾,比如“XXXBuilder”、“XXXConfiguration”、“XXXHelper”。
這里我展示一些我開發的項目中的文件擺放。
類、變量、方法命名方式
我們先直觀感受下不同語言的命名方式:
java(來自Android開發之onClick事件的三種寫法)
package a.a;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class AActivity extends Activity {
/** Called when the activity is first created. */
EditText Ev1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Ev1 = (EditText)findViewById(R.id.editText1);
//第一種方式
Button Btn1 = (Button)findViewById(R.id.button1);//獲取按鈕資源
Btn1.setOnClickListener(new Button.OnClickListener(){//創建監聽
public void onClick(View v) {
String strTmp = "點擊Button01";
Ev1.setText(strTmp);
}
});
//第二種方式
Button Btn2 = (Button) findViewById(R.id.button2);//獲取按鈕資源
Btn2.setOnClickListener(listener);//設置監聽
}
Button.OnClickListener listener = new Button.OnClickListener(){//創建監聽對象
public void onClick(View v){
String strTmp="點擊Button02";
Ev1.setText(strTmp);
}
};
//第三種方式(Android1.6版本及以后的版本中提供了)
public void Btn3OnClick(View view){
String strTmp="點擊Button03";
Ev1.setText(strTmp);
}
}
python
import requests #導入requests包
import json
def get_translate_date(word=None):
url = 'url'
From_data={}
#請求表單數據
response = requests.post(url,data=From_data)
#將Json格式字符串轉字典
content = json.loads(response.text)
print(content)
#打印翻譯后的數據
#print(content['translateResult'][0][0]['tgt'])
if __name__=='__main__':
get_translate_date('......')
C#(來自在C#中,Json的序列化和反序列化的幾種方式總結)
Student stu = new Student()
{
ID = 1,
Name = "曹操",
Sex = "男",
Age = 1000
};
//序列化
DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(Student));
MemoryStream msObj = new MemoryStream();
//將序列化之后的Json格式數據寫入流中
js.WriteObject(msObj, stu);
msObj.Position = 0;
//從0這個位置開始讀取流中的數據
StreamReader sr = new StreamReader(msObj, Encoding.UTF8);
string json = sr.ReadToEnd();
sr.Close();
msObj.Close();
Console.WriteLine(json);
//反序列化
string toDes = json;
//string to = "{\"ID\":\"1\",\"Name\":\"曹操\",\"Sex\":\"男\",\"Age\":\"1230\"}";
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(toDes)))
{
DataContractJsonSerializer deseralizer = new DataContractJsonSerializer(typeof(Student));
Student model = (Student)deseralizer.ReadObject(ms);// //反序列化ReadObject
Console.WriteLine("ID=" + model.ID);
Console.WriteLine("Name=" + model.Name);
Console.WriteLine("Age=" + model.Age);
Console.WriteLine("Sex=" + model.Sex);
}
Console.ReadKey();
可以看出,不同的語言寫法差異很大,一方面是來自語法、格式本身不同,一方面是不同語言的開發者的命名規范不同。
C#的命名方式也有很多,這里我只描述我最常用的方式。
所有多單詞的連接,都使用駱駝命名法
。即"Get Your Information",變為"GetYourInformation"。
類中的屬性、方法名,以大寫字母開頭,字段以小寫字母開頭(一些開發喜歡以下划線開頭)。
接口以“I”開頭,比如“ISendMessage”。
命名方式,可以選擇一種自己覺得最舒適的規范,然后一直遵守它。
舉個例子:
public class StudentByINotifyPropertyChanged: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//實現INotifyPropertyChanged接口
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//私有字段小寫
private string sex;
private string name;
//公開屬性大寫
public string Sex
{
get { return sex; }
set
{
sex = value;
NotifyPropertyChanged("Sex");
}
}
public string Name
{
get { return name; }
set
{
name = value;
NotifyPropertyChanged("Name");
}
}
}
INotifyPropertyChanged
是接口,以“I”開頭。“StudentByINotifyPropertyChanged”這個名字不是太好,實際上這是“StudentViewModel”(MVVM相關概念)。
私有字段小寫開頭,公有屬性大寫開頭。如果將Name拆分為“姓”、“名”,則私有字段是“lastName”,“firstName”,公有屬性為“LastName”、“FirstName”。
有方法“獲得姓名”,則應該命名為“GetName”或者“GetFullName”。