十八年开发经验分享(03)问题解决篇(中)

【QMIX】一种基于Value-Based多智能体算法 文章目录1. QMIX 解决了什么问题(Motivation)2. QMIX 怎样解决团队收益最大化问题(Method)2.1 算法大框架 —— 基于 AC 框架的 CTDE(Centralized Training Distributed Execution) 模式 QMIX 是一种基于 Value-Based 的多智能体强化学习算法(MARL),其基本思想来源于 Actor-Critic 与 DQN 的结合。使用中心式学习(Centralized Learning)分布式执行(Distributed 阅读详情

关于本系列文字的来源,初衷和内容定位可以参考第一篇的开头部分,链接地址如下:
http://blog.youkuaiyun.com/binarytreeex/article/details/8174445
http://www.cnblogs.com/WideUnion/archive/2012/11/12/2766397.html
本文前一篇地址如下,感兴趣的可以访问下面的连接:
http://blog.youkuaiyun.com/binarytreeex/article/details/8456766
http://www.cnblogs.com/WideUnion/archive/2013/01/01/2841335.html
 
本文是问题解决篇的第二部分,继续讨论与解决实际工作中的问题相关的内容。本文假设读者是具备一定开发经验的。这个所谓的经验是指需要满足这样一个底线:代码中的语法错误和逻辑错误可以自己独立解决,或者说基本上可以独立解决。如果是开发新手,尤其是没有经验的毕业生,我不推荐来看本文,对这部分程序员来说本文的难度有点大了。
 
对于有一定开发经验的程序员来说,工作中遇到的问题基本上是可以自己独立解决的。所以本文讨论的内容旨在帮助这部分程序员更好的解决问题,或者说在进一步提高解决问题的能力上,提供一些参考和有用的方法与思路。和上一篇一样你不能期望本文可以解决你所遇到的所有问题,或者看了本文之后就可以立马武功大增,这是不现实的。但是如果记住我个人的这些经验,然后在工作中去实践,在日积月累中可以帮助你(至少有一部分程序员是这样)更快,更好的提高解决问题的能力,这个是可以做到的。因为我就是这么走过来的,所以如果你也想这么走过来,那么我分享的经验对你一定是有帮助的。
 
再次强调本文介绍的内容来自个人的实践,对于解决问题这样一个宏大的话题和全体开发者这样一个宽泛的群体来说,局限性和片面性是在所难免的。所以请同行们自行取舍,同时也要根据自己的经验,实际应用场合做出适当的变化,这样才能更好的应用本文介绍的内容。如果分享的内容可以为同行们解决实际工作中的问题起到积极作用的话,那么我的目的就达到了。当然如果能够达到庖丁解牛那样游刃有余的境界那是最好的。
 
一.解决问题的一般步骤
当程序员在实际工作中遇到问题时该如何去解决呢?以我个人的经验来说大致是以下几个步骤。首先需要去认识问题,确认这是一个什么样的问题或者问题是什么。比如对于调试程序中出现的bug,往往是以能够重现bug为前提的,否则无从下手。这种可重现性对我们认清并判断问题是一个前提。在实现某一个功能时,程序员也需要对实现的功能有一个清楚的认识,然后才能选择合适的方法来解决。所以解决问题的第一步是认清问题。第二步是评估这个问题是否有解决的办法,或者说需要做一定尝试工作以确定这个问题是可以解决的。这一步也很重要,它的作用在于保证程序员在解决问题的一开始就朝一个正确地方向前进。这一步的另外一个作用在于评估解决一个问题是否值得去做。有时候解决一个问题,不总是以解决作为结果的,有时候放弃也是一个合理的选择。第三步是选择合适的方法解决问题。不同的人对于相同的问题可能会给出不同解,这个由解决问题的程序员自己决定。能力,环境等等因素都会导致不同的解决问题的方法。
 
二.程序员通常会遇到什么样的问题
在大部分的情况下程序员遇到的问题属于工程问题,而不是科研问题。与我们在学校中做习题相比实际工作中的问题具有一些不同的特征。
 
1.是否存在解
在学校中我们做的习题一定是有解的,但是实际工作中的问题则未必,或者说自己面对的问题不一定是可以最终被解决的,而是以失败告终的。
 
2.是否有最优解
习题往往存在一个所谓的标准答案,但是实际工作中的问题往往会存在多个或者若干个可行办法来解决问题,工程师需要从中选择一个。所谓的最优解有可能是不存在的。
 
3.选择解的标准不同
用于判断最优(或者说最合适)的解的标准不同。做习题往往是单纯的比较方法本身的差异。而在实际工作中需要考虑其它相关的或者周边的因素,比如:难易程度,成本等等。对我而言我把最终选择的方法的可理解性,可维护性和功能变化后可重构性放在非常重要的位置,作为选择解的标准。
 
4.可选解的选择范围不同
做习题只能是用知识正面解决问题,当然抄袭是不算的。但是实际工作中的问题可以使用非技术手段来解决。比如对于性能问题的改善,可以通过重新设计算法来解决,也可以通过改善硬件配置来解决;对于用户提出的bug,可以直接修改解决,也可以通过富有技巧性的沟通来解决,等等。
 
实际工作中的问题还有一个比较乐观的特点,那就是问题往往总是可以被解决的。其原因是有由于大环境和小环境决定的。大环境是公司或者团队在选择开发任务或者立项时会有一个评估,这和上面提到的解决问题步骤中的第一第二步类似。小环境是,在具体安排开发任务时,往往会根据各人不同的技术特长而安排有针对性的开发任务,或者有选择性的安排不同难度的任务。就我而言,当初是以VC入行的,结果公司开始就安排VC的开发任务,今后就一直以此为依据来安排开发任务的。从而导致我很少有机会接触其他的开发任务,比如Java之类的。
 
在实际工作中,程序员遇到的大部分问题都是如此的。所以从战略层面讲,没有必要畏惧问题。当程序员遇到问题时,请保持信心,要相信方法总是会比问题多的。这样的心理状态对解决问题也是很有帮助的。
 
三.解决问题的基础条件
就我个人的体会而言,解决问题的基础条件应该有三个,但是本文需要关注的只有两个,那就是知识和经验。实际上对我而言,在解决问题时我最担心的是需要用到我不知道的知识,这才是最可怕的。这次在给Entity Model Studio开发时序图时就出现过这样的担心,后文会讨论这个例子的。现在举另外一个例子来简单说明一下知识的作用。
 
有一个非常著名游戏叫魔法门,我在2000年之前玩过其中的几个版本。其中一个版本有这么一个任务,要求主角到一个修道院去拿一件物品。该物品在一条走廊的尽头,如果直接走过去拿是不行的,因为那里有一个牧师在做祷告,挡住了去路。按照攻略上的说法,需要去大堂的阁楼上按照一定的次序拉动五根绳索,然后回来,这时牧师就离开了,从而可以成功拿到物品。这五根绳子的拉动方式是这样,用鼠标选择然后点击,如果点击的顺序匹配上了,游戏就给出一个响声作为提示。否则你就可以一直没完没了的点下去。好,现在简单说明一下这个问题的核心焦点是什么。
 
首先说明这不是一个难问题,但是有一个不算问题的小障碍,那就是在处理输入数据时和我们通常的方式是不同的。我们回想一下自己实现过的功能,一般来说用户输入的数据(这个游戏场景里就相当于用鼠标点绳索)会有一个明显的结束操作。比如:用户注册,填完注册信息之后按提交按钮;查询时输入表示条件的数据,然后按查询按钮,等等。但是这个游戏中的场景却不是这样的,这个第一人称的角色扮演游戏允许用户可以不停的点击鼠标,而不是要求玩家每点五次鼠标然后再按提交按钮,程序做判断,匹配就通过,否则重新再点五次。与我们通常处理的情况相比这是最大的不同,这个问题的核心焦点就在这里。有兴趣的同行可以考虑一下自己会如何做。这里限于篇幅,我就不说明解决的过程了,而是直接给出我的作法。当然这个不是什么标准答案,但是从用到的知识和方法来说,我相信魔法门的真正开发者也应该是这么做的。
 
这里假设正确的点击次序是54321,也就是第一次点第五根绳子,第二次点击第四根绳子,以下类推,这个数据可以保存在一个数组里,比如整型数组。当玩家第一次点击时,获得点击的绳子的序号,然后和数组的第一个元素比较。如果相同,那么玩家第二次点击时就和数组中的第二个元素比较,如果一直正确那么每次点击后都依次比较后一个元素,一直比较到最后一个元素正确时,就可以让那个牧师走开了。如果比较的结果不对,那么当玩家再次点击时就要和数组中的第一个元素比较,重新开始了。比如,玩家连续三次点对,但是第四次点击错误的话,那么第五次点击时比较的数据是数组中的第一个元素。好了,解决问题的思路有了,下面的问题是代码怎么写?一般来说直接用嵌套的if语句或者嵌套的循环就算做出来也是不可取的。打分的话是零分,肯定是零分。我推荐一个做法是用状态转换图,到这里,书上学到的知识开始用上了。
 
下图是我画的状态转换图,当然只是一个示意,将就着看吧,不规范或者不正确的地方可以指出来。



由于问题比较简单,表示状态的变量和表示数组下标的变量可以用同一个来表示,并且初始化为零。玩家每点击一次就和下标指示的当前位置的元素比较,如果一致,下标就加一。然后判断下标是否超出数组长度,如果是那就表示通过了,否则将下标设置为零。所以,可能的代码大概是这样:
 
if (data[state] == inputData)
    state = state + 1;
else
    state = 0;
 
if (state >= 5)
{
   触发通过剧情
}

或者简洁一点可以写成这样:
state = (data[state] == inputData)? state + 1 : 0;
 
if (state >= 5)
{
   触发通过剧情
}

其中data保存的是正确次序的数组,state就是那个状态也就是下标,inputData表示玩家点击的绳子的编号。
 
这里需要强调一下,如果按照书本上的知识,严格规范的按照状态转换图的作法来解决这个问题的话,代码会比较臃肿。比如,我们在这个例子中还是遵守一个状态用一个独立方法来处理的话,那就很没有必要了。所以提醒工程师们在应用知识时做适当的有针对性的变化。另一个需要强调的是,知识在这个例子中对解决问题是非常有效的。想想开发魔法门的程序员和我们相比当然强的很多很多,但是只要有足够的知识,我们就可以和他们做的一样好,至少这个局部的小功能是这样的。请体会一下知识的重要性。
 
解决问题的另外一个基础条件是经验。这是在长期职业工作中逐步积累起来的一种敏锐的判断力和识别能力。这种职业的嗅觉或者直觉往往可以在第一时间告诉工程师自己,什么是正确的方法。但是遗憾的是,经验这个东西除了自己逐步积累,或者用功的去积累,好像没有什么别的办法可以替代。
 
基于上面的讨论:解决问题的步骤,问题的类型,解决问题的条件,在实际工作中解决问题时,我归纳出需要注意的事项有三点,它们是:行不行,好不好和对不对。很遗憾的是,在实际工作中这三点往往被忽略,或者没有主动的使用,即便是用上了,也是下意识的。下面依次讨论这三点。
 
1.行不行
所谓行不行就是,需要考虑面临的问题是可以解决的么?这个解决有两个层面的意思,第一个层面是能不能解决这个问题,第二个层面是我能不能解决这个问题。基于上面的介绍,一般来说或者大部分情况下,程序员是不会明显的体会到这个步骤的存在的。因为接受的开发任务都是被过滤过的,大部分情况下程序员自己都是知道应该怎么去完成工作的。所以这个步骤往往被忽略了。还有一种认识是,行不行这个问题往往是存在于一些比较难的或者大的问题中。比如考察项目的可行性,等等。这当然是事实,但是在实际工作中,在处理一些小问题时(或者相对较小的问题),也会需要程序员带着这种意识,去解决问题,从而避免自己在第一时间犯错误。这时行不行这个步骤的作用可以理解为,这个问题是否值得或者是否应该去解决。下面举几个例子说明一下。
 
第一次例子是在一个对日外包工作做得一个通信程序的项目。预计的工作量是三个程序员两个月完成,应该说是一个不起眼的小项目。但是日方在工作环境上提出了苛刻的要求,这些要求导致通信程序的调试将无法从服务器得到任何可用信息。另一个问题是中方项目经理对通信程序的开发经验不足,没有要求日方提供与服务器端通信的协议文档。在这样的前提下,两次会议先后经过三个项目经理,一个部门经理,一个技术总监的参与下,还是认为项目是可以完成的。最后实际耗费的开发时间是七个月,日方限制的条件全部作废,并且提供了通信协议文档,这才算勉强完成。这应该是一个教训,我觉得其最大原因可能是对日外包公司有一种奴性的文化,对员工提出的正确意见完全不予采纳,盲目强调下级对上级的服从,同时还唯日方要求为正确。
 
第二个例子也是一个外包的活。客户提出的要求是改进一下现有的程序,通过进一步了解需求后发现两个情况:
1.  修改的原因是性能问题
2.  客户很快就会实施新的系统
由于改善性能的前提是需要明确性能的瓶颈在哪里,根据对实际的工作环境的了解,发现这个工作做起来会比较困难。其次性能是否有足够的提高没有把握。所以这项目最后评估下来是不做了。
 
第三个例子是当初确定Entity Model Studio是否支持图形化的UML建模功能。这个判断相对上面两个例子就复杂一些了。正方的理由是:
1.  Entity Model Studio从最初开始的定位就需要支持
2.  通过市场调研为了确立优势,也需要支持
3.  我们有自己的一些理解和特色的功能需要图形化的设计界面作为支持
而反方的理由基本上只有一个,那就是WideUnion的开发团队是否可以胜任这个开发任务。相对上面两个例子,是否支持这个决定事实上不是通过一次,两次沟通就完成的。而是在此后的一个相当长的时间段中才逐步完成的。最终还是认为需要支持,当然事实上我们也做到了。最终确定支持的理由来自同类产品的比较,Entity Model Studio产品的远景和定位,以及开发技能的积累和研发难点的突破。
 
上面的三个例子所涉及的问题都不是很大的问题,但是复杂程度有差异,做出判断的理由不同,最终的结果也各有不同。所以提醒开发者在类似场合下还是需要认真对待这个步骤的。
 
2.好不好
所谓好不好是指最终选择的用来解决问题的方法是否为最优的或者是否为足够好。作为一个独立的用于帮助程序员判断自己选择的方法是否足够好的提问,这是一个很有挑战的步骤,对工程师的能力是一个综合的考验,当然也是一个富有乐趣的工作。在实际工作中,工程师在第一判断下所选择的方法往往就是应该满足工作要求的,从这个角度来说就是足够好的。之所以出现这个情况是由于上面介绍的大小环境决定的。那么在这样的前提下,还有必要再独立的用好不好这样的提问步骤来帮助我们确认所选择的方法是否足够好呢?
 
回答当然是肯定的,有必要。我们从上文提到的问题解决步骤开始解答这个提问。作为解决问题的第一步,需要考察面临的问题是否可以解决。作为最直接也是最简单的回答就是给出一个可以解决该问题的方法。这样我们在解决这个问题的过程中就得到了第一个解。但是这个解往往是不能用于实际工作中的,因为这个解只是为了确认问题可解决,而在解的质量上可能会存在缺陷或者在可行性上存在难度,从而使得这个解在用于实际工作中时,往往不能满足工程上的要求。于是我们在解决问题的下一个步骤中需要在第一个解的基础上做优化或者再找出一个更好的解。这样会得到第二个解,基于第二个解,我们才真正开始着手解决问题。但是在这个解决过程中,我们会发现当前对问题的认识有可能是不全面或者错误的,也有可能若干细节我们还没有考虑到。这个时候需要对第二个解做修改,改进或者重新寻找第三个解。所以从这个步骤来说,我们在解决同一个问题的过程中很有可能会得到两个,三个解或者若干个解。因此面临好不好这个问题是经常性的。
 
这里再用上面提到的魔法门点绳索的例子来说明一下如何查找不同的解。在寻找新的解时,首先需要明确一点,我为什么需要去寻找新的解,或者说寻找新的解的理由是什么。这个步骤对开发者能力是有要求的,需要对具体的问题,环境和要求综合考虑。就本例来说寻找不同解的原因主要是两个。第一个是原来的解用到了状态图,这部分内容来自编译原理的自动机。显然没有学到这部分知识的程序员要用这个解是有困难的,也就是说这个解对使用的人是有要求的。第二个原因是来自另一个游戏中的场景。在暗黑2中为了解救凯恩首先需要在石头矿野中按照指定的次序点击五根石柱,从而激活一个传送门来解救凯恩。这里点击五根石柱和点击五根绳索两个场景几乎一模一样,唯一的区别是魔法门中点击的次序玩家是不知道的,而暗黑中点击的次序是知道的。这个差异是让我尝试找出不同解的第二个原因。
 
下面就直接给出新的解法。将绳索看作是按钮,开始时只允许第一个按钮可以点击,其他按钮为disable,当然这个disable不是不让点,而是说点了没有效果。玩家点击第一个绳索时,就enable下一个绳索,这个enable是指点击了有效果。然后玩家点击下一个绳索时,再enable下下一个绳索。直至所有绳索被点击后触发剧情。这个解对书本知识的要求可能几乎没有。
 
还可以给出第三个解法。这个解法需要我们再定义一个新的数组(或者链表),这个数组用于保存玩家过去五次点击鼠标的数据。但是这个数组需要用一个与众不同的数来初始化,这里可以选用-1,而绳子的编号是0,1,2,3,4,注意这点。当玩家每次点击鼠标时,将玩家点击的绳子的序号插入到最后,然后数组中的原来数据依次往前移一个位置,这样原来第一个元素就从数组中移出去了,不在数组中了。实际上这就是一个队列的基本操作,注意这里使用到了数据结构的知识。然后再将这个数组中的数据和data数组中的数据比较,如果一致就通过,否则继续等待玩家的输入。关于寻找不同解的其他例子可以参考我的其它博文,比如:
http://blog.youkuaiyun.com/binarytreeex/article/details/1595936
http://blog.youkuaiyun.com/binarytreeex/article/details/1585550
 
再简单说明一下,上面的例子在推广到一般情况下的应用。寻找不同的解首先需要一个理由,开发者需要根据自己的实际情况去发现这样的理由。一般来说这个理由往往是某一个存在的缺陷或者瑕疵。在开始寻找不同的解时,需要明确主要矛盾是什么,或者说新的解的目的是什么。如果把,团队成员的技能水平,成员人数,时间,问题难度,开发工具,可利用的资料,完成的质量数量等等统称为外部条件,那么当外部条件发生变化时,寻找不同的解可以帮助我们任然可以完成原来的目标和任务。需要强调一下,在我的观念中,根据不同条件,要求和场合找出不同的解来更好的达到目的,是一个工程师应该具备的能力,而且是一个很重要的能力。
 
下面说一下如何来判断一个解是否更好。如果面临的是一个算法问题,我的建议是时间复杂度放在优先考虑的地位,可以为了性能牺牲空间,只要不是巨大的牺牲空间都是可以接受的。如果是非算法问题,那么考虑的因素就会多一些,情况会有点复杂。我的建议是首先考虑选的方法是否可以满足功能的要求,其次是考虑稳定性和可靠性。选择的方法可以在各种条件或者情况下相对更可靠稳定的工作。然后是选择的方法是否够简单,够易于理解。应该说前面两个是硬指标,是必须满足的,而排在第三个标准就是简单和易于理解,这说明我对这点非常重视。其原因是简单和易于理解的方法有以下几个优点:
1.  可以得到的更好的质量和可靠性。
2.  便于实现和修改
3.  更少的调试和测试的工作量
4.  对编码人员的要求可以相对低一些
 
当然还有其他的一些可供参考的标准,同行们可以根据自己面对的实际问题和场景自己来确定。
 
3.对不对
对不对的意思是指,我们做的对么?这个步骤可能最有可能或者最高频被忽略掉的。对于一个有经验的程序员来说,一般不会去选择一个对错不确定的方法来解决问题。或者更恰当的表述是,有经验的程序员都是在认为自己正确的前提下才会去做出选择。而问题就恰好出在这里,自己认为正确并不表示事实上就是对的。这里需要明确一下,如果一个程序员需要一个独立的步骤来确认自己的选择是否正确,那么这个程序员面临的问题是比较难的或者比较复杂的,否则是没有必要这么做的。
 
最理想的确认自己的选择是否正确,是象数学证明那样得到证明,当然这并不容易做的。因为我们面临的问题往往不是一个可以用数学来描述的命题。其次是寻找足够的充分的理由来说明正确性,这时经验的作用至关重要。我曾在实际工作中发现这么一个情况。一个开发者按照我的要求去实现一个功能。等我去查看进度的时候发现解决的过程基本顺利,编码也完成,但是问题出在解的正确性的保证上。这个开发者对正确性的保证是用调试和测试来完成的。由于使用到了一个自己设计的算法,所以只靠调试和测试来确保正确是不对的,象这类问题的正确性的保证首先是算法正确性需要得到证明。调试和测试只是例证,不是推演证明,只能作为辅助手段。这个步骤有可能被很多开发者忽略,或者没有意识到。就这个例子来说,经过沟通后发现所采用的算法的正确性的证明难度太大,所以重新设计了一个易于理解的算法来完成功能。如果不这么做的话,完成的软件就有可能会表现为不稳定,时不时出错,导致用户觉得质量太差。
 
作为一个解决问题的思维和沟通上的方法,对自己提问对不对也是很有用处的。在一次和其他部门的同事配合解决问题时就是如此。那次的背景情况如下:我的同事是做PHP的,有经验但是不太强;我是做C的,做过通信,但是我刚去什么情况都不了解。C写的通信程序拼接字符串,然后通过socket直接向PHP服务器的端口发送字符串,以模拟http通信。现在问题来,测试程序发现数据没有保存到数据库中。PHP一侧有日志,从日志看数据没有发送过去,而C这边也有日志,日志表明数据发送了。于是双方各持一词,都怀疑对方的程序问题。那么谁出问题了?这次遇到的问题的关键是我刚去那个公司上班,接手时也没有交接,直接通过读程序了解相关的事情。所以无论从哪一个角度讲,我都不是很清楚,再说我对PHP一窍不通,从而给沟通和解决问题带了难度。这个时候就需要冷静的问一下自己,我怀疑对方的程序有问题,那么我有证据么?或者说我的判断对么?于是和相关的PHP程序员沟通了一下,要求在服务器端的PHP代码中独立加入写文件的代码,并且这部分代码是不受如何业务逻辑干扰的。测试后发现日志文件可以生成,从而证明数据发送到了服务器端。然后,还是使用这个方法在PHP代码的不同位置,加入写日志文件的代码,最终找出了问题代码的位置。
 
这次就写到这里,下一篇还是继续讨论如何解决问题这个话题。下一次讨论的是在遇到一个自己不知道如何解决的问题时应该采取什么样的方法和思路最终解决该问题。下一篇的题目是问题解决篇(下)。如何解决问题这个话题原本只打算写一篇的,现在最终会写成三篇,应该说这在实际工作中是一个很有份量也很有实际价值的话题。我相信靠博文分享是不够的,如果有兴趣的可以加我的QQ群,群号是:244054966,这个群创业的人多一点;231233168,这个群新手多一点。希望能在群中和同行们互相分享共同提高。加入时请说明:优快云博文
全功能tgbot/Telegram机器人多功能有后台版源码 trx兑换 闪兑 关键字监控 群管 usdt监控 余额查询 推广分享 等几乎常见的tg机器人功能都有。全功能tgbot/telegram机器人多功能有后台版源码-打包好的可以直接上手。 阅读详情

相关推荐

Zlib1.2.11源码编译(Win10+VS2019)

下载 下载网址: zlib Home Site 得到文件: 解压缩到“D:\SourceCodes\zlib-1.2.11” 使用CMake配置、生成并打开项目 将CMakeLists.txt拖入CMake,配置(Configure): 生成(Generate) 打开项目(Open Project),CMake调用VS2019打开项目 生成debug版本 构建项目ALL_BUILD。成功生成debug版本 在“D:\Sourc...

Alexabc3000的专栏 1892

十八年开发经验分享(三)问题解决篇(中)

关于本系列文字的来源,初衷和内容定位可以参考第一篇的开头部分,链接地址如下: http://blog.youkuaiyun.com/binarytreeex/article/details/8174445 http://www.cnblogs.com/WideUnion/archive/2012/11/12/2766397.html 本文前一篇地址如下,感兴趣的可以访问下面的连接: http://...

xuela-net 300

从爱好者到工程师:如何低成本体验RFSoC ZU47DR?性能实测与避坑指南

本文详细介绍了如何低成本体验赛灵思RFSoC ZU47DR芯片,包括二手开发板选购、租赁服务、精简开发环境搭建等实用方案。通过性能实测与避坑指南,帮助爱好者和工程师在有限预算下充分利用这款集成了ARM处理器和FPGA的高性能芯片,降低开发门槛。

weixin_42525005的博客 214

解决问题的心得(一)

最近遇到好多问题,解决起来不能得心应手.多亏别人帮助,所以我现在想写一篇总结心得 问题一: java.lang.NullPointerException at com.urundp.corona.metadata.quality.schedule.MeatdataTask.getMeatdata(MeatdataTask.java:40) at com.urundp.coron...

sky 1597

从0到全栈:C#/.NET/.NET Core终极学习路线——2025年开发者必修的12个阶段与30个实战项目

【代码】从0到全栈:C#/.NET/.NET Core终极学习路线——2024年开发者必修的12个阶段与30个实战项目。

墨夶的博客 2041

【Claude】Auto Mode 触发安全分类器拦截的三种错误变体及对应处理 bug报错已解决

深度解析Claude Auto Mode安全分类器拦截的三种变体:内容拒绝、操作中断、累积触发,含完整排查流程与绕过策略。

博客 7578

测试环境不稳定咋解决,功能时好时不好,开发这么说环境不稳定, 我们测试怎么办?

不能开发说不稳定,我们就不管了,我们要去尝试找到产生这个不稳定的原因, 首先看看开发环境是否也会有这个问题,如果开发环境没有,测试环境有, 那就比较两个环境的差异性(配置、系统、软硬件的差异性),排除差异后,看看是否还会不稳定,如果测试环境和开发环境都不稳定,这个时候提交一个偶现的bug,让开发找到可能的原因, 总之一句话,遇到不稳定出现的bug,一定不要轻易放过,要寻根问底,找到原因, 不然项目...

测试小小的博客 2864

STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)

