该代码是活的还是死的。 第一部分 对象

代码是一种思想。 出现任务,开发人员考虑如何解决该问题,如何在功能和类中表达需求,如何使其成为朋友,如何实现严谨和正确性以及如何正确开展业务。 实践,技术,原则,模式和方法-一切都需要考虑,一切都需要记住。


随之而来的是,我们看到了经理,助手,服务,控制器,选择器,适配器,吸气剂,设置器和其他恶魔的普遍流行:所有这些都是无效的代码。 他束手无策。


我建议以这种方式与之抗争:您需要以自然语言将程序呈现为文本,并对其进行相应的评估。 这是怎么回事以及发生了什么-在文章中。


循环目录


  1. 对象
  2. 动作和属性
  3. 文字编码

序言


我的经验不高(大约四年),但是我工作的越多,我的理解就越多:如果该程序不可读,则毫无意义。 早已众所周知并提醒人们注意-该代码不仅现在解决了一些问题,而且以后又解决了:支持,扩展,更正了它。 而且,他总是:读。


毕竟,这是文本。


代码作为文本的美观是周期中的关键主题。 这里的美学是杯,我们透过它看事物,然后说,是的,很好,是的,很漂亮。


在美观和可理解性方面,言语至关重要。 要说: “目前,由于血液中乙醇含量高,我的感知处于沉闷状态”“我喝醉 了”根本不一样。


我们很幸运,程序几乎完全由文字组成。


假设您需要创建“一个具有健康和法术力的角色,他可以行走,攻击,使用咒语”,并且您可以立即看到:有对象 (字符,健康,法术力,咒语), 动作 (行走,攻击,使用)和属性 (角色具有健康,法力和施法速度)-所有这些都将被命名为:类,函数,方法,变量,属性和字段,总之,是编程语言所分割的所有内容。


但是我不会区分类与结构,字段与属性,方法与函数:作为叙述的一部分的字符不依赖于技术细节(可以将其表示为引用或重要类型)。 本质上不同的东西:这是一个角色,他们称他为Hero (或Character ),而不是HeroDataHeroUtils


现在,我将带大家欣赏一下美学,并展示当今如何编写一些代码以及为什么它远非完美。


对象


在C#中(不仅是),对象-放置在堆上的类的实例在其中生活了一段时间,然后垃圾收集器将其删除。 也可以在堆栈或关联数组等上创建结构。 对我们来说,它们是:类名,名词。


代码中的名称(如一般名称)可能会造成混淆。 是的,您很少看到一个丑陋的名字,而是一个漂亮的物体。 特别是如果是Manager


经理而不是对象


UserServiceAccountManagerDamageUtilsMathHelperGraphicsManagerGameManagerVectorUtil


在这里不是主要的准确性和有形性,而是模糊不清的地方,在雾中留下了阴影。 对于这样的名称,可以允许很多。


例如,在任何GameManager您都可以添加与游戏游戏逻辑相关的任何内容。 六个月后,将会出现技术上的奇异之处。


或者,碰巧,您需要使用facebook。 为什么不将所有代码放在一个地方: FacebookManagerFacebookService ? 听起来很诱人,但这种含糊的意图会造成同样含糊的决定 。 同时,我们知道Facebook上有用户,朋友,消息,群组,音乐,兴趣爱好等。 够了!


不仅有足够的单词:我们仍在使用它们。 仅在普通语音中,不在程序之间。


不是GitUtils ,而是IRepositoryICommitIBranch ; 不是ExcelHelper ,而是ExcelDocumentExcelSheet ; 不是GoogleDocsService ,而是GoogleDocs


每个主题区域都充满了对象。 “这些物体被巨大的空隙标记”“心脏在疯狂跳动”“房子在站立” –这些物体的动作,感觉,易于想象; 他们在这里某处,有形而密集。


同时,您有时会看到以下内容:在Microsoft/calculator存储库SetPrimaryDisplay ,使用以下方法: SetPrimaryDisplayMaxDigitsReachedSetParentDisplayTextOnHistoryItemAdded ...


(不过,我记得曾经见过 UtilsManager ...)


它是这样发生的:我想用新的行为扩展List<>类型,并且ListUtilsListHelper诞生了。 在这种情况下,最好使用扩展方法ListExtensions更好,更准确:它们是概念的一部分,而不是过程的转储。


少数例外之一是OfficeManager作为帖子。


其余的...如果程序包含此类单词,则不应对其进行编译。


行动而不是对象


IProcessorILoaderISelectorIFilterIProviderISetterICreatorIOpenerIHandler ; IEnableableIInitializableIUpdatableICloneableIDrawableILoadableIOpenableISettableIConvertible


在这里,本质的本质是一个过程,而不是一个概念,并且代码再次失去了图像和可读性,通常的单词被人为的代替。


更活泼的是ISequence ,不是IEnumerable ; IBlueprint ,而不是ICreatorIButton而不是IButtonPainter ; IPredicate ,而不是IFilterIGate ,不是IOpeneable ; IToggle ,不是IEnableable


一个好的故事讲述的是人物及其发展,而不是创作者的创作方式,建造者的建造以及画家的绘画。 一个动作不能完全代表一个对象。 ListSorter不是SortedList


DirectoryCleaner为例,该对象用于清理文件系统上的文件夹。 优雅吗? 但是我们永远不会说: “要求文件夹清洁程序来清洁D:/测试” ,总是: “清洁D:/测试” ,因此使用Clean方法的Directory看起来更自然,更接近。


