1. 程式人生 > >第1篇-如何編寫一個面試時能拿的出手的開源專案?

第1篇-如何編寫一個面試時能拿的出手的開源專案?

編寫一個不錯的開源專案至少有3個好處:

(1)練技術,長經驗

(2)面試時展現自己的Coding能力

(3)獲取成就感

練技術,長經驗是最實在的,不過如果自己有一個好的開源專案,還可以在開源中國或github上開源,讓更多人受益,也許能獲得許多的Star,讓自已獲得滿足,激勵自己完善專案功能。在面試時,也可以在簡歷顯眼的位置給出開源專案名稱和Git地址。面試官一般都會去檢視,這是程式設計師實力的最好見證,是自己Coding能力的最好見證。所以如果要編寫一個面試時拿的出手的專案,首先需要做到“規範”,下面談一下我眼中規範的開源專案。

1 專案規範

1.1 規範編寫README.md

README.md檔案是一個專案的入門手冊,裡面介紹了整個專案的使用、功能等等。所以README檔案寫得好不好,關係到這個專案能不能更容易的被其他人瞭解和使用。

首先最起碼要做到的就是格式要清晰,讓人一眼能看出層次感,例如分幾個大標題對專案進行介紹,最簡單的就是分為如下的4部分:

  • 專案名及簡介:簡單介紹一下這個專案是做什麼的。有的話最好加上demo地址;
  • 功能:你這個專案可以實現的功能;
  • 用法:這可以說是最重要的,一定要讓別人看得懂你這專案是怎麼使用的;
  • 其他:作者或者是維護人列表、版權、鳴謝、貢獻、logo、聯絡方式等等,這些有的話當然會更加高大上。
讓面試官能在最短的時間內瞭解專案才是最重要的,所以簡介要簡短,三言二語就把專案要做的事兒交待清楚。這樣面試官才會想更多的瞭解這個專案,例如使用了什麼技術呀、具體原始碼的書寫邏輯呀等等。 

1.2 使用版本管理工具

最好使用版本管理工具,而且建議使用Git,並且是2個或多個人參與開發最好。許多面試官看到一個專案時通常都會問“這個專案是幾個人開發的?”,除了瞭解專案分工的細節,也能體現團隊合作的精神。另外在使用版本管理時,commit程式碼時一定要認真書寫簡短的描述,描述此次開發了什麼功能或修復了什麼Bug等,不能敷衍了事,這是一種習慣,會讓自己以後受益。 

1.3 好的程式碼書寫習慣

許多面試官司也會看具體的專案實現,所以專案模組劃分要清晰,模組名稱要見名之意,具體的程式碼書寫要規範,現在許多大公司都有自己的程式碼規範,我們可以好好學一下阿里的Java程式碼規範。 

1.4 有完整的測試用例

這也是最容易被忽視的,但是卻是保證專案功能正確最不可或缺的一部分。專案簡單還好說,如果專案稍等複雜一點,沒有測試用例保證的專案很容易出問題。試想一下,假如我們修復了一個系統Bug,但是沒有為此Bug新增測試用例,那麼下一個人在修復其它Bug時,很可能會破壞之前修復Bug的程式碼邏輯,導致一個Bug的修復引入了另外的Bug。所以要針對程式碼重要功能及相關Bug有完整的測試用例,必要時還要新增詳細的註釋。 

2 Javac AST View外掛的開發  

下面博主打算寫一個系列的博文,從零編寫一個“規範”的開源專案,好在以後面試中更多的展現自己的實力。今天先簡單介紹一下這個專案,並且為這個專案做一些準備工作。

2.1 專案介紹

開發一個類似Eclipse AST View的外掛,安裝的過程見如下博文: 

https://www.cnblogs.com/nettee/p/4463841.html

這個外掛的詳細使用說明的連結如下:

https://www.eclipse.org/jdt/ui/astview/

安裝後就可以直觀地檢視抽象語法樹了,舉個例子,如下:

package com.compiler;

import java.util.List;

public class C {
  public void test(List<String> list){
	list.add("a");
  }
}

語法樹如下:

不過這個外掛顯示的是基於Eclipse JDT中的增量式編譯器ECJ的抽象語法樹,而我們經常使用的OpenJDK中的Javac編譯器的抽象語法樹與ECJ的抽象語法樹並不相同,不過絕大多數的語法樹節點劃分是一樣的,但是有少量的節點劃分不一樣,我打算開發一個類似Eclipse AST View的外掛,用來顯示Javac編譯器的抽象語法樹。 

2.2 專案知識儲備 

開發這樣的外掛需要了解JDT編譯器和Javac編譯器的抽象語法樹,同時還需要掌握Eclipse下的外掛開發,參考的相關資源如下:

第一本就是《Eclipse外掛開發學習筆記》,開發Eclipse外掛必須要有外掛開發相關基礎,這本書發版時間很早,但是外掛開發的基本思想是不會變的。另外官方的Eclipse API也是開發中必不可少的資料。

  有了外掛開發基礎後就需要了解OpenJDK的Javac編譯器和Eclipse JDT中的增量式編譯器ECJ了,重點就是了解這兩個編譯器對抽象語法樹節點的表示。對Javac編譯器來說,還需要了解從Java原始碼解析為抽象語法樹的過程,參考的資料為《深入解析Java編譯器:原始碼剖析與例項詳解》。  

Eclipse JDT中的增量式編譯器ECJ的抽象語法樹可以通過博文Eclipse AST抽象語法樹API來了解,沒有相關的書籍。不過由於是在Eclipse中開發外掛,所以直接呼叫Eclipse相關API來獲取抽象語法樹就可以了,不需要自已編寫Java原始碼轉換為抽象語法樹的程式碼實現。所以Eclipse AST View整個專案的實現也相對簡單。 

把Eclipse AST View專案的原始碼匯入到Eclipse中,這樣就可以通過閱讀、除錯的方式來學習這個外掛了,然後參考這個外掛來寫我自己的Javac AST View外掛。專案原始碼結構如下:

不得不說,閱讀別人的程式碼也是學習的最好方式之一。 

2.3 編寫專案框架 

編寫的外掛中主要使用了樹外掛,JFace為樹控制元件提供了檢視器Viewer。在檢視器框架中,將模型稱為輸入,檢視器本身充當控制器的角色,而樹控制元件本身作為檢視,當輸入改變時,檢視器負責相應地改變控制元件的內容。

檢視器框架主要由以下幾部分構成。

(1)模型和元素-儲存著要顯示在控制元件中的資料模型,我們編寫的抽象語法樹節點模型如下:

package astview;

import java.util.ArrayList;
import java.util.List;

public class JavacASTNode {
	private int id;
	private String name;
	private List<JavacASTNode> children;
	private JavacASTNode parent = null;

	public JavacASTNode() {
		children = new ArrayList<JavacASTNode>();
	}

	public List<JavacASTNode> getChildren() {
		return children;
	}

	public void setChildren(List<JavacASTNode> children) {
		this.children = children;
	}

	public JavacASTNode getParent() {
		return parent;
	}

	public void setParent(JavacASTNode parent) {
		this.parent = parent;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String toString() {
		return name;
	}
}

(2)內容提供者和標籤提供者-負責將資料模型轉化成可以顯示的圖片和文字。我編寫的內容提供者如下:

class ViewContentProvider extends ArrayContentProvider implements ITreeContentProvider {

	public Object[] getChildren(Object parentElement) {
		JavacASTNode node = (JavacASTNode) parentElement;
		return node.getChildren().toArray();
	}

	public Object getParent(Object element) {
		JavacASTNode node = (JavacASTNode) element;
		return node.getParent();
	}

	public boolean hasChildren(Object element) {
		JavacASTNode node = (JavacASTNode) element;
		return node.getChildren().size() > 0 ? true : false;
	}

	public Object[] getElements(Object inputElement) {
		JavacASTNode compilatinUnitNode = new JavacASTNode();
		compilatinUnitNode.setId(001);
		compilatinUnitNode.setName("JCCompilationUnit");
		
		JavacASTNode importNode = new JavacASTNode();
		importNode.setId(002);
		importNode.setName("JCImport");
		
		JavacASTNode classNode = new JavacASTNode();
		classNode.setId(003);
		classNode.setName("JCClassDecl");

		compilatinUnitNode.getChildren().add(importNode);
		compilatinUnitNode.getChildren().add(classNode);
		importNode.setParent(compilatinUnitNode);
		classNode.setParent(compilatinUnitNode);
		
		return new JavacASTNode[] {compilatinUnitNode};
	}

}

這個類是JavacTreeViewer的內部類。我們只簡單寫了一些測試用的資料,其實這些資料都是要從Javac編譯器中讀取的,而Javac編譯器分析的Java原始碼又需要從當前啟用的編輯器中獲取,後面我會不斷完善更新這些功能。  

編寫的標籤提供者如下: 

class ViewLabelProvider extends LabelProvider {
	public Image getColumnImage(Object element) {
		return null;
	}

	public String getColumnText(Object element) {
		return ((JavacASTNode) element).toString();
	}
}

這個類也同樣是JavacTreeViewer的內部類。  

(3)控制元件,用來顯示內容,這裡用到的為樹控制元件TreeViewer

(4)檢視器

模型和元素以及內容提供者和標籤提供者需要自己編寫,控制元件和檢視器不需要開發者自己編寫。

編寫JavacTreeViewer類,如下: 

package astview;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;


public class JavacASTViewer extends ViewPart {
	public static final String ID = "javacastviewer";
	
	private TreeViewer viewer;

	public void createPartControl(Composite parent) {
		viewer = new TreeViewer(parent, SWT.SINGLE);
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setInput(getSite());
	}

	public void setFocus() {
		// not supported
	}
        ...
}

最後執行後,檢視JavacTreeViewer檢視,顯示效果如下:

最後就是上傳到github了,我的github倉庫地址為:

https://github.com/mazhimazh/JavacASTViewer

接下來我會不斷開發完善這個專案,如果各位能給個“Star”是最好了,你的支援是我繼續開發的最大動力。