本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可。 1、键盘原理图: 原理举例:先把 F0-F7 内部拉高,这样这个8个引脚都是高电平,然后就进行列扫描。例如:假如按下3按钮,Y3 列扫描,把F4先拉低,然后读取F0-F3的状态,就会读出为1110,这就可 以知道是F3行拉低了,同时这时候是程序控制F4拉低的,这样就可以知道是F4列导致它转态变化了的,这样就可以定位出是F4列F3行的按键按下了;其他的列也是这样子扫描

lhh_qrsly的博客 7058

2018北京3月份java面试题(3~5年工作经验)

仅提供面试知识点,详细内容后续补充一、java基础     1.final修饰方法、类、成员变量的特点     2.集合框架 ArrayList,HashMap,ConcurrentHashMap(这三个问到的频率最高)      知识点:底层数据结构,知道哪些是线程安全的,线程不安全的,最好阅读一下源码,构造方法有几个,默认参数。(jdk1.8和之前的版本区别)      ConcurrentH...

有点皮的博客 4889

ABAP 里的 XML 与 JSON 处理,一套从接口落地到 Clean Core 的完整参考

ABAP 里的 XML 和 JSON 处理并不只是几段工具类调用。iXML、sXML、、XCO、、code page conversion、GZIP、对象序列化,这些能力背后对应的是不同的数据规模、访问模式、接口契约和运行时边界。小报文、复杂树结构、需要修改节点,iXML 很顺手。大报文、顺序读写、内存敏感,sXML 更可靠。ABAP 结构和 XML、JSON 之间要做标准转换,是主干。现代 JSON API、ABAP Cloud、命名转换,XCO 值得优先考虑。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 224

