LYP's Blog


  • 首页

  • 分类

  • 了解我

  • 归档

  • 标签

  • 简历

  • 看书

如何写好可维护的好代码

发表于 2017-05-25   |  

背景

在公司写了将接近一年的业务代码,自己维护自己的代码,同时也接手过别人的代码,不断地重构过程中,自己也不断地思考和总结:如何写好代码?

为啥需要写好代码

可讲的理由太多,说两点:

  • 这份代码不是只有你自己看,别人看到这份代码,如果写的太差,可读性很差,估计别人就不会认可的作者代码水平(要是个接盘侠,估计背地里也就开始骂娘了).
  • 可维护性太差,谁敢改?全是坑。

一些原则

保持代码洁癖

代码风格严谨的团队,从代码的基本规范,代码的命名,函数的抽取,类的抽取,最后UT的覆盖率,OOP,以及设计模式的运用,都会有要求,本身在学生时代,或多或少接触过代码规范问题,
有些意识,但是在生产环境,就需要特别加强。
最近阿里的java代码规范的开源,还是比google的代码规范详尽很多,涉及了例如函数设计的经验,作为一个职场的新人,至少得把这份规范好好研读下

代码的可维护性是个长期的过程

业务代码就是这样,不断地随着业务在改,很多代码慢慢的就没用了,脏代码越来越多,慢慢这套代码就需要进行重构了

  • 删除没用的代码
  • 避免相同的代码(或相近)出现在3个或以上的类里面,注意提取
  • 避免一个类写的太长,一个类大于300 line,我觉得就要拆了,业务代码嘛,就按业务功能拆开,提取公用的部分。
    最近接手一个工程,看到一个service,写了1500 行,那感觉真是日了* 。

UT

  • 至少覆盖静态类

工程的配置文件的配置常量问题

  • 工程配置常量集中化管理
    工程有很多的根据环境不同(生产环境,预上线环境,测试环境,本地环境)配置变量不同的情况,这些配置常量需要提取集中化到配置常量文件中,不能到处散落在各地,不好维护

系统稳定性之监控报警建设

发表于 2017-05-18   |  
  • 自己目前将一个系统从零起步,逐渐完善,一路走来,对整个系统的稳定性也是比较满意, 针对高可稳定这个角度,总结下需要包含哪些设计元素。
  • 文章就需要的元素进行大概的总结,不对具体的技术选型,以及设计细节,展开描述。
  • 是自己的实践总结之谈。

阅读全文 »

web api 接口安全设计探讨

发表于 2017-04-10   |   分类于 web   |  

web api安全性需要考虑的内容

  • 验证调用合法性
  • 防篡改 ,包括request 和response
  • 防重放(DDOS)
  • 防读

等

阅读全文 »

2017's plan

发表于 2017-02-08   |   分类于 私人   |  

一年之计在于春,2017年计划

  • 每天看两个小时的书。一年读10本技术书,书单记录如下:
    • java multithread
  • 每天健身时间>=45min。体重控制在65kg。
  • 两个开源项目的代码
    • okhttp
    • jetty && spring && spring mvc 部分源码
  • 精通java,成长历程:
    -
  • 熟悉前端,成长历程:
    -
  • 厨艺能有些进步,回家能给父母做好饭

  • 驾照

  • 说话不能有脏话 🤓

共勉

不能停止对生活的思考

专注做事情,不断坚持和改进,降低姿态

show your affection to others, so you can get others’ affection

流和文件

发表于 2016-12-09   |  

流结构基础梳理

java 的io体系概念较多,相应的读写的类较为复杂,有必要根据种类进行分类梳理,以便记忆

字节流 字符流

字节流

  • super class: InputStream && OutputStream
  • 读写的基本长度是8bit
  • 可以处理任意类型的文件

字符流

  • super class : Reader && Writer
  • 读写的基本长度是一个字符 16bit
  • 一般用来处理带有编码格式的文本

节点流,处理流

节点流

  • 节点流职级操作文件,或者网络数据 ,FileInputStream,FileOutputStream

处理流

  • 对节点流进行进一步包装,例如提供缓冲功能,数据过滤功能,对数据的读写的报装
    常见处理流又包含 缓冲流,转换流,数据流,对象流

缓冲流

  • BufferedInputStream / BufferedOutputStream
  • 数据会缓冲到内存里面,流关闭之前,需要进行flush的操作,将数据写入磁盘,避免数据的丢失

转换流

  • 只有InputStreamReader / OutputStreamWriter
  • 字节到字符的转换

    数据流

  • 提供java 基本类型数据的读写
  • DataInputStream / DataOutputStream

Print 流

Object 流

  • 对象的序列化
  • readObject() / writeObject()
  • jvm原生的序列化对象按自定义固定的格式(基于二进制)
  • 对于不可序列化的域,可以使用transient 标示

使用总结

读写文本数据

  • 文本输出PrintWriter,文本读入Scanner 或者BufferedReader
  • nio 的File类可以方便的读写中等长度的文本文件

