Results Team Project Summary

Members: Linyue Ling (3218005082), Luo Yi-ming (3118005066)

1, GitHub Address : https://github.com/HandsomeLuoYM/examination-system


2, PSP form

PSP2.1 Personal Software Process Stages Estimated time consuming (minutes) The actual time-consuming (minutes)
Planning plan 60 45
- Estimate Estimate how much time this task requires 60 45
Development Develop 1720 1700
- Analysis Needs analysis (including learning new technologies) 80 60
- Design Spec Generate design documents 30 20
- Design Review Design review (and colleagues reviewed the design documents) 30 20
- Coding Standard Code specifications (development of appropriate norms for the current development) 20 30
- Design Specific design 180 120
- Coding Specific coding 1200 1300
- Code Review Code Review 60 45
- Test Test (self-test, modify the code, submit modifications) 120 105
Reporting report 120 110
- Test Report testing report 60 40
- Size Measurement Computing workload 30 20
- Postmortem & Process Improvement Plan Later summarized, and process improvement plan 30 50
total 1900 1855

3, performance analysis

When I randomly generated 10000 expression: You can see that the heap memory consumption stabilized after rising

Seen, in the high efficiency Class Operator monitoring and CUP utilization is not high, but the memory consumption for a short time to achieve a high

It charged seen from the following report, since a large number of calculations of addition, subtraction of the string, so as to reduce the burden of the virtual machine, we use StringBuilder string manipulation to most


4, design and implementation process


Programming language is first determined, in order to reduce the cost of learning, using familiar Java related development, demand and proofreading involves randomly generated, it requires a lot of operating string, it is used to perform a corresponding operation StringBuilder improve system speed, Secondly, also relates to the relevant file operations, we need to use IO streams and related operations, and in order to allow users to have a better interaction, the need to use Java Swing interface provided by the final due to the need to analyze the performance, they need to use the appropriate performance analysis artifact JProfiler.


Class analysis
  • CreatUtil class: Create operation related operations
    • creat Method: random generation equation
    • creatNum Method: random number generation operation
    • creatSign Method: randomly generated symbols
    • formulaNum method: set a number of randomly generated equation
    • numRange method of: determining whether the operand exceeds a maximum value
  • ProcessUtil categories: the correlation calculation process and the
    • creatNum Methods: The answer according to specifications generated out
    • gcd Method: seeking the greatest common divisor of two numbers
    • charFind method: a bit sequence stored in the specified character formula
    • changeNum methods: the numeric string to a numeric value
    • judge Methods: The formula to determine compliance with specifications
    • Method change: the denominator operand molecule string into digital
  • CalculateUtil categories: Calculation Method
    • add method: adding
    • minus Method: subtraction
    • multiply method: multiplication
    • divide method: division
    • calculate method: right and left two numbers arithmetic operation symbol
    • calculateFormula method: Calculation formula
  • CheckUtil categories: check equation (check weight)
    • spiltStringBuilderToArray Method: Split the general formula array
    • spiltStringBuilderToList Method: List array split into the equation
    • spiltStringBuilderToOrderList Method: The equation split into an ordered array of List
    • judgeRepeat method of: determining whether a duplicate content
  • FileDao method:
    • storageResult Method: store the results to a file
    • storageFile method: stored procedures formulas and answers
    • readFile method: read the file
  • Enumeration Operator: The operator with information about the package, to avoid a plurality of times to reduce the effectiveness of new
  • MainUI categories: main page user interaction
  • Users fill out the page and other related operations: UserUI class


5, Code Description