一个更生动的案例更有趣:.NET中的FileSystemWatcher是报告更改的文件系统观察者。 但是,为什么整个观察者(如果变更本身可以报​​告它们已发生)呢? 此外,它们必须与文件或文件夹密不可分地链接,因此也应将它们放置在DirectoryFile (使用Changes属性可以调用file.Changes.OnNext(action) )。


这样的口头名字似乎证明了Strategy设计模式的合理性,指示“封装算法家族” 。 但是,如果我们找到故事中存在的真实对象而不是“算法家族” ,那么我们将看到该策略只是一个概括。


为了解释这些以及许多其他错误,我们转向哲学。


存在先于本质


MethodInfoItemDataAttackOutputCreationStrategyStringBuilderSomethingWrapperLogBehaviour


这样的名字由一件事统一起来:它们的存在是基于细节的。


碰巧某些事物会很快干扰任务:某些事物丢失或存在,但并非某种事物。 然后您会想: “现在可以做X的事情会帮助我” -这就是生存的构想。 然后,为了做X,编写了XImpl这就是实体的外观。


因此,不是IArrayItem而是IIndexedItemIItemWithIndex更为常见,或者说,在反射API中,我们只看到有关它的信息MethodInfo ),而不是方法Method )。


一个更真实的方法:面对生存的需求, 找到一个实现它实体,并且由于这是它的本质,所以找到其他实体。


例如,他们希望在不创建中间实例的情况下更改string类型的值-事实证明这是StringBuilder形式的直接解决方案,而我认为更合适MutableString


调用文件系统:不需要DirectoryRenamer重命名文件夹,因为一旦您同意Directory对象的存在,该操作已经在其中,您只是在代码中找不到相应的方法。


如果要描述如何进行锁定 ,则无需弄清楚这是ILockBehaviour还是ILockStrategy ,这要容易得多ILock (使用返回IDisposableAcquire方法)或ICriticalSection (使用Enter )。


这也包括各种DataInfoOutputInputArgsParams (很少是State )-完全没有行为的对象,因为它们被认为是单面的。


在主要存在的地方,商与一般相混合,并且对象的名称令人困惑-您必须通读每一行并找出角色去向何处以及为什么只有他的Data


奇异分类法


CalculatorImplAbstractHeroConcreteThingCharacterBase


出于上述相同的原因,有时我们会看到对象,这些对象在层次结构中被精确地指出。 再次,生存急于前进,我们再次看到瞬时需求是如何仓促地涌入代码中,而不考虑后果。


毕竟,真的有一个人( Human )-基本人的继承人( HumanBase )吗? 但是,当Item继承AbstractItem时如何?


有时,他们想要显示出不是Character ,而是某种“原始”相似性-CharacterRaw。


ImplAbstractCustomBaseConcreteInternalRaw不稳定,建筑模糊的标志,就像第一个场景中的枪一样,它肯定会在以后拍摄。


重复次数


对于嵌套类型,会发生这种情况: RepositoryItem中的RepositoryWindow WindowStateHero HeroBuilder


重复贯穿意义,加剧缺陷,只会增加文本的复杂性。


冗余部分


为了同步线程, ManualResetEvent通常与以下API结合使用:


 public class ManualResetEvent { //   —  `EventWaitHandle`. void Set(); void Reset(); bool WaitOne(); } 

每次,个人而言,我都必须记住SetReset (语法不舒服)有何不同,以及在使用流时上下文中的“手动重置事件”通常什么。


在这种情况下,比起编程(而不是日常生活)更容易使用隐喻:


 public class ThreadGate { void Open(); void Close(); bool WaitForOpen(); } 

当然没有什么可混淆的!


有时会变得荒谬:指定项目不仅是Items ,还必须是ItemsListItemsDictionary


但是,如果ItemsList不好笑,那么Spring的 AbstractInterceptorDrivenBeanDefinitionDecorator ItemsList 。 这个名字中的单词是缝制巨大怪物的破布。 虽然...如果这是一个怪物,那么HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitorHasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor ? 希望遗产


除了类和接口名称外,还经常在变量或字段中遇到冗余。


例如,类型为IOrdersRepository的字段称为_ordersRepository 。 但是,报告存储库已提交订单有多重要? 毕竟,容易得多_orders


碰巧在LINQ查询中,他们编写了lambda表达式的完整参数名称,例如Player.Items.Where(item => item.IsWeapon) ,尽管我们已经通过查看Player.Items理解了此项。 。 在这种情况下,我总是喜欢使用相同的字符xPlayer.Items.Where(x => x.IsWeapon) (如果这些是函数内部的函数,则继续到yz )。


合计


我承认,从这样的开始,要找到客观事实并不容易。 例如,有人会说:写Service或不写Service是有争议的,微不足道的,有品位的,如果有效,它有什么区别?


但是你可以用一次性杯子喝!


我坚信内容的路径是通过表单,如果不看这个思想,它似乎就消失了。 在该程序的文本中,所有操作均以相同的方式进行:样式,气氛和节奏有助于表达自己,而不会感到困惑,而是可以理解且功能丰富。


物体的名称不仅是它的面孔,而且是自我。 它确定是空灵的还是饱和的,抽象的还是真实的,干燥的还是动画的。 名称在变化-内容在变化。


在下一篇文章中,我们将讨论这一内容及其发生的情况。

Source: https://habr.com/ru/post/zh-CN447404/


All Articles