prplOS amx-fxgi调试-订阅subscribe

本文分析了prplOS中amx-fxgi订阅功能(subscribe)的实现与调试过程。通过梳理订阅流程发现,默认订阅失败主要由于acl规则限制导致。文章详细介绍了订阅的两个关键步骤:建立GET长连接和POST设置订阅路径,并通过修改代码绕过acl验证成功实现订阅功能。最终验证了在同一连接下订阅多个路径及实时接收状态更新的可行性,有效降低了设备查询负载。该方案为prplOS的实时数据监控提供了优化思路。

四儿家的小祖宗的博客 329

JAVA疑难问题排查、解决经验总结(Linux系统)

Java疑难问题的排查、解决有一定的步骤可循。大概就是程咬金的三板斧。按照对应的步骤对着问题砍下去,很多问题就都迎刃而解了。接下来,就根据个人的理解和经验将几类问题的解决步骤总结一下。1 先排查运行环境首先要强调的是,有些问题不是疑难问题,或是伪疑难问题。其实就是些运行环境的问题,磁盘空间、内存大小、CPU占用、数据库连接、用户权限等问题。如果有人向我反馈某个软件启动不了、启动后运行很慢、启动了但...

weilan06的博客 3538

零基础入门simulink建模仿真--基于Simulink的QPSK调制与解调仿真建模示例