The following lists the key codes and descriptions
  • CreatUtil classes: the class employed changed more random number generation to implement relatively random, and have the necessary calibration data at each step, to ensure data accuracy.
    @SuppressWarnings("all")
    public class CreatUtil {

    //日志输出
    private static final Logger logger = Logger.getLogger("CreatUtil");
    List<StringBuilder> formula;
    //备份式子,存储"分子/分母"结构的式子,便于结果计算
    List<StringBuilder> answer;
    StringBuilder extraCopy ;

    public List<StringBuilder> getFormula() {
        return formula;
    }

    public List<StringBuilder> getAnswer() {
        return answer;
    }

    /**
     * 随机生成式子
     * 用List存储式子
     * @param maxNum 最大值
     * @return 返回改字符串
     * */
    public StringBuilder creat(int maxNum) {
        StringBuilder formula = new StringBuilder();
        extraCopy = new StringBuilder(" ");
        //符号个数 (1,2,3)
        int signNum = (int)(Math.random()*3+1);
        creatNum(formula,maxNum);
        for(int i=0; i<signNum; i++) {
            creatSign(formula);
            creatNum(formula,maxNum);
        }
        formula.append(Operator.EQUAL_SIGN.getExpress() +" ");
        return formula;
    }

    /**
     * 随机生成操作数
     * 并将操作数存入list中
     * @param formula 字符串
     * @param maxNum 数
     * @return 返回参数的字符串
     * */
    public StringBuilder creatNum(StringBuilder formula,int maxNum) {
    	int numerator,denominator,type;
		type = (int)(Math.random()*2);
        //生成整数
		if(type==0) {
			do {
				numerator =(int)(Math.random()*10);
			}while(numerator > maxNum);
            //备份分子/分母
			extraCopy.append(numerator+"/"+1+" ");
			formula.append(numerator+" ");
		}
		else {
			do {
                //随机生成分子
				numerator = (int)(Math.random()*10);
                //保证分母不等于0
				while((denominator=(int)(Math.random()*10))==0);
			}while(!numRange(numerator, denominator,maxNum));
            //备份分子/分母
			extraCopy.append(numerator+"/"+denominator+" ");
			formula.append(ProcessUtil.creatNum(numerator, denominator));
		}
		return formula;
    }

    /**
     *  随机生成符号
     * 并将符号存入list中
     * @param formula 符号
     * @return 返回符号
     */
    public StringBuilder creatSign(StringBuilder formula) {
        //符号类型(+ - * /)
        int signType = (int)(Math.random()*4+1);
        switch (signType){
            case 1 :
                formula.append(Operator.PLUS_SIGN.getExpress());
                extraCopy.append(Operator.PLUS_SIGN.getExpress());
                break;
            case 2 :
                formula.append(Operator.MINUS_SIGN.getExpress());
                extraCopy.append(Operator.MINUS_SIGN.getExpress());
                break;
            case 3 :
                formula.append(Operator.MULTIPLIED_SIGN.getExpress());
                extraCopy.append(Operator.MULTIPLIED_SIGN.getExpress());
                break;
            case 4 :
                formula.append(Operator.DIVISION_SIGN.getExpress());
                extraCopy.append(Operator.DIVISION_SIGN.getExpress());
                break;
            default:

        }
        extraCopy.append(" ");
        formula.append(" ");
        return formula;
    }

    /**
     * 设定随机生成一定数目的式子,并将式子和答案分别存在formula和answer中
     * @param num 生成的式子数目
     * @param maxNum 最大值
     */
    public void formulaNum(int num, int maxNum) throws IOException {
        Long beginTime = System.currentTimeMillis();
        //存放拆分完的式子
        List<List<String>> formulaLists = new ArrayList<List<String>>(num);
        formula = new ArrayList<StringBuilder>();
        answer = new ArrayList<StringBuilder>();
        //原始式子
        StringBuilder singleFormula;
        for(int i=0; formula.size()<num; i++) {
            formula.add(singleFormula = creat(maxNum));
            CalculateUtil.calculateFormula(extraCopy);
            //式子不符合规范(结果为负数),并且查重
            if(extraCopy.charAt(0)=='@' || CheckUtil.judgeRepeat(singleFormula,formulaLists,extraCopy,answer)) {
                formula.remove(formula.size()-1);
                continue;
            }
            answer.add(extraCopy);
        }
        int i=0;
        FileDao.storageFile(formula,"Exercises.txt");
        FileDao.storageFile(answer,"Answers.txt");
        System.out.println("生成时间: " + (System.currentTimeMillis()-beginTime));
    }

    /**
     * 设定操作数的最大数值
     * @param numerator 分子
     * @param denominator 分母
     * @param maxNum 最大值
     * @return 是否超过最大值
     */
    public boolean numRange(int numerator, int denominator,int maxNum) {
        if((numerator/denominator)<maxNum) {
            return true;
        }else if((numerator/denominator)==maxNum) {
            if((numerator%denominator)==0) {
                return true;
            }
        }
        return false;
    }
}

  • CheckUtil categories: formulas for generating a checksum, the expression split, and then compared, and also answers comparison, a double guarantee the uniqueness of the formula

