让程序员崩溃的瞬间

引言

华软第二版开发以来,要么在开发JNA调用C++的功能,要么在学习RealVNC的文档,要么在Github上看别人的VNC客户端代码。

一直在看第三方的代码,我的内心是崩溃的。

今天我来教教大家,如何让程序员崩溃。

令人崩溃的操作

if十八层地狱

这是JNA的源码,我想问问,大家什么感受?

当然,这个还算逻辑简单的,如果逻辑复杂套18if,爽不爽?

public static int getNativeSize(Class<?> cls) {
    if (NativeMapped.class.isAssignableFrom(cls)) {
        cls = NativeMappedConverter.getInstance(cls).nativeType();
    }

    if (cls != Boolean.TYPE && cls != Boolean.class) {
        if (cls != Byte.TYPE && cls != Byte.class) {
            if (cls != Short.TYPE && cls != Short.class) {
                if (cls != Character.TYPE && cls != Character.class) {
                    if (cls != Integer.TYPE && cls != Integer.class) {
                        if (cls != Long.TYPE && cls != Long.class) {
                            if (cls != Float.TYPE && cls != Float.class) {
                                if (cls != Double.TYPE && cls != Double.class) {
                                    if (Structure.class.isAssignableFrom(cls)) {
                                        return ByValue.class.isAssignableFrom(cls) ? Structure.size(cls) : POINTER_SIZE;
                                    } else if (!Pointer.class.isAssignableFrom(cls) && (!Platform.HAS_BUFFERS || !Native.Buffers.isBuffer(cls)) && !Callback.class.isAssignableFrom(cls) && String.class != cls && WString.class != cls) {
                                        throw new IllegalArgumentException("Native size for type \"" + cls.getName() + "\" is unknown");
                                    } else {
                                        return POINTER_SIZE;
                                    }
                                } else {
                                    return 8;
                                }
                            } else {
                                return 4;
                            }
                        } else {
                            return 8;
                        }
                    } else {
                        return 4;
                    }
                } else {
                    return WCHAR_SIZE;
                }
            } else {
                return 2;
            }
        } else {
            return 1;
        }
    } else {
        return 4;
    }
}

如果是我写这个方法,我会这样写:

这也是我一直推崇的编码风格,if判断终止条件,正常情况再执行到最后,这样会减少嵌套。同样都是实现功能,为什么不把代码写得友好一点,让别人少骂两句呢?

public static int getNativeSize(Class<?> cls) {
    if (NativeMapped.class.isAssignableFrom(cls)) {
        cls = NativeMappedConverter.getInstance(cls).nativeType();
    }

    if (cls == Boolean.TYPE || cls == Boolean.class) {
        return 4;
    }

    if (cls == Byte.TYPE || cls == Byte.class) {
        return 1;
    }

    if (cls == Short.TYPE || cls == Short.class) {
        return 2;
    }

    if (cls == Character.TYPE || cls == Character.class) {
        return WCHAR_SIZE;
    }

    if (cls == Integer.TYPE || cls == Integer.class) {
        return 4;
    }

    if (cls == Long.TYPE || cls == Long.class) {
        return 8;
    }

    if (cls == Float.TYPE || cls == Float.class) {
        return 4;
    }

    if (cls == Double.TYPE || cls == Double.class) {
        return 8;
    }

    if (Structure.class.isAssignableFrom(cls)) {
        return ByValue.class.isAssignableFrom(cls) ? Structure.size(cls) : POINTER_SIZE;
    } else if (!Pointer.class.isAssignableFrom(cls) && (!Platform.HAS_BUFFERS || !Native.Buffers.isBuffer(cls)) && !Callback.class.isAssignableFrom(cls) && String.class != cls && WString.class != cls) {
        throw new IllegalArgumentException("Native size for type \"" + cls.getName() + "\" is unknown");
    } else {
        return POINTER_SIZE;
    }
}

不健全的文档

JNA获取系统状态信息,照着头文件开始拼结构体。

typedef struct {
    DWORD         rev;
    DWORD         kernel_memory_bytes;
    LONGLONG      disk_cache_memory_bytes;
    DWORD         host_online_count;
    DWORD         rev1;
    DWORD         rev2;
} PSA_SYSTEM_STATUS;

内存缓存容量:

1000010111011110101111(我获取的)
100001011101(实际数据)

硬盘缓存容量:

1111001000000000000000000000000(我获取的)
111100100000000000000(实际数据)

嗯?为什么我获取的数据就比实际的数据多10位呢?

再看看变量名,原来人家都告诉我了,kernel_memory_bytes,单位不一样。无符号右移10位相当于除以1024,就将B变成KB了。

其实在变量名声明的时候就已经告诉我单位了,但是编写结构体映射的时候,都是大致看看名字,怕自己打错,直接复制过来的,没关注着最后一个单词里还有单位。

假面向对象

这个是我当时写节点同步的时候遇到的问题。关系如下,一个节点下有多个计算机,同步的时候需要将节点和其下的所有计算机都同步过来。

设计的时候就去api里找同步节点的方法,EnumImageNodeFirstEnumImageNodeNext

然后天真地以为还有一个EmunHostByImageNode的方法,找啊找,也找不着。

后来发现该方法有一个get_type参数,你传什么参数,这个方法就是什么功能。

数据类型又是万恶的void *,哪天你真把类型传错了都发现不了。

秉着写if不带else的宗旨,这样的方法我是写不出来。

没注释

我尝试学习一下TightVNC Java Viewer的代码,几千行代码,一条注释都没有。

对不起,打扰了。不写注释的都是牛人,惹不起惹不起。

神奇的方法名

不用我多说了吧?

百度翻译没毛病!

当然,瑕不掩瑜。还是要表扬潘佳琦的,在华软项目上贡献巨大,还有之前的选修课签到、评分都是交给他完成的。

不要怕,都能看懂

语言是用来交流的,外国人看你的英语就像你看老外的中文一样,虽然看着有点怪,但是还是能看懂的。

前天研究VNC的时候,需要启用Direct TCP Connect(TCP直联)功能,需要传一个add-on code,我找了半天也不知道是啥,就拿着我六级还没过的英语就给RealVNC官方发邮件。

Hello VNC! I'm a software developer.
I use vnc in my project. I'd like to try it myself using real vnc sdk, but i met some problems, i have to enable add on components. But i don't know the add-on code list.
I see the blog from https://www.realvnc.com/en/news/connect-devices-directly-instead-using-vnc-cloud/, it suggests me to email to you to obtain an add-on code.
Sincerely, Thank you very much!

官方也很认真地回复了我,解决了我的问题,很开心。但是最后因为这个软件太贵了,用不起正版,还是决定改用其它方式。

总结

  1. if多判断终止条件,减少嵌套。
  2. 用别人的代码难就难在你需要先去学习其思想,所以,请友好一些。
  3. 方法名尽量起得符合场景。
  4. 我们的英语其实都可以,不用怕,我们都可以和外国人交流。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理