Heim  >  Fragen und Antworten  >  Hauptteil

http - 如何通过 debugging 来学习软件的运行原理?

第一次在 SegmentFault 提问,请多关照 ^^

这个问题可能有点泛泛,请先让我具体描述一下。我是一个编程小白初学者(本职是设计,编程是好奇心作祟),不过我也系统学习了 HTTP 以及一些基本的编程技术,最近经人介绍学起了 Rails 才逐渐了解和学习到编程方方面面的知识,很喜欢,刚刚跟着一个教程编写了一个非常简单的注册/登录功能,目前工作良好。

然而我的导师(带我入门的朋友)跟我说:

在 Web 开发中,身份校验是非常典型的功能,所有的 Web 开发框架都会提供哪怕是最基本的支持,同样也有很多第三方的插件和扩展包来提供更丰富的接口和功能。尝试学习和了解经典的身份校验原理对于 Web 开发者来说简直就是必修课。比如你刚才实现的东西,行话说就是:'基于 cookie 的认证机制'。你觉得不难,那是因为 Rails 帮你做了很多很多事情,而你做的只是最表层的,也是最简单的一些必要步骤而已。有机会的话,不妨试试去跟踪登录时框架的全过程,对你大有裨益的。

以上是他的原话(略作整理),我听了以后第一感觉好像很有道理……于是我问他怎么跟踪这个过程,但由于我们通讯不便(在外地旅游),他只给我讲了一些很抽象很难懂的要点。他建议我上这里来问问各路英雄,遇见类似的问题(不限定于注册/登录,也不限定于 Rails/Ruby),如果你们需要跟踪源代码来学习和理解某一个具体的功能实现,一般会怎么做?有什么要注意的事项或技巧呢?

其实我自己知道是要用到 debugging 的技术的,一些基本的技术我之前也学习过,至少知道如何给自己写的代码打断点,然后查看运行时的变量值或者步进/跳转之类的。但是就上述问题来说,当我登录的时候,我并不知道(举例) Rails 框架何时何地向我的浏览器发送 cookie 等等,在这种情形下,面对庞大的框架(随便看看就头晕)我要如何找到下手的地方呢?

真心请教各位学长前辈们,希望能从你们身上获得宝贵的启发和经验,谢谢!

伊谢尔伦伊谢尔伦2761 Tage vor627