QPSK是一种相位调制技术,将两个比特映射到一个符号上,每个符号对应四个可能的相位之一(0°、90°、180°、270°)。通过Simulink,我们可以通过模块化的建模方式实现QPSK的调制和解调过程,并观察信号在信道中的传输效果。通过本指南,我们介绍了如何基于Simulink搭建一个完整的QPSK调制与解调仿真模型,并进行仿真和性能评估。背景介绍:理解QPSK调制与解调的基本原理及其应用。所需工具和环境:列出进行QPSK仿真所需的工具和环境。步骤详解。

amy_mhd的博客 1306

十八年开发经验分享(04)问题解决篇(下)

关于本系列文字的来源,初衷和内容定位可以参考第一篇的开头部分,链接地址如下: http://blog.youkuaiyun.com/binarytreeex/article/details/8174445 http://www.cnblogs.com/WideUnion/archive/2012/11/12/2766397.html 本文前一篇地址如下,感兴趣的可以访问下面的连接: http://bl

BinaryTreeEx的专栏 3568

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

十八年开发经验分享(四)问题解决篇(下)

关于本系列文字的来源,初衷和内容定位可以参考第一篇的开头部分,链接地址如下: http://blog.youkuaiyun.com/binarytreeex/article/details/8174445 http://www.cnblogs.com/WideUnion/archive/2012/11/12/2766397.html 本文前一篇地址如下,感兴趣的可以访问下面的连接: http://bl

