The practice of programming
2015-10-24 04:24
344 查看
1. Style
1.1 Names
Use descriptive names for globals, short name for locals. The broader the scope of a variable, the more information should be conveyed by its name.method name should be based on active verbs: getTime()
method return boolean: isChar() inArray()
main concerns of programming style: descriptive names, clarity in expressions, straightforward control flow, readability of code and comments.
2. Algorithms and Data Structure
The behavior of some algorithms depends strongly on the input data.Steps for choosing a algorithms :
Consider how much data the program is likely to process. Simple techniques enough? or need scalable solution?
Use a library or language feature
Data Structure: array, list, binary search tree, hash table.
Arrays support constant-time access to any element but do not grow or shrink gracefully. Lists adjust well to insertions and deletions, but take O(n) time to access random elements. Trees and hash tables provide a good compromise: rapid access to specific items combined with easy growth, so long as some balance criterion is maintained.
3. Design and Implementation
The design and implementation of the MarkovChain program illustrate a number of lessons for larger programs. First is the importance of choosing simple algorithms and data structures, the simplest that will do the job in reasonable time for the expected problem size.It best to start detailed design with data structures, guided by knowledge of what algorithms might be used; with the data structures settled. the code goes together easily.
MarkovChainTextGenerator
package com.mtjwy.tpop.generator; import java.io.File; /** * This program is to generate random English text that reads well. * The approach is to use an existing text to construct a statistical * model. The model presents the frequency of appearance of whole * phrases used in the chosen text. From the model, this program generate new text * using MarkovChain Algorithm. * * reference: The Practice of Programming * */ public class MainApplication { public static final int MAX_WORDS_GENERATED = 1000; public static void main(String[] args) { MarkovChain chain = new MarkovChain(); File file = new File("GoneWithTheWind.txt"); chain.build(file); String newText = chain.generate(MAX_WORDS_GENERATED); System.out.println(newText); } }
package com.mtjwy.tpop.generator; import java.util.ArrayList; import java.util.List; /** * Here a Prefix is a phrase consisted of a sequence of adjacent words in a text. */ public class Prefix { private static final int MULTIPLIER = 31; // for hashCode() private List<String> pref;//store each word of prefix in list public Prefix(Prefix p) { //make deep copy pref = new ArrayList<String>(); for (String s : p.getPref()) { pref.add(s); } } public Prefix(int n, String str) { pref = new ArrayList<String>(); for(int i = 0; i < n; i++) { pref.add(str); } } public List<String> getPref() { return pref; } public void setPref(List<String> pref) { this.pref = pref; } /* * Prefix object will be used as key in HashMap, * so need to rewrite hashCode for it. */ @Override public int hashCode() { int h = 17; for (String s : pref) { h = MULTIPLIER * h + s.hashCode(); } return h; } /* * Need to rewrite hashCode() and equals() at the same time * */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } if (getClass() != o.getClass()) { return false; } final Prefix p = (Prefix) o; for (int i = 0; i < pref.size(); i++) { if (!pref.get(i).equals(p.getPref().get(i))) { return false; } } return true; } }
package com.mtjwy.tpop.generator; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Scanner; public class MarkovChain { public static final int PREFIX_SIZE = 2; public static final String MARKER = "\n"; private Pr 4000 efix prefix; private Map<Prefix, List<String>> stateMap; // key = prefix, // value = suffix list public MarkovChain() { prefix = new Prefix(PREFIX_SIZE, MARKER); stateMap = new HashMap<>(); } /* * build the stateMap from a file */ public void build(File f) { Scanner sc2 = null; try { sc2 = new Scanner(f); } catch (FileNotFoundException e) { e.printStackTrace(); } while (sc2.hasNextLine()) { Scanner s2 = new Scanner(sc2.nextLine()); while (s2.hasNext()) { String s = s2.next(); add(s); } } add(MARKER); } /* * add word to suffix list, update prefix */ private void add(String word) { // retrieves the suffix list for the current prefix from the stateMap List<String> suf = stateMap.get(prefix); if (suf == null) { suf = new ArrayList<String>(); stateMap.put(new Prefix(prefix), suf);// make a deep copy of prefix, // and use it as key } // add word to suf list suf.add(word); // advance the prefix prefix.getPref().remove(0); prefix.getPref().add(word); } /* * generate output string from stateMap */ public String generate(int numWords) { prefix = stateMap.keySet().iterator().next(); Random rand = new Random(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < numWords; i++) { List<String> s = stateMap.get(prefix); int r = rand.nextInt(s.size()); String suf = s.get(r); if (suf.equals(MARKER)) { break; } sb.append(suf).append(" "); if (i != 0 && i % 8 == 0) { sb.append("\n"); } prefix.getPref().remove(0); prefix.getPref().add(suf); } return sb.toString(); } public Map<Prefix, List<String>> getStateMap() { return stateMap; } public void setStateMap(Map<Prefix, List<String>> stateMap) { this.stateMap = stateMap; } public Prefix getPrefix() { return prefix; } public void setPrefix(Prefix prefix) { this.prefix = prefix; } }
5. Debugging
Techniques that help reduce debugging time include good design, good style, boundary condition tests, assertions and sanity checks in the code, defensive programming, well-designed interfaces, limited global data, and checking tools.Multi-thread programs are not handled well by debuggers.
Debug techniques:
Good Clues, Easy Bugs
Think hard and add output statement and self-checking code at critical places.Look for familiar patterns.
Examine the most recent change.
If you’re changing only one thing at a time as a program evolves, the bug most likely is either in the new code or has been exposed by it.
you should keep records of changes made and bugs fixed.
Don’t make the same mistake twice.
After you fix a bug, ask whether you might have made the same mistake somewhere else.
Debug it now, not later.
Don’t ignore a crash when it happens; track it down right away, since it may not happen again until it’s too late. A famous example occurred on the Mars Pathfinder mission.
Get a stack trace.
Read before typing.
read the code very carefully and think about it for a while without making changes.
Explain your code to someone else.
No Clues, Hard Bugs
Make the bug reproducible.Setting the seed for random.
Divide and conquer.
Can the input that causes the program to fail be made smaller or more focused?
Proceed by binary search.
Study the numerology of failures. Sometimes a pattern in the numerology of failing examples gives a clue that focuses the search.
Display output to localize your search.
Write self-checking code.
Draw a picture.
Use tools. Compare diff of two version.
Keep records.
Last resorts
use a good debugger to step through the program.wrong operator
scope error
arguments in the wrong order
global, shared or referenced variables are modified
algorithm or data structure has a fatal flaw
the test program is wrong
orgetting to close files
Memory “leaks”
Non-reproducible Bugs
Check whether all variables have been initializedOther People’s Bugs
Do you have the latest version of the program?Before starting, though, you must first acquire some under-standing of how the program is organized and how the original programmers thought and wrote.
Find cross-referencers. Track the execution flow.
Bug report
provide the owner with as good a test case as you can manage.
Strip the test down to a minimal and self- contained case.
Include other information like the version of the program itself. and of the compiler. operating system. and hardware.
6. Testing
Systematic testing, from easy tests to elaborate ones, helps ensure that programs begin life working correctly and remain correct as they grow.
Thinking about testing as you write a program will lead to better code, because that’s when you know best what the code should do.
Test as You Write the Code
Test code at its boundaries. It is effective to find off-by-one error.condition branches go the right way
loop goes through the proper number of times
non existing or empty input
single input item, full array,nearly full, exactly full, and over-full
Test pre- and post-conditions.
Use assertions.
Program defensively.
A useful technique is to add code to handle “can’t happen” cases, situations where it is not logically possible for something to happen but it might anyway. (because of some failure elsewhere)
Check error returns.
Systematic Testing
To be orderly, keep recordsTest incrementally.
Test simple parts first.
example of test binary search
Know what output to expect
Verify conservation properties.
Measure test coverage.
Test Automation
Automate regression testing.The most basic form of automation is regression testing, which performs a sequence of tests that compare the new version of something with the previous version.
It’s good practice to check the regression test itself periodically to make sure it is still valid.
Create self-contained tests.
Stress Tests
High volumes of machine-generated input are another effective testing technique.相关文章推荐
- 两种观点兼顾的架构设计方法
- 初学架构设计的第一步:需求、愿景与架构
- 初学架构设计的第一步:需求、愿景与架构
- 初学架构设计的第一步:需求、愿景与架构
- Android:数据持久化(1/2)文件、SharedPreferences
- Formal System-表达逻辑:Syntax,Semantik
- ibm traveler 无法同步新邮件的问题
- (二)redis的启动和关闭
- 常用算法:分治算法、动态规划算法、贪心算法、回溯法、分支限界法
- LeetCode #24 Swap Nodes in Pairs (M)
- (一)使用源码包方式安装redis-2.8.13
- C++调用python
- C++模板与泛型编程基础
- POJ 3207 解题报告
- 界面之间的滑动
- 关于使用phpstudy搭建本地服务器,80端口被系统服务占用,不能关掉
- Centos 7 上安装 Gitlab的步骤和一些设置方法
- flexbox学习
- 5.2的Dr.com客户端启动不了,3.7的客户端提示本机未安装TCPIP协议
- leetcode之Invert Binary Tree