@SuppressWarnings("all")
public class CheckUtil {

    /**
     * 将StringBuilder拆分成string数组
     * @param stringBuilder
     * @return 返回string[] 数组
     */
    public static String[] spiltStringBuilderToArray(StringBuilder stringBuilder){
        return stringBuilder.toString().split("\\s+");
    }

    /**
     * 将StringBuilder拆分成List数组
     * @param stringBuilder string串串
     * @return 返回List数组
     */
    public static List<String> spiltStringBuilderToList(StringBuilder stringBuilder){
        return Arrays.asList(spiltStringBuilderToArray(stringBuilder));
    }

    /**
     * 将StringBuilder拆分成有序的 List 数组
     * @param stringBuilder string串串
     * @return 返回List数组
     */
    public static List<String> spiltStringBuilderToOrderList(StringBuilder stringBuilder){
        List<String> stringList = spiltStringBuilderToList(stringBuilder);
        Collections.sort(stringList);
        return stringList;
    }

    /**
     * 判断内容是否有重复
     * @param formula 判断的式子
     * @param lists 排序完的全部 list
     * @param answer 答案
     * @param answerLists 答案集
     * @return 返回是否重复
     */
    public static boolean judgeRepeat(StringBuilder formula, List<List<String>> lists,StringBuilder answer,List<StringBuilder> answerLists){
        List<String> formulaList = spiltStringBuilderToOrderList(formula);
        int i;
        for (i = 0;i<lists.size();i++){
            if(lists.get(i).equals(formulaList) && answer.toString().equals(answerLists.get(i).toString())){
                return true;
            }
        }
        lists.add(formulaList);
        return false;
    }
}

  • CalculateUtil categories: speaking pulled calculation method to reduce the degree of coupling, but also determines the data to ensure that the robustness of the system

@SuppressWarnings("unused")
public class CalculateUtil {

	private static final Logger logger = Logger.getLogger("CalculateUtil");

	/**
	 * 加法运算
	 * @param numerator1 分子1
	 * @param denominator1 分母1
	 * @param numerator2 分子2
	 * @param denominator2 分母2
	 * @return 返回结果
	 */
	public static StringBuilder add(int numerator1,int denominator1,int numerator2,int denominator2) {
		int numerator,denominator;
		StringBuilder result = new StringBuilder();
		numerator = numerator1*denominator2+numerator2*denominator1;
		denominator = denominator1 * denominator2;
		if(numerator!=0) {
			//化简分子分母(除以最大公因数)
			int gcdNum = ProcessUtil.gcd(numerator,denominator);
			numerator /= gcdNum;
			denominator /= gcdNum;
		}

		result.append(numerator+"/"+denominator);
		return result;
	}

	/**
	 * 减法运算
	 * @param numerator1 分子1
	 * @param denominator1 分母1
	 * @param numerator2 分子2
	 * @param denominator2 分母2
	 * @return 返回计算结果
	 */
	public static StringBuilder minus(int numerator1,int denominator1,int numerator2,int denominator2) {
		int numerator,denominator;
		StringBuilder result = new StringBuilder();

		numerator = numerator1*denominator2-numerator2*denominator1;
		denominator = denominator1*denominator2;
		//化简分子分母(除以最大公因数)
		if(numerator!=0) {
			int gcdNum = ProcessUtil.gcd(numerator,denominator);
			numerator /= gcdNum;
			denominator /= gcdNum;
		}
		result.append(numerator+"/"+denominator);
		return result;
	}

	/**
	 * 乘法运算
	 * @param numerator1 分子1
	 * @param denominator1 分母1
	 * @param numerator2 分子2
	 * @param denominator2 分母2
	 * @return 返回计算结果
	 */
	public static StringBuilder multiply(int numerator1,int denominator1,int numerator2,int denominator2) {
		int numerator,denominator;
		StringBuilder result = new StringBuilder();
		//操作数有一个等于0的情况
		if(numerator1==0||numerator2==0) {
			result.append(0+"/"+1);
		}
		//操作数大于0的情况
		else {
			numerator = numerator1*numerator2;
			denominator = denominator1*denominator2;
			//化简分子分母(除以最大公因数)
			if(numerator!=0) {
				int gcdNum = ProcessUtil.gcd(numerator,denominator);
				numerator /= gcdNum;
				denominator /= gcdNum;
			}
			result.append(numerator+"/"+denominator);
		}
		return result;
	}