读写二进制数据

  • DataInputStream 读入二进制数据并转化为java数据类型 , DataOutputStream 将java的数据以二进制写入,这两个流分别实现接口DataInput 和DataOutput 接口

java对象的读写

  • ObjectInputStream ObjectOutputStream

java 对象的序列化

  • 不可序列化的field,使用trandient 修饰符,注意常见的不可序列化的域或者没有序列化意义的域
  • 关于java序列化时的serialVersionUid的原因以及生成的办法

java 文件目录操作

  • File 、Path 对系统文件目录进行操作
  • 操作的文件系统默认是用户所在的磁盘,Paths 也可以操作其他的文件系统,例如一个zip压缩包

java 里面的内存映射

  • 关于四种文件读入的方式的性能比较
    • 四种方式分别为:普通输入流,带缓冲的输入流,随机访问文件,内存映射文件
    • 性能测试代码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      public class ReadSpeedTest {
      public interface Command {
      public long execute(Object data);
      }
      public static class TestInputStream implements Command {
      public long execute(Object data) {
      try{
      InputStream in = Files.newInputStream((Path)data);
      CRC32 crc32 = new CRC32();
      int c;
      while ((c = in.read()) != -1) {
      crc32.update(c);
      }
      return crc32.getValue();
      } catch (Exception e) {
      return -1;
      }
      }
      }
      public static class TestBufferInputStream implements Command {
      public long execute(Object data) {
      try {
      BufferedInputStream bufferedInputStream = new BufferedInputStream(Files.newInputStream((Path)data));
      CRC32 crc32 = new CRC32();
      int c ;
      while ((c = bufferedInputStream.read()) != -1) {
      crc32.update(c);
      }
      return crc32.getValue();
      } catch (Exception e) {
      return -1;
      }
      }
      }
      public static class TestRandomAccessFile implements Command {
      public long execute(Object file) {
      try {
      RandomAccessFile randomAccessFile = new RandomAccessFile(((Path)file).toFile(),"r");
      long fileLength = randomAccessFile.length();
      CRC32 crc32 = new CRC32();
      for (int i = 0; i < fileLength; i++) {
      randomAccessFile.seek(i);
      int c = randomAccessFile.read();
      crc32.update(c);
      }
      return crc32.getValue();
      } catch (Exception e) {
      return -1;
      }
      }
      }
      public static class TestMappedFile implements Command {
      public long execute(Object file) {
      try {
      FileChannel fileChannel = FileChannel.open((Path)file);
      CRC32 crc32 = new CRC32();
      long length = fileChannel.size();
      MappedByteBuffer memBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY,0,length);
      for (int i = 0; i < length; i++) {
      int c = memBuffer.get(i);
      crc32.update(c);
      }
      return crc32.getValue();
      } catch (Exception e) {
      return -1;
      }
      }
      }
      public static long time(String fileName,Command c) {
      long startTime = System.currentTimeMillis();
      long crcValues = c.execute(Paths.get(fileName));
      long endTime = System.currentTimeMillis();
      System.out.println(endTime - startTime);
      return 0;
      }
      public static void main(String[] args) {
      time(args[0],new TestInputStream());
      time(args[0],new TestBufferInputStream());
      time(args[0],new TestRandomAccessFile());
      time(args[0],new TestMappedFile());
      }

ps: 上面的代码一个一个字节读数据,能代表的数据很有限,可以尝试读取一个大文件,感受性能差异

文件锁

  • 获得文件锁使用FileChannel类 ,lock() or trylock()

    • api

      1
      2
      FileLock lock (long start , long size,boolean shared)
      FileLock tryLock (long start , long size,boolean shared)
    • java中的锁

正则表达式

  • Pattern && Matcher
  • Pattern.compile(regexString) ,then User Matcher to get the taget

参考链接

  • 深入理解 Java中的 流 (Stream)

daemontools

发表于 2016-11-25   |  

What is daemontools?

daemontools is a collection of tools for managing UNIX services.
supervise monitors a service. It starts the service and restarts the service if it dies.
Setting up a new service is easy: all supervise needs is a directory with a run script that runs the service.

tools list

  • supervise
    • 目录的结构是有规定的
  • svc
    service 开关
  • svscan
    用来启动服务目录下的所有子目录中的supervise(请看supervise)进程
  • svoko
    用来检查supervise是否在运行
  • svstat
    打印出被supverise监视的services运行状态

  • svscanboot

    这条指令非常重要,但是一般不需要自己手动输入执行,
    它用来启动 /service 目录下的svscan(请看svscan)命令,
    然后svscan会启动supvise(请看supvise),supvise会执行run脚本并且监视它。
    安装成功后在Linux重启的时候会自动执行svscanboot

How to install it?

use it

Reference

  • 用Daemontools监控Linux服务
  • daemontools 官方文档
  • Supervise
  • Daemontools: Tutorial
  • 在CentOS 6.4上安装daemontools(守护进程工具)
1234
罗宇平

罗宇平

keep thinking!

22 日志
13 分类
31 标签
GitHub
© 2015.7 - 2018 罗宇平
由 Hexo 强力驱动
主题 - NexT.Pisces