java_7star的专栏 1297

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

问题战略[置顶] 十八年开发经验分享(四)问题解决篇(下)

最近一直在研究问题战略之类的问题,下午正好有机会和大家分享一下. 关于本系列文字的源来,衷初和内容定位可以考参第一篇的头开部份,链接址地如下: http://blog.youkuaiyun.com/binarytreeex/article/details/8174445 http://www.cnblogs.com/WideUnion/archive/2012/11/12/276...

weixin_30784945的博客 86

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

每位开发者都该看:如何在四十岁后还能继续从事软件开发?

这是一个 42 岁的开发者所写经验分享文章.并且列出一些他 18 年多身为软件开发者的经验谈.许多部分看完后都会希望自己当时就能够了解,所以很推荐不论是新手或是老手都要好好阅读这一篇文章。故事很长,一切从 1997 年开始讲起.那是一个令人怀念的年代(FF7 发售,微软入股苹果,铁达尼号电影上映),那是作者第一年身为软件开发者的年份。当时他的第一份工作是从事 ASP 并且在微软的平台上面使用 Ed...

欢迎来到技术宅的博客 1350

如何在40岁后继续做软件开发?

这是一个 42 岁的开发者所写经验分享文章.并且列出一些他 18 年多身为软件开发者的经验谈.许多部分看完后都会希望自己当时就能够了解,所以很推荐不论是新手或是老手都要好好阅读这一篇文章。故事很长,一切从 1997 年开始讲起.那是一个令人怀念的年代(FF7 发售,微软入股苹果,铁达尼号电影上映),那是作者第一年身为软件开发者的年份。当时他的第一份工作是从事 ASP 并且在微软的平台上面使用 Ed