Antworte allen(2)Ich werde antworten

  • 阿神

    阿神2017-04-22 09:01:18

    个人意见,仅供参考。
    用debugging跟代码是学习一个框架的好方法,但是前提是你了解基础知识,如果你对http协议本身还不熟悉,那么去看实现这个的框架就是如同看天书一般。

    比如说这个身份校验。
    首先你要知道大多数情况下的http是短连接,客户端(大多数情况下是浏览器)与http服务器建立连接,发送数据,然后拿到服务器返回的数据,之后连接就断开了。
    其次你多少要知道http通讯中的数据分为请求(Request)和响应(Response),请求由客户端(发往服务器,响应是服务器返回给客户端的。请求和响应的分为头(Header)和内容(Content),头是必须的,内容可以为空。

    知道上面两点知识后,再来看身份验证。
    身份验证大概分为两个过程:
    1、用户登录;
    2、用户访问其他资源,你获取到用户身份,并判断他能不能访问这个资源;

    由于上面提到http大多数情况下是短连接,像上面的场景就是短连接。
    用户登录和访问其他资源,这显然已经是两个连接了。
    那么服务器是无法判断两个连接都来自你,那么你是如何在第二次连接——访问资源时,获取到用户身份的呢?
    http协议为了解决这个问题,规定了cookie。

    在第一次连接——处理用户登录时,如果用户登录成功,那么服务器的响应(Response)的头(Header)中,包含了Set-Cookie的头,其中包含用户的信息,表示让客户端保存一些cookie,并规定了什么情况下(具体请参见cookie的规定)客户端应该把这些cookie发回给客户端。
    在第二次连接——访问资源时,因为满足发送cookie的条件,客户端会将cookie放在请求(Request)的头(Header)中,作为一个Cookie的头。这样服务器通过解析请求头,拿到了cookie,也就从中拿到了用户的信息。

    这就是一次身份校验的底层实现过程。

    这其中,处理响应头中的Set-Cookie,保存cookie,并在满足条件时将cookie放在请求头中发往服务器,是浏览器来实现的。
    而在响应头中放置Set-Cookie,以及从请求头中读取Cookie信息,可能就是你所使用的框架来实现的。

    ////////// 把回复补充到回答上来 //////////
    经题主回复,我把与题主讨论的内容补充到答案中。
    上面我提到的,是要了解框架的前提条件。也就是首先要了解框架帮你做了哪些事,然后再去看框架是如何做这些事情的。
    下面是讨论的内容,我就偷懒直接复制粘贴了:
    说下我一般的理解:Web框架负责了请求的解码处理和响应的编码封装。开发者需要写逻辑时,只需要拿参数和返回数据即可。参数如何从请求中取,以及返回的结果如何被编码为响应,这都是框架做的事情。
    因此一般来说,在自己编写逻辑的最开始和最后下断点,然后一直跟到框架内部的处理即可。
    先说在最后下断点,这个比较简单,因为在你的逻辑处理完成,返回数据之后,就交由框架来处理了,这个时候通过单步跟踪跟到框架代码的内部,一步一步看你返回的数据被框架如何处理即可。
    另外就是在开头下断点,这个时候实际上框架处理的部分已经执行完成,但是一般调试工具都可以看到调用栈,可通过调用栈看到执行你的逻辑代码前,框架执行了哪些代码,然后找到请求刚刚到达的代码,然后在此处下断点,再次发送请求,然后一步一步跟下来看。
    跟完开始和结束的代码,你就已经了解整个框架的处理流程了。

    Antwort
    0
  • 天蓬老师

    天蓬老师2017-04-22 09:01:18

    首先Debug对于任何一门语言都是必须的。如果语言不提供良好的debug工具。这么这门语言就相当于一坨shit。尤其是讨厌某些所谓的不需要debug。一边写一边编译的程序。

    学东西的方法是。先快速看入门书。看一遍。懂概念就行。然后按需求打代码。首先打的能编译成功(C++)。或者能运行(python)。这个状态。主要靠的是IDE纠错功能。

    等IDE纠错完成后。运行后会出现各种问题。主要是逻辑错误或者SegmentFault(C++)。
    到这个时候怎么办。从代码一遍遍看简直不能忍啊。

    一般有些人会告诉初学者。Printf/System.Out.println/print/等各种输出查看各个变量是否正常是否是你想要的值。
    这些对于熟练者是不能忍的(程序员三大美德(暴躁,懒惰,傲慢)中的前两美德的要求),写Print很累。发布的时候还要删除。而且有些调用的接口不知道返回值。打一个printf运行一下。耗时耗体力。

    那么熟练者怎么做。debug。这就是楼主所说中debug来源。
    我不需要打Print了。直接就可以看个个数据是否正常。是否是想要的值。
    在Java/C++中。debug还可以是。
    你不知道某个函数的返回值或者作用。debug中。再需要运行的环境里面停下。测试函数。就可以知道其相应的返回值。知道怎么继续写。
    当运行错误爆出到堆栈的时候,直接设置断点到相应的堆栈时。哪段代码出问题。哪个变量是空值一目了然。
    还有程序运行的流程。做了些操作。也可以通过控制debug来追踪代码运行的流程。这个就是楼主说的学习功能了。

    但是这只是debug。
    后面还有两个东西:
    一个是Log:线上是不让你debug的。出问题怎么办。把自己觉得哪里出问题的点打log,到时候找bug就一目了然。。
    一个是Test:只说单元测试。测试是另一种确定代码没问题的方法。比如你写项目中的很小一部分。而这一部分的main函数很远。要很特殊的情况才涉及到你的代码。(当然Java/Python这类可以无限制写Main函数,但某些不行)。但是你写好单元测试后。直接以单元测试启动。恩。模拟你想要的输入和输出。及时就可以发现函数的错误。不需要全部写完一个大工程。然后在无数个堆栈中找错误了。
    还有就是单元测试可以在排除某些特定的环境中的bug。比如你这段代码在你的电脑运行正常。一切满意。但是在其他电脑上运行不正常。用单元测试可以很快就能知道哪一段代码出问题。

    假如走到这里。相信你已经是个合格的程序员了。

    但是高手还有两个东西。性能测试和性能分析。到这一步。你就需要深入各个语言或者虚拟机底层的知识了。我这种菜鸟就不多说了

    Antwort
    0
  • StornierenAntwort