分类 默认分类 下的文章

书的标题叫《简洁之美》,副标题叫”软件设计之道”。
英文原版书名叫:Code Simplicity: The Science of Software Development.
个人感觉英文名字更明了,更简洁。

老外尤其是老美喜欢给软件开发这件事情戴帽子,比如有人把软件开发说成是一门手艺,而本书则说软件开发是一门科学,是有法可依的。
呵呵,这也反应了软件开发这个事情,老美的专业化程度还是比较高的。

软件的质量和代码的质量息息相关,因此,本书的目的就是要总结提高代码质量的”道”,做到软件开发有章可依。

作者认为,软件的目标就是要帮助人,任何的软件决策都应该以这个为出发点。不仅要能帮助人,还要尽可能多的帮助人,更甚至于要持续的尽可能多的帮助人,于是,需要软件开发后维护的成本要低,这样才能可持续。

既然是科学,当然要列个方程式,软件改变的合意度(可行性),正比于软件当前价值和未来价值之和,反比于实现成本和维护成本之和。所以,如果软件要使用很长时间(持续为人提供帮助)的话,那么,降低维护成本就显得越来越重要。

变化是不可避免的,大部分程序员也都知道这点,但是为了处理变化,程序员也会进入以下设计误区:1)编写不必要的代码。常常会给后来的维护者带来很大的误解,不知道这段代码有何用,因为根本没用,所以,不要编写不是必需的代码,并删除不用的代码。2)代码难以修改。主要原因有对未来做过多的假设,不仔细设计就开始编码。为避免此问题,在设计时应该根据现在确切知道的需求,而不是你认为未来会出现的需求。同时要考虑到未来会变化,保持可扩展性。3)过分追求通用。因为未来是一定会变化的,而怎么变化我们又无法预测,因此,即使设计的再通用,也可能会出现不能满足的情况。如果你的设计让事情变得复杂而不是简单,那么你可能就过度工程了。当然,渐进式的设计和开发可以避免上述的三个误区。

程序中新增缺陷的可能性和代码修改量成正比,所以好的设计应该是能满足外界的变化,但是自身变化要少。于是,就有如下规则:永远不要修正任何东西,除非他真的有问题,而且有证据表明问题确实存在。附加一条,任何系统里的任何信息,理想情况下应该只存在一份,DRY原则。

软件越简洁越容易维护,为保持简洁,尽量保持一致(命名,方法定义等),代码排版格式,名字足够长,完整表达意义但又不要太长影响阅读。要做到简洁,通常需要设计。如果遇到了不可避免的复杂,那么在外面包一层,让别人易于理解。

本书只有100页左右,主要列出了一些原则和可以遵守的条例,跟书名比较符合,非常简单。可以作为日常软件开发的一些指导,只有在实践中不断尝试,才能利用好这些原则。另外,感觉里面的东西,在《代码大全》里都有涉及,不愧的大全啊,那本书值得多读多实践。所以,相比本书,更推荐直接去读《代码大全》那本书。

之前用惯了eclipse,后来部门里都用IntelliJ IDEA,并且大家都说IDEA更好用,然后自己也去试用了下,发现了一些优点,但是仍然感觉不如eclipse好用,然后又切换回去了。

切换回eclipse之后,又开始想念IDEA的某些好处,再次试用,如此反复,来回几个回合,然后发现两个都有优点,又都有用不惯的地方。

最开始用电脑的时候,肯定是用的Windows,后来周围的人都在用MBP,业界对MBP的评价也比较好,于是体验了Mac系统,不习惯,但是还是感受到了一些优点,比如MBP的触模板,以及笔记本本身的设计感。但是老是想念用鼠标点点的感觉,尤其是macOS的Finder出奇的难用,于是,在Windows和Mac之间来来回回切换了无数次。最后感觉找不到一个各方面都合适的电脑了。

后来,来回折腾,耗费了大量的时间,心也累。索性不切换了,选了业界大部分人认为好的选项,IDEA和MBP。到现在,已经习惯了这两个东西,并且越来越觉得好用。当然也容忍了他们的缺点,而且也觉得所谓的缺点可能并非缺点,或者没那么重要。