公众号 2346

每个程序员必看:如何在40岁后继续做软件开发?

点击标题下「瑞才科技」可快速关注这是一个 42 岁的开发者所写经验分享文章.并且列出一些他 18 年多身为软件开发者的经验谈.许多部分看完后都会希望自己当时就能够了解,所以很推荐不论是新手或是老手都要好好阅读这一篇文章。故事很长,一切从 1997 年开始讲起.那是一个令人怀念的年代(FF7 发售,微软入股苹果,铁达尼号电影上映),那是作者第一年身为软件开发者的年份。当时他的第一份工作是从事 ASP

公众号 1166

如何在四十岁后还能继续做软件开发?

导读:   这是一个 42 岁的开发者所写经验分享文章.并且列出一些他 18 年多身为软件开发者的经验谈.许多部分看完后都会希望自己当时就能够了解,所以很推荐不论是新手或是老手都要好好阅读这一篇文章。   故事很长,一切从 1997 年开始讲起.那是一个令人怀念的年代(FF7 发售,微软入股苹果,铁达尼号电影上映),那是作者第一年身为软件开发者的年份。当时他的第一份工作是从事 ASP 并且在微

ymmz_2016的博客 1091
上一篇: 十八年开发经验分享(02)问题解决篇(上)
下一篇: 十八年开发经验分享(04)问题解决篇(下)
BinaryTreeEx
博客等级 码龄25年 849粉丝 20原创
评论 26
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值