	/**
	 * 除法运算
	 * @param numerator1 分子1
	 * @param denominator1 分母1
	 * @param numerator2 分子2
	 * @param denominator2 分母2
	 * @return 返回计算结果
	 */
	public static StringBuilder divide(int numerator1,int denominator1,int numerator2,int denominator2) {
		int numerator,denominator;
		StringBuilder result = new StringBuilder();
		numerator = numerator1*denominator2;
		denominator = denominator1*numerator2;
		//化简分子分母(除以最大公因数)
		if(numerator!=0) {
			int gcdNum = ProcessUtil.gcd(numerator,denominator);
			numerator /= gcdNum;
			denominator /= gcdNum;
		}
		result.append(numerator+"/"+denominator);
		return result;
	}

	/**
	 * 对运算符号左右的两个数进行运算
	 * @param index 运算符的位序
	 * @param extraCopy 待计算的式子
	 * @return
	 */
	public static StringBuilder calculate(int index,StringBuilder extraCopy) {
		char sign = extraCopy.charAt(index);
		int beginIndex = 0, endIndex = -1;
		int[] datas = new int[3];
		for(int index1=0; ; beginIndex=index1) {
			//找到第一个操作数的开头空格
			index1 = extraCopy.indexOf(" ", index1+1);
			if(index1==(index-1)) {
				break;
			}
		}
		datas = ProcessUtil.change(extraCopy, beginIndex);
		int numerator1 = datas[1];
		int denominator1 = datas[2];
		datas = new int[3];
		datas = ProcessUtil.change(extraCopy, index+1);
		int numerator2 = datas[1];
		int denominator2 = datas[2];
		endIndex = datas[0];
		//删除数字部分
		extraCopy.delete(beginIndex+1,endIndex);
		//根据符号进行相应的运算
		switch(sign){
			case '+':
				extraCopy.insert(beginIndex+1, add(numerator1,denominator1,numerator2,denominator2));
				break;
			case '-':
				if(!ProcessUtil.judge(numerator1, denominator1, numerator2, denominator2)) {
					//识别答案是否为负数
					extraCopy.insert(0, "@ ");
					break;
				}
				else{
					extraCopy.insert(beginIndex+1, minus(numerator1,denominator1,numerator2,denominator2));
					break;
				}
			case '*':
				extraCopy.insert(beginIndex+1, multiply(numerator1,denominator1,numerator2,denominator2));
				break;
			case '÷':
				if(numerator2 == 0) {
					//识别答案是否为负数,是的话在开头插入@作为标识
					extraCopy.insert(0, "@ ");
					break;
				}
				else{
					extraCopy.insert(beginIndex+1, divide(numerator1,denominator1,numerator2,denominator2));
					break;
				}
			default: break;
		}
		return extraCopy;
	}

	/**
	 * 按优先级进行运算(*  /  +  -)
	 * @param extraCopy copy副本
	 * @return 返回
	 */
	public static StringBuilder calculateFormula(StringBuilder extraCopy) {
//		logger.info(extraCopy.toString());
		//记录符号的位序
		int index = -1;
		//计算式子
		Pattern pattern1 = Pattern.compile("[*]|[÷]");
		Matcher m1;
		while((m1 = pattern1.matcher(extraCopy)).find()) {
			index = m1.start();
			calculate(index, extraCopy);
			if(extraCopy.charAt(0)=='@') {
				break;
			}	
		}
		//如果式子正确,在进行加运算(从左到右)
		if(extraCopy.charAt(0)!='@') {
			Pattern pattern2 = Pattern.compile("[-]|[+]");
			Matcher m2;
			while((m2 = pattern2.matcher(extraCopy)).find()) {
				index = m2.start();
				calculate(index, extraCopy);
				if(extraCopy.charAt(0)=='@') {
					break;
				}	
			}
		}
		//如果运算结束后(式子正确),调整答案格式
		if(extraCopy.charAt(0)!='@') {
			int datas[] = new int[3];
			datas = ProcessUtil.change(extraCopy, 0);
			int numerator = datas[1];
			int denominator = datas[2];
			//将原存储内容清空
			extraCopy.setLength(0);
			//将答案换成标准格式
			extraCopy.append(ProcessUtil.creatNum(numerator, denominator));
		}
		return extraCopy;
	}
}

  • ProcessUtil categories: providing a moment and method of operation of the calculation process for computing provides a solid backing