结论:
1)改变习惯肯定会觉得不习惯,但是当你度过了这个不习惯的阶段,你会迎来一个新的天地。
2)大多数情况下,大家的感觉还是准的,选择大家都觉得好的一般没错。
3)没有完美的工具,选一个差不多好的工具,用熟练它,会大大提高你的效率。不要在工具上耗费太多的时间,尤其是同类的工具。

后记:
近视,配了一副眼镜,刚开始带不习惯,所以,很少带。最近感觉不带看不清了,于是带的时间久了,感觉也没那么不适了。

以下文字只在特定条件下成立,不可轻信:

国内银行卡之间是不能转账外币的,除非是直系亲属;
海外个人银行卡可以转账美元给(本人/非本人)的内地银行卡,要收费的;
海外个人银行卡可以直接结汇人民币到同名的内地账户,免费的。

记录下今年自驾回家过年的经历和感受。

拿到驾照买车后,没怎么开车上高速,一直在市区上下班开开。今年回老家过年,虽然老妈和老婆都不希望我开车,因为离老家实在太远了,有800多公里,还带着小孩,而且是只能我自己开。但是在我的坚持下,最终还是同意了。

由于之前没上过高速,因此,这次也是做足了准备,在今日头条关注了好多上高速的注意事项,并且在出发之前去4s店做了保养,没想到还真查出轮胎慢撒气,扎了钉子,于是补胎。后来,为了安全,又花了1000多大洋,装了一个胎压监测。因此,以后上高速,最好做个保养或者全车检查,尤其是轮胎。

腊月25一大早8点半我们一行四人就出发了,车上装的满满的,恨后备箱不够大啊,宝宝的推车都没装下,而这也间接造成了后来的老婆在家抱孩子不小心闪了腰,囧rz。第一次独自上高速还是蛮激动的,不过毕竟已经在市区开了一年多了,因此开的也算稳稳当当。开了一个多小时,就遇到了前方事故,堵车,正好又早上喝水多了,于是就进了服务区,休息了一会,继续上路。后来又去了两次服务区,吃个午饭,大约堵了2个小时,本来9个小时的路程,用了12多个小时,到晚上9点才到家。自己一个人开,还可以,稍微有点累,不过,毕竟第一次开这么久,兴奋大于疲惫,哈哈,一路还算顺利。

回到家后,发现老家虽然是乡下,但是比上次回来,汽车明显多了起来,好多人家的门口都停了小汽车。不过配套还是不行,之前修的路太窄了,基本只能通行一辆车,一旦对向两辆车,就要让着过了。

大年初五,从家里开始往回走,不过回来的路就没那么顺利了。早晨8点半出发的,走到高速路口就被告知封闭了,不让上高速,需要换到另一个高速入口上高速,要多跑几十公里的路。后来上了高速,发现车流量很大,再后来就堵在高速上了,特别的堵,到晚上9点,才走了1/3的路,光在加油站加油排了一个多小时的队,终于在晚上9点再次上路,流量相对好点,不是堵着不动了,但是也快不起来。一路开着,后来遇上了大雾,基本上能见度不到10米,开着双闪,根本没法走,老婆吓得要下高速,自己当时心里也是有点发憷,毕竟根本看不清前面的路,还怕后面车追尾,最终硬着头皮开过了那段大雾的路段。再往后就遇到了下雨,还有闪电,不过比之前的大雾好多了,毕竟能看清路了。最后路段,自己感觉太疲劳了,基本上靠自己掐大腿和打脸来保持清醒,老婆在副驾驶上也不断的提醒我。所幸,凭借着坚强的意志,平平安安的开到了家,到家的时候,凌晨3点多,一共开了19个小时。自己当时的感觉是,以后再也不这么开了。现在想想,有些后怕,在那种情况下,大雾+疲劳+天黑,太过冒险。提醒自己,下不为例。

值得欣慰的时候,来回路上,宝宝很乖,没怎么闹腾,远远好于我们之前的担心。赞一个。但是,为了宝宝,以后也不能这么开了,大人小孩都受罪。

这次回家过年,老婆闪了腰,自己喝酒后收了风寒,都没怎么好好过年。不过欣慰的是,我们回去,老爸很开心。老妈在我们这里帮着看孩子,老爸自己在家很辛苦,自己还是不能很好的照顾自己,这是让我很不舒服的。今年尽量争取有空多回去看看。

以上就是今年回家过年时自驾的见闻和感受。

Buffer是一块将要写到Channel里的数据,或者刚从Channel里读出来的数据。它是用来保存数据的一个对象,并且作为NIO Channel的其中一个端点(另一端可能是网络或者文件等)。Buffer提供了一种访问数据的机制,并且跟踪数据读写流程。

Buffer是Java 老的IO和NIO的主要不同之一。以前老的IO直接从流中读或者写。现在数据是从Buffer中都数据或者将写的数据写入Buffer中。在NIO中,Channel就相当于以前的Stream。了解更多NIO Channel可以访问这里

Buffer特点:

1 Buffer是NIO的基本构建块。
2 提供固定大小的容器来读写数据。
3 每一个Buffer都是可读的,但是选中的Buffer才可以写。
4 Buffer是Channel的其中一个端点。
5 在只读Buffer中数据内容是不可变的,但是Buffer的mark,position,limit是可以变的。
6 默认Buffer不是线程安全的。

Buffer类型:

每一个原生类型都有对应的Buffer类型。所有的Buffer类型都实现了Buffer接口。最常用的Buffer类型是ByteBuffer。在Java NIO包中包含如下的Buffer类型:ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer,MappedByteBuffer。

Buffer Capacity:

Buffer是固定大小的类型。如果Buffer满了,那么必须先clear,然后才能继续写入。一旦Capacity被设置就不能再改。

Buffer Limit:

在写模式中,Buffer的limit和capacity相同。在读模式中,limit是最后写入数据的索引加1。随着Buffer不断写入,Limit会保持增长。0 <= limit >= capacity

Buffer Position:

position指向Buffer的当前位置。当Buffer刚被新建的时候,position指向0,当读或者写的时候,position增加到下一个索引。Position在0和Limit之间。

Buffer Mark:

Mark就像对Buffer中的位置做了一个书签。当调用mark()方法的时候,当前的position会被记录。调用reset()方法可以恢复到之前mark的position。

Buffer flip,clear,rewind:

flip():调用此方法,使得Buffer准备开始读或者开始一系列新的写。设置limit=position,position=0.
clear():调用此方法,使得Buffer准备开始写或者启动一系列的新的读。设置limit=capacity,position=0.
rewind():想要从头开始读时,调用此方法,会把position设成0.

从Buffer中读数据示例代码:

ByteBuffer byteBuffer = ByteBuffer.allocate(512);
byteBuffer.flip(); //Flip the buffer to prepare for read operation.
int numberOfBytes = fileChannel.read(byteBuffer);
char c = (char)byteBuffer.get();

向Buffer中写数据:

ByteBuffer byteBuffer = ByteBuffer.allocate(512);
byteBuffer.put((byte) 0xff);

在NIO中,如果你要向文件中写数据,先把数据写入到Buffer,然后用Channel把Buffer写入到文件。与此同理,如果要从文件读数据,用Channel把数据从文件读到Buffer,然后从Buffer中取数据。

package com.javapapers.java.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class BufferExample {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("temp.txt");
        write(path);
        read(path);
    }

    private static void write(Path path) throws IOException {
        String input = "NIO Buffer Hello World!";
        byte[] inputBytes = input.getBytes();
        ByteBuffer byteBuffer = ByteBuffer.wrap(inputBytes);
        FileChannel channelWrite = FileChannel.open(path,
                StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        channelWrite.write(byteBuffer);
        channelWrite.close();
    }

    private static void read(Path path) throws IOException {
        FileChannel channelRead = FileChannel.open(path);
        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        channelRead.read(byteBuffer);
        byte[] byteArray = byteBuffer.array();
        String fileContent = new String(byteArray).trim();
        System.out.println("File Content: " + fileContent);
        channelRead.close();
    }
}

本文翻译自 javapapers文章,仅供参考和学习。