public class ProcessUtil {

    /**
     * 将答案按规范生成出来
     * @param numerator 分子
     * @param denominator 分母
     * @return 式子
     */
    public static StringBuilder creatNum(int numerator, int denominator) {
        StringBuilder num = new StringBuilder();
        int gcdNum = gcd(numerator, denominator);
        numerator /= gcdNum;
        denominator /= gcdNum;
        if (numerator >= denominator) {
            //分子大于等于分母
            if (numerator % denominator == 0) {
                //结果为整数
                num.append(numerator / denominator + " ");
            } else {
                //结果为带分数
                int interger = numerator / denominator;
                numerator = numerator - (interger * denominator);
                num.append(interger + "’" + numerator + "/" + denominator + " ");
            }
        } else {
            //分子小于分母
            if (numerator == 0) {
                //分子小于0
                num.append(0 + " ");
            } else {
                //其他情况
                num.append(numerator + "/" + denominator + " ");
            }
        }
        return num;
    }

    /**
     * 求两数的最大公因数
     * @param num01 数字1
     * @param num02 数字2
     * @return 返回公因数
     */
    public static int gcd(int num01, int num02) {
        int num = 0;
        while (num02 != 0) {
            num = num01 % num02;
            num01 = num02;
            num02 = num;
        }
        return num01;
    }

    /**
     * 将式子中指定字符的所有位序存储起来
     * @param str 字符串
     * @param formula 式子
     * @return 返回位序
     */
    public static int[] charFind(String str, StringBuilder formula) {
        int[] indexs = new int[20];
        for (int i = 0; ; i++) {
            if (i == 0) {
                indexs[i] = formula.indexOf(str, 0);
                continue;
            }
            if (str.equals(" ") && (indexs[i - 1] == formula.length() - 1)) {
                break;
            }
            if (str.equals(" ") || str.equals("/")) {
                indexs[i] = formula.indexOf(str, indexs[i - 1] + 1);
            }
            if (str.equals("/") && (formula.length() - 1 - indexs[i] <= 4)) {
                break;
            }
        }
        return indexs;
    }


    /**
     * 将指定数字字符串转为数字值
     * @param formula 带查找的式子
     * @param fromIndex 操作数前的空格位序
     * @param endIndex 操作数后的空格位序
     * @return 返回数字
     */
    public static int changeNum(StringBuilder formula, int fromIndex, int endIndex) {
        int num = -1;
        //根据数字的位数进行转换
        int sum = 0, temp;
        for (int i = 1; i < (endIndex - fromIndex); i++) {
            temp = (int) Math.pow((double) 10, (double) (i - 1));
            num = (int) (formula.charAt(endIndex - i) - 48) * temp;
            sum += num;
        }
        return sum;
    }

    /**
     * 判断被减数、减数是否符合规范(true:符合;false:不符合)
     * @param numerator1 第一个操作数的分子
     * @param denominator1  第一个操作数的分母
     * @param numerator2 第二个操作数的分子
     * @param denominator2 第二个操作数的分母
     * @return 返回是否正确
     */
    public static boolean judge(int numerator1, int denominator1, int numerator2, int denominator2) {
        int numerator = numerator1 * denominator2 - numerator2 * denominator1;
        if (numerator < 0) {
            return false;
        }
        return true;
    }



    /**
     * 通过字符串将操作数的分子分母转成数字
     * @param extraCopy 进行操作的字符串
     * @param beginIndex 操作数前的空格位序
     * @return 返回数字集
     */
    public static int[] change(StringBuilder extraCopy, int beginIndex) {
		int[] num = new int[3];
		int[] blanks = charFind(" ", extraCopy);//存储空格的位序,方便找到完整的操作数
		int indexBl = -1 ,indexBa ;
		indexBa = extraCopy.indexOf("/", beginIndex);//反斜杠的位置
		for(int i=0; i<blanks.length; i++) {
			if(blanks[i]==beginIndex) {//找到传入空格位序在blanks中的位置
				indexBl = i;
				break;
			}
		}
		num[0]=blanks[indexBl+1];//操作数后的空格位序
		num[1]=changeNum(extraCopy,beginIndex,indexBa);//分子
		num[2]=changeNum(extraCopy,indexBa,num[0]);//分母
		return num;
	}
}

  • FileDao categories: files for import and export encapsulated, i.e. operations for data persistence, there is a method for the file format determined corresponding to eliminate the occurrence of some abnormality

public class FileDao {

    private static final String PATH = System.getProperty("user.dir");

    /**
     * 输出信息导文件中
     * @param list 输入的内容
     * @param fileName 输入的文件名
     * @return 返回是否成功
     */
    public static boolean storageFile(List<StringBuilder> list, String fileName)  {
        File file = new File(PATH + "\\" +fileName);
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(file,false);
            String content = "";
            for (int i =0 ;i<list.size();i++){
                content = content + (i+1) + "、" + list.get(i).toString() + "\n";
            }
            fileOutputStream.write(content.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * 阅读用户传入的文件
     * @param file 传入的文件
     * @return 返回一个List集合
     */
    public static List<StringBuilder> readFile(File file) {
        List<StringBuilder> list = new ArrayList<>();
        FileInputStream fileInputStream = null;
        BufferedReader bufferedReader = null;
        //判断文件类型是否正确
        if (!file.exists() || !file.getName().contains("txt")){
            return null;
        }
        try {
            fileInputStream = new FileInputStream(file);
            bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
            String raw;
            for (int i = 0; null != (raw = bufferedReader.readLine()); i++) {
                //文件内容是否有、,分情况输出
                if (raw.contains("、")) {
                    list.add(new StringBuilder(raw.substring(raw.indexOf("、") + 1, raw.length() - 1)));
                } else {
                    list.add(new StringBuilder(raw));
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }
}

  • Enumeration Operator: The operator simple encapsulation

public enum Operator {

    /**
     * 运算符
     */
    PLUS_SIGN("加号","+","+"),
    MINUS_SIGN("减号","-","-"),
    MULTIPLIED_SIGN("乘以号","*","*"),
    DIVISION_SIGN("除以号","÷","/"),
    EQUAL_SIGN("等于号","=","=");

    private String name;
    private String express;
    private String calculation;

    Operator(String name, String express, String calculation) {
        this.name = name;
        this.express = express;
        this.calculation = calculation;
    }

    public String getName() {
        return name;
    }
    public String getExpress() {
        return express;
    }
    public String getCalculation() {
        return calculation;
    }
}


6, the test run


  • The program supports direct generation equation, if choose not to import the file, the system automatically generates equations, equation generation program supports 1W or greater number of bars, will also generate documents stored equation


  • 10000 system generating a test subject


  • The program supports local file import, and there is a wrong judgment function of the absolute path to the file, when the absolute wrong path, will show red box prompt, also supports the incoming file of a wrong judgment function


  • The results and the program also supports proofreading and proofreading will be stored in the appropriate file


  • The system has built-in instructions, the user can understand the instructions by the system.


  • This system has many features wrong ruling. The system supports only operands of less than 10, if the input operand is greater than the maximum 10, will prompt an error; not completed this page, you can not jump or click Next; if the input is greater than the total page jump page, there will be Tip error


7, Project Summary

Course of the project:
  • Early: In the absence of good planning and good architecture, but also they lack some of the necessary communication, resulting in the development of the project later blocked.
  • Mid-: In programming, there is no better subcontracting, resulting in the business layer is not completely pulled out.
  • Late: in debugging the test, because there is no experience BUG better pre-planning, it is more difficult in solving BUG.
Personal summary:
  • Luo Yi-ming: Due to the busy early, not the first time to join the development project. Exists in the development of some of the problems can not be ignored, as there is no user interaction to achieve complete separation of business logic and, on the other hand is not very sub-standard, the last is the lack of some of the exchanges in the cooperation. Partner Linyue Ling classmates found a lot of shine, she is full of enthusiasm for the development, it will not shirk, and learning speed than the block of new knowledge. But programming skills should be improved.
  • Linyue Ling: My analysis of this project is to do while writing, so write interface in the back when a lot of confusion, often change to change to not do full requirements in advance. A waste of time, have to write a lot of bug. There is construction projects and ideas I wrote a bit confusing, to his teammates brought great inconvenience, this is my this project reflected the two larger problem. Luo Yi-ming from classmates, I learned some experience in writing small programs, but also made me realize that I wrote a lot of shortcomings in the project, the future is much more to find him to ask for advice.

Guess you like

Origin www.cnblogs.com/mbya/p/12617155.html