-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
10794 lines (9021 loc) · 909 KB
/
atom.xml
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[The Hard Way Is Easier]]></title>
<link href="http://cs50Mu.github.io/atom.xml" rel="self"/>
<link href="http://cs50Mu.github.io/"/>
<updated>2021-02-05T14:15:19+08:00</updated>
<id>http://cs50Mu.github.io/</id>
<author>
<name><![CDATA[linuxfish]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[「Applying UML and Patterns」读书笔记]]></title>
<link href="http://cs50Mu.github.io/blog/2021/02/05/reading-notes-of-applying-uml-and-patterns/"/>
<updated>2021-02-05T12:08:00+08:00</updated>
<id>http://cs50Mu.github.io/blog/2021/02/05/reading-notes-of-applying-uml-and-patterns</id>
<content type="html"><![CDATA[<h2>「Applying UML and Patterns」读书笔记</h2>
<h3>Inception</h3>
<p>前期评估</p>
<p>the idea is to do just enough investigation to form a rational, justifiable opinion of the overall purpose and feasibility of the potential new system, and decide if it is worthwhile to invest in deeper exploration</p>
<p><strong>It is to decide if the project is worth a serious investigation (during elaboration), not to do that investigation.</strong></p>
<h4>Use Cases</h4>
<p>Informally, use cases are text stories of some actor using a system to meet goals.</p>
<p>the essence is discovering and recording functional requirements by writing stories of using a system to fulfill user goals; that is, cases of use</p>
<h3>Elaboration Iteration 1Basics – Domain Models</h3>
<h4>What is a Domain Model?</h4>
<p>A domain model is a visual representation of conceptual classes or real-situation objects in a domain.</p>
<p>Domain models have also been called conceptual models (the term used in the first edition of this book), domain object models, and analysis object models.</p>
<p>Applying UML notation, a domain model is illustrated <strong>with a set of class diagrams in which no operations (method signatures) are defined.</strong> It provides a conceptual perspective. It may show:</p>
<ul>
<li>domain objects or conceptual classes</li>
<li>associations between conceptual classes</li>
<li>attributes of conceptual classes</li>
</ul>
<p>A domain model shows real-situation conceptual classes, <strong>not software classes.</strong></p>
<h4>How to Find Conceptual Classes?</h4>
<ul>
<li>Reuse or modify existing models.</li>
<li>Use a category list. 一些默认建议,非常好</li>
<li>Finding Conceptual Classes with Noun Phrase Identification. 通过名词来找灵感
<ul>
<li><strong>use cases</strong> are one rich source to mine for noun phrase identification.</li>
</ul>
</li>
</ul>
<blockquote><p>Perhaps the most common mistake when creating a domain model is to represent something as an attribute when it should have been a conceptual class.</p></blockquote>
<p>If we do not think of some conceptual class X as a number or text in the real world, X is probably a conceptual class, not an attribute. 类比现实世界</p>
<h4>Why Use ‘Description’ Classes?</h4>
<p><img src="http://cs50Mu.github.io/images/post/description-class.jpg" alt="" /></p>
<p>item的描述是一直存在的,但item可能会卖光</p>
<p>The need for description classes is common in sales, product, and service domains. It is also common in manufacturing, which requires a description of a manufactured thing that is distinct from the thing itself.</p>
<h4>Associations</h4>
<p>An association is a relationship between classes (more precisely, instances of those classes) that indicates some meaningful and interesting connection</p>
<p>Multiplicity defines how many instances of a class A can be associated with one instance of a class B</p>
<p><img src="http://cs50Mu.github.io/images/post/association-multiplicity.jpg" alt="" /></p>
<h4>Attributes</h4>
<p>An attribute is a logical data value of an object.</p>
<p>Informally, most attribute types should be what are often thought of as “primitive” data types, such as numbers and booleans. The type of an attribute should not normally be a complex domain concept, such as a Sale or Airport. 类属性应该是基础类型,不应该是复杂的自定义领域类型(这种应该用Association来表达)</p>
<p>Relate conceptual classes with an association, not with an attribute.</p>
<h4>Conclusion: Is the Domain Model Correct?</h4>
<p>There is no such thing as a single correct domain model. All models are approximations of the domain we are attempting to understand; the domain model is primarily a tool of understanding and communication among a particular group. A useful domain model captures the essential abstractions and information required to understand the domain in the context of the current requirements, and aids people in understanding the domainits concepts, terminology, and relationships. 没有“正确”的模型</p>
<h3>Elaboration Iteration 1Basics – System Sequence Diagrams</h3>
<h4>What are System Sequence Diagrams?</h4>
<p>A system sequence diagram is a picture that shows, for one particular scenario of a use case, the events that external actors generate, their order, and inter-system events. All systems are treated as a <strong>black box</strong>; the emphasis of the diagram is events that cross the system boundary from actors to systems.</p>
<p>System behavior is a description of what a system does, without explaining how it does it. 用于描述系统是做什么的,而不是如何做</p>
<h3>Elaboration Iteration 1Basics – Operation Contracts</h3>
<h3>Elaboration Iteration 1Basics – Requirements to DesignIteratively</h3>
<p>Iteratively Do the Right Thing, Do the Thing Right 做对的事 和 把事做对</p>
<p>The requirements and object-oriented analysis has focused on learning to do the right thing; that is, understanding some of the outstanding goals for the case studies, and related rules and constraints. By contrast, the following design work will stress do the thing right; that is, skillfully designing a solution to satisfy the requirements for this iteration.</p>
<h3>Elaboration Iteration 1Basics – Logical Architecture and UML Package Diagrams</h3>
<h4>What is the Logical Architecture? And Layers?</h4>
<p>The logical architecture is the large-scale organization of the software classes into packages (or namespaces), subsystems, and layers. <strong>It’s called the logical architecture because there’s no decision about how these elements are deployed across different operating system processes or across physical computers in a network</strong></p>
<p>A layer is a very coarse-grained grouping of classes, packages, or subsystems that has cohesive responsibility for a major aspect of the system. Also, layers are organized such that “higher” layers (such as the UI layer) call upon services of “lower” layers, but not normally vice versa.</p>
<p>Typically layers in an OO system include:</p>
<ul>
<li>User Interface.</li>
<li>Application Logic and Domain Objects 领域层</li>
<li>Technical Services
<ul>
<li>general purpose objects and subsystems that provide supporting technical services, such as interfacing with a database or error logging.</li>
<li>These services are usually application-independent and reusable across several systems.</li>
</ul>
</li>
</ul>
<blockquote><p>Guideline: Design with Layers</p></blockquote>
<p>Applied to information systems, <strong>typical layers</strong> are illustrated and explained as follows:</p>
<ul>
<li>UI</li>
<li>Application
<ul>
<li>handles presentation layer request</li>
<li>workflow</li>
<li>session state</li>
</ul>
</li>
<li>Domain (aka Business, Application logic)
<ul>
<li>implementation of domain rules</li>
</ul>
</li>
<li>Business Infrasture
<ul>
<li>very general low-level business services</li>
<li>used in many business domains</li>
<li>eg, CurrencyConverter</li>
</ul>
</li>
<li>Technial Services
<ul>
<li>(relatively) high-level technical services and frameworks</li>
<li>eg, persistence, security</li>
</ul>
</li>
<li>Foundation
<ul>
<li>low-level technical services, utilities and frameworks</li>
<li>eg, data structures, threads, math, file, DB and network I/O</li>
</ul>
</li>
</ul>
<blockquote><p>Guideline: Cohesive Responsibilities; Maintain a Separation of Concerns</p></blockquote>
<p>每层干自己该干的事</p>
<p>The responsibilities of the objects in a layer should be strongly related to each other and should not be mixed with responsibilities of other layers. For example, objects in the UI layer should focus on UI work, such as creating windows and widgets, capturing mouse and keyboard events, and so forth. Objects in the application logic or “domain” layer should focus on application logic, such as calculating a sales total or taxes, or moving a piece on a game board.</p>
<p>UI objects should not do application logic. For example, a Java Swing JFrame (window) object should not contain logic to calculate taxes or move a game piece. And on the other hand, application logic classes should not trap UI mouse or keyboard events. That would violate a clear separation of concerns and maintaining high cohesion basic architectural principles.</p>
<blockquote><p>How do we design the application logic with objects?</p></blockquote>
<p>To create software objects with names and information similar to the real-world domain, and <strong>assign application logic responsibilities to them</strong>. For example, in the real world of POS, there are sales and payments. So, in software, we create a Sale and Payment class, and give them application logic responsibilities.</p>
<blockquote><p>Guideline: The Model-View Separation Principle</p></blockquote>
<p>In this context, model is a synonym for the domain layer of objects (it’s an old OO term from the late 1970s). View is a synonym for UI objects, such as windows, Web pages, applets, and reports.</p>
<p><strong>The Model-View Separation principle[2] states that model (domain) objects should not have direct knowledge of view (UI) objects, at least as view objects</strong>. So, for example, a Register or Sale object should not directly send a message to a GUI window object ProcessSaleFrame, asking it to display something, change color, close, and so forth.</p>
<p>Model-View-Controller (MVC): The Model is the Domain Layer, the View is the UI Layer, and the Controllers are the workflow objects in the Application layer. 至今看到的对MVC的最完美的诠释吧</p>
<h3>Elaboration Iteration 1Basics – On to Object Design</h3>
<h4>Designing Objects: What are Static and Dynamic Modeling?</h4>
<p>There are two kinds of object models: dynamic and static. <strong>Dynamic models, such as UML interaction diagrams (sequence diagrams or communication diagrams), help design the logic, the behavior of the code or the method bodies.</strong> They tend to be the more interesting, difficult, important diagrams to create. <strong>Static models, such as UML class diagrams, help design the definition of packages, class names, attributes, and method signatures (but not method bodies).</strong></p>
<p>People new to UML tend to think that the important diagram is the static-view class diagram, but in fact, most of the challenging, interesting, useful design work happens while drawing the UML dynamic-view interaction diagrams. It’s during dynamic object modeling (such as drawing sequence diagrams) that “the rubber hits the road” in terms of really thinking through the exact details of what objects need to exist and how they collaborate via messages and methods. 重点:先做Dynamic Modeling(新手会误认为要先做Static Modeling)</p>
<p>What’s important is knowing how to think and design in objects, and apply object design best-practice patterns, which is a very different and much more valuable skill than knowing UML notation. 重点是OO设计,而不是UML</p>
<h3>Elaboration Iteration 1Basics – UML Interaction Diagrams</h3>
<p>The term interaction diagram is a generalization of two more specialized UML diagram types:</p>
<ul>
<li>sequence diagrams
<ul>
<li>illustrate interactions in a kind of fence format, in which each new object is added to the right</li>
</ul>
</li>
<li>communication diagrams
<ul>
<li>illustrate object interactions in a graph or network format, in which objects can be placed anywhere on the diagram</li>
</ul>
</li>
</ul>
<p><img src="http://cs50Mu.github.io/images/post/sequence-diagram.jpg" alt="" />
<img src="http://cs50Mu.github.io/images/post/communication-diagram.jpg" alt="" /></p>
<h3>Elaboration Iteration 1Basics – UML Class Diagrams</h3>
<h3>Elaboration Iteration 1Basics – GRASP: Designing Objects with Responsibilities</h3>
<p><strong>The critical design tool for software development is a mind well educated in design principles.</strong> It is not the UML or any other technology.</p>
<blockquote><p>What Are Inputs to Object Design?</p></blockquote>
<p>开始设计的前提是已做好需求分析</p>
<blockquote><p>Responsibilities and Responsibility-Driven Design</p></blockquote>
<p>Basically, these responsibilities are of the following two types: doing and knowing.</p>
<p>Doing responsibilities of an object include:</p>
<ul>
<li>doing something itself, such as creating an object or doing a calculation</li>
<li>initiating action in other objects</li>
<li>controlling and coordinating activities in other objects</li>
</ul>
<p>Knowing responsibilities of an object include:</p>
<ul>
<li>knowing about private encapsulated data</li>
<li>knowing about related objects</li>
<li>knowing about things it can derive or calculate</li>
</ul>
<blockquote><p>What are Patterns?</p></blockquote>
<p>In OO design, a pattern is a named description of a problem and solution that can be applied to new contexts; ideally, a pattern advises us on how to apply its solution in varying circumstances and considers the forces and trade-offs.</p>
<p>New pattern should be considered an oxymoron if it describes a new idea. The very term “pattern” suggests a long-repeating thing. <strong>The point of design patterns is not to express new design ideas. Quite the oppositegreat patterns attempt to codify existing tried-and-true knowledge, idioms, and principles</strong>; the more honed, old, and widely used, the better.</p>
<blockquote><p>A Short Example of Object Design with GRASP</p></blockquote>
<p>There are nine GRASP patterns:</p>
<ul>
<li>Creator</li>
</ul>
<p>关键词:mental model、low representational gap (LRG)</p>
<p>原则是要尽量降低人的心理模型跟design model之间的认知差异</p>
<ul>
<li>Information Expert</li>
</ul>
<p>Problem: What is a basic principle by which to assign responsibilities to objects?</p>
<p>Solution: Assign a responsibility to the class that has the information needed to fulfill it.</p>
<ul>
<li>Low Coupling</li>
</ul>
<p>Briefly and informally, coupling is a measure of how strongly one element is connected to, has knowledge of, or depends on other elements.</p>
<p>If there is coupling or dependency, then when the depended-upon element changes, the dependant may be affected. For example, a subclass is strongly coupled to a superclass. An object A that calls on the operations of object B has coupling to B’s services.</p>
<p>It is not high coupling per se that is the problem; it is high coupling to elements that are unstable in some dimension, such as their interface, implementation, or mere presence. 不是耦合本身不好,而要看耦合的东西,若耦合的东西不稳定就不太好</p>
<ul>
<li>Controller</li>
</ul>
<p>Problem:What first object beyond the UI layer receives and coordinates (“controls”) a system operation?</p>
<p>Solution: Assign the responsibility to an object representing one of these choices:</p>
<ol>
<li>Represents the overall “system,” a “root object,” a device that the software is running within, or a major subsystem (these are all variations of a facade controller).</li>
<li>Represents a use case scenario within which the system operation occurs (a use case or session controller)</li>
</ol>
<p>有两种:</p>
<p>Facade controllers:门面,一切全包,比如TelecommSwitch、Phone、ChessGame</p>
<p>use case controller:按使用场景来分的,比如ProcessSaleHandler</p>
<ul>
<li>High Cohesion</li>
</ul>
<p>In software design a basic quality known as cohesion informally measures how <strong>functionally related</strong> the operations of a software element are, and also measures how much work a software element is doing. 做的事要有相关性,一个类的方法集中如果有很多关系不大的事情,则这个类不是cohesive的</p>
<p>As a simple contrasting example, an object Big with 100 methods and 2,000 source lines of code (SLOC) is doing a lot more than an object Small with 10 methods and 200 source lines. <strong>And if the 100 methods of Big are covering many different areas of responsibility (such as database access and random number generation), then Big has less focus or functional cohesion than Small.</strong> In summary, both the amount of code and the relatedness of the code are an indicator of an object’s cohesion.</p>
<p>Problem: How to keep objects focused, understandable, and manageable, and as a side effect, support Low Coupling?</p>
<p>Solution: Assign responsibilities so that cohesion remains high. Use this to evaluate alternatives.</p>
<h3>Elaboration Iteration 1Basics – Object Design Examples with GRASP</h3>
<p>I wish to exhaustively illustrate that no “magic” is needed in object design</p>
<p>OO software design really can be <strong>more science than art</strong>, though there is plenty of room for creativity and elegant design.</p>
<p>实例讲解,非常详尽!</p>
<blockquote><p>The Command-Query Separation Principle</p></blockquote>
<p>命令(有side effect的操作,比如update create等)与 查询 分离的原则</p>
<p>要这样:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="c1">// style #1; used in the official solution</span>
</span><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">roll</span><span class="o">()</span>
</span><span class='line'><span class="o">{</span>
</span><span class='line'><span class="n">faceValue</span> <span class="o">=</span> <span class="c1">// random num generation</span>
</span><span class='line'><span class="o">}</span>
</span><span class='line'><span class="kd">public</span> <span class="kt">int</span> <span class="nf">getFaceValue</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'> <span class="k">return</span> <span class="n">faceValue</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>而不是这样:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="c1">// style #2; why is this poor?</span>
</span><span class='line'><span class="kd">public</span> <span class="kt">int</span> <span class="nf">roll</span><span class="o">()</span>
</span><span class='line'><span class="o">{</span>
</span><span class='line'><span class="n">faceValue</span> <span class="o">=</span> <span class="c1">// random num generation</span>
</span><span class='line'> <span class="k">return</span> <span class="n">faceValue</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>为什么呢?</p>
<p>CQS is widely considered desirable in computer science theory <strong>because with it, you can more easily reason about a program’s state without simultaneously modifying that state. And it makes designs simpler to understand and anticipate.</strong> For example, if an application consistently follows CQS, you know that a query or getter method isn’t going to modify anything and a command isn’t going to return anything. Simple pattern. This often turns out to be nice to rely on, as the alternative can be a nasty surpriseviolating the Principle of <strong>Least Surprise</strong> in software development</p>
<h3>Elaboration Iteration 1Basics – Designing for Visibility</h3>
<p>Visibility is the ability of one object to see or have reference to another</p>
<p>There are four common ways that visibility can be achieved from object A to object B:</p>
<ul>
<li>Attribute visibility B is an attribute of A.</li>
<li>Parameter visibility B is a parameter of a method of A.</li>
<li>Local visibility B is a (non-parameter) local object in a method of A.</li>
<li>Global visibility B is in some way globally visible.</li>
</ul>
<h3>Elaboration Iteration 1Basics – Mapping Designs to Code</h3>
<h3>Elaboration Iteration 1Basics – Test-Driven Development and Refactoring</h3>
<p>Refactoring [Fowler99] is a structured, disciplined method to rewrite or restructure existing code without changing its external behavior, applying small transformation steps combined with re- executing tests each step.</p>
<h3>Elaboration Iteration 2 More Patterns – UML Tools and UML as Blueprint</h3>
<h3>Elaboration Iteration 2 More Patterns – Quick Analysis Update</h3>
<h3>Elaboration Iteration 2 More Patterns – Iteration 2More Patterns</h3>
<h3>Elaboration Iteration 2 More Patterns – More Objects with Responsibilities</h3>
<p>GRASP patterns:</p>
<ul>
<li>Polymorphism</li>
</ul>
<p>多态</p>
<p>Alternatives based on type Conditional variation is a fundamental theme in programs. If a program is designed using if-then-else or case statement conditional logic, then if a new variation arises, it requires modification of the case logicoften in many places. This approach makes it difficult to easily extend a program with new variations because changes tend to be required in several placeswherever the conditional logic exists. if-else 问题</p>
<p>原则:不要用if-else或者case来解决,而是用多态来解决</p>
<ul>
<li>Pure Fabrication</li>
</ul>
<p>Object-oriented designs are sometimes characterized by implementing as software classes representations of concepts in the real-world problem domain to lower the representational gap</p>
<p>Problem: What object should have the responsibility, when you do not want to violate High Cohesion and Low Coupling, or other goals, but solutions offered by Expert (for example) are not appropriate? there are many situations in which assigning responsibilities only to domain layer software classes leads to problems in terms of poor cohesion or coupling, or low reuse potential. 没办法跟Domain model(现实模型)对应上的object怎么设计?</p>
<p>Solution: Assign a highly cohesive set of responsibilities to <strong>an artificial or convenience class that does not represent a problem domain concept something made up</strong>, to support high cohesion, low coupling, and reuse.</p>
<ul>
<li>Indirection</li>
</ul>
<p>Most problems in computer science can be solved by another level of indirection</p>
<ul>
<li>Protected Variations</li>
</ul>
<p>Problem: How to design objects, subsystems, and systems so that the variations or instability in these elements does not have an undesirable impact on other elements?</p>
<p>Solution: Identify points of predicted variation or instability; <strong>assign responsibilities to create a stable interface around them</strong>.</p>
<p>虚拟机也是一个应用这个原则的例子</p>
<blockquote><p>The Liskov Substitution Principle (LSP)</p></blockquote>
<p>LSP [Liskov88] formalizes the principle of protection against variations in different implementations of an interface, or subclass extensions of a superclass.</p>
<p>Informally, software (methods, classes, …) that refers to a type T (some interface or abstract superclass) should work properly or as expected with any substituted implementation or subclass of Tcall it S.</p>
<blockquote><p>Law of Demeter</p></blockquote>
<p>Don’t Talk to Strangers</p>
<p>违反<code>Law of Demeter</code>的代码示例:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">doX</span><span class="o">()</span>
</span><span class='line'><span class="o">{</span>
</span><span class='line'><span class="n">F</span> <span class="n">someF</span> <span class="o">=</span> <span class="n">foo</span><span class="o">.</span><span class="na">getA</span><span class="o">().</span><span class="na">getB</span><span class="o">().</span><span class="na">getC</span><span class="o">().</span><span class="na">getD</span><span class="o">().</span><span class="na">getE</span><span class="o">().</span><span class="na">getF</span><span class="o">();</span>
</span><span class='line'><span class="c1">// ... </span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>
<p><strong>The design is coupled to a particular structure of how objects are connected.</strong> The farther along a path the program traverses, the more fragile it is. Why? Because the object structure (the connections) may change.</p>
<p>Novice developers tend toward brittle designs, intermediate developers tend toward overly fancy and flexible, generalized ones (in ways that never get used). Expert designers choose with insight; 关键是这个度不好把握啊</p>
<blockquote><p>Open-Closed Principle</p></blockquote>
<p>OCP and PV are essentially two expressions of the same principle, with different emphasis</p>
<h3>Elaboration Iteration 2 More Patterns – Applying GoF Design Patterns</h3>
<blockquote><p>Adapter (GoF)</p></blockquote>
<p>Problem: How to resolve incompatible interfaces, or provide a stable interface to similar components with different interfaces?</p>
<p>Solution: Convert the original interface of a component into another interface, through an intermediate adapter object.</p>
<blockquote><p>Factory</p></blockquote>
<p>The adapter raises a new problem in the design:</p>
<p>who creates the adapters? And how to determine which class of adapter to create, such as TaxMaster-Adapter or GoodAsGoldTaxProAdapter?</p>
<p>答案就是Factory</p>
<p>Problem: Who should be responsible for creating objects when there are special considerations, such as complex creation logic, a desire to separate the creation responsibilities for better cohesion, and so forth?</p>
<p>Solution: Create a Pure Fabrication object called a Factory that handles the creation.</p>
<p><img src="http://cs50Mu.github.io/images/post/factory.jpg" alt="" /></p>
<p>重点关注上图中,它是如何决定应该使用哪个Adapter的</p>
<p>Note that in the ServicesFactory, the logic to decide which class to create is resolved <strong>by reading in the class name from an external source (for example, via a system property if Java is used) and then dynamically loading the class.</strong> This is an example of a partial data-driven design.</p>
<blockquote><p>Singleton (GoF)</p></blockquote>
<p>The ServicesFactory raises another new problem in the design: Who creates the factory itself, and how is it accessed? 汗死。。。 按下葫芦起了瓢的感觉</p>
<p>观察</p>
<p>First, observe that only one instance of the factory is needed within the process. Second, quick reflection suggests that the methods of this factory may need to be called from various places in the code, as different places need access to the adapters for calling on the external services.</p>
<p>Problem: Exactly one instance of a class is allowedit is a “singleton.” Objects need a global and single point of access.</p>
<p>Solution: Define a static method of the class that returns the singleton.</p>
<p><img src="http://cs50Mu.github.io/images/post/singleton.jpg" alt="" /></p>
<blockquote><p>Strategy (GoF)</p></blockquote>
<p>Problem: How to design for varying, but related, algorithms or policies? How to design for the ability to change these algorithms or policies?</p>
<p>Solution: Define each algorithm/policy/strategy in a separate class, with a common interface.</p>
<blockquote><p>Composite (GoF)</p></blockquote>
<p>Problem:How to treat a group or composition structure of objects the same way (polymorphically) as a non-composite (atomic) object?</p>
<p>Solution: Define classes for composite and atomic objects so that they implement the same interface.</p>
<p>没有太理解清楚这个pattern</p>
<blockquote><p>Facade (GoF)</p></blockquote>
<p>Problem: A common, unified interface to a disparate set of implementations or interfacessuch as within a subsystemis required. There may be undesirable coupling to many things in the subsystem, or the implementation of the subsystem may change. What to do?</p>
<p>Solution: Define a single point of contact to the subsystema facade object that wraps the subsystem. This facade object presents a single unified interface and is responsible for collaborating with the subsystem components.</p>
<blockquote><p>Observer (Publish-Subscribe)</p></blockquote>
<p>Problem: Different kinds of subscriber objects are interested in the state changes or events of a publisher object, and want to react in their own unique way when the publisher generates an event. Moreover, the publisher wants to maintain low coupling to the subscribers. What to do?</p>
<p>Solution: Define a “subscriber” or “listener” interface. Subscribers implement this interface. The publisher can dynamically register subscribers who are interested in an event and notify them when an event occurs.</p>
<blockquote><p>Observer/Publish-Subscribe/Delegation Event Model (GoF)</p></blockquote>
<p>都是一个意思</p>
<p>Problem:Different kinds of subscriber objects are interested in the state changes or events of a publisher object, and want to react in their own unique way when the publisher generates an event. Moreover, the publisher wants to maintain low coupling to the subscribers. What to do?</p>
<p>Solution: Define a “subscriber” or “listener” interface. Subscribers implement this interface. The publisher can dynamically register subscribers who are interested in an event and notify them when an event occurs.</p>
<p>Observer provides a way to loosely couple objects in terms of communication. Publishers know about subscribers only through an interface, and subscribers can register (or de-register) dynamically with the publisher.</p>
<h3>Elaboration Iteration 3 – Intermediate Topics</h3>
<h3>Elaboration Iteration 3 – UML Activity Diagrams and Modeling</h3>
<p>A UML activity diagram shows sequential and parallel activities in a process. They are useful for modeling business processes, workflows, data flows, and complex algorithms.</p>
<p><img src="http://cs50Mu.github.io/images/post/activity-diagram.jpg" alt="" /></p>
<h3>Elaboration Iteration 3 – UML State Machine Diagrams and Modeling</h3>
<p>A UML state machine diagram, illustrates the interesting events and states of an object, and the behavior of an object in reaction to an event.</p>
<p>A state machine diagram shows the lifecycle of an object: what events it experiences, its transitions, and the states it is in between these events.</p>
<p><img src="http://cs50Mu.github.io/images/post/state-machine.jpg" alt="" /></p>
<h3>Elaboration Iteration 3 – Relating Use Cases</h3>
<h3>Elaboration Iteration 3 – More SSDs and Contracts</h3>
<h3>Elaboration Iteration 3 – Domain Model Refinement</h3>
<h3>Elaboration Iteration 3 – Architectural Analysis</h3>
<p>Architectural analysis can be viewed as a specialization of requirements analysis, with a focus on requirements that strongly influence the “architecture.” For example, identifying the need for a highly-secure system.</p>
<p>The essence of architectural analysis is to <strong>identify factors that should influence the architecture, understand their variability and priority, and resolve them.</strong> The difficult part is knowing what questions to ask, weighing the trade-offs, and knowing the many ways to resolve an architecturally significant factor, ranging from benign neglect, to fancy designs, to third-party products</p>
<ul>
<li>variation point
<ul>
<li>Variations in the existing current system or requirements, such as the multiple tax calculator interfaces that must be supported.</li>
</ul>
</li>
<li>evolution point
<ul>
<li>Speculative points of variation that may arise in the future, but which are not present in the existing requirements.</li>
</ul>
</li>
</ul>
<p>非功能性分析,比如安全、性能等</p>
<h3>Elaboration Iteration 3 – Logical Architecture Refinement</h3>
<p><img src="http://cs50Mu.github.io/images/post/view-of-layers.jpg" alt="" /></p>
<p>When the lower Application or Domain layer needs to communicate upward with the UI layer, it is usually via the Observer pattern.</p>
<p>it is not coupling per se that is a problem, but unnecessary coupling to variation and evolution points that are unstable and expensive to fix.</p>
<blockquote><p>Is the Application Layer Optional?</p></blockquote>
<p>If present, the Application layer contains objects responsible for knowing the session state of clients, mediating between the UI and Domain layers, and controlling the flow of work.</p>
<h3>Elaboration Iteration 3 – More Object Design with GoF Patterns</h3>
<blockquote><p>Handling Failure</p></blockquote>
<p>a common exception handling pattern:</p>
<ul>
<li>Convert Exceptions
<ul>
<li>Within a subsystem, avoid emitting lower level exceptions coming from lower subsystems or services. Rather, convert the lower level exception into one that is meaningful at the level of the subsystem. The higher level exception usually wraps the lower-level exception, and adds information, to make the exception more contextually meaningful to the higher level.</li>
</ul>
</li>
</ul>
<p>For example, the persistence subsystem catches a particular SQLException, and (assuming it can’t handle it[2] ) throws a new DBUnavailableException, which contains the SQLException. Note that the DBProductAdapter is like a facade onto a logical subsystem for product information. Thus, the higher level DBProductAdapter (as the representative for a logical subsystem) catches the lower level DBUnavailableException and (assuming it can’t handle it) throws a new ProductInfoUnavailableException, which wraps the DBUnavailableException.</p>
<ul>
<li><p>Name The Problem Not The Thrower</p>
<ul>
<li>What to call an exception? Assign a name that describes why the exception is being thrown, not the thrower. The benefit is that it makes it easier for the programmer to understand the problem, and it the highlights the essential similarity of many classes of exceptions (in a way that naming the thrower does not).</li>
</ul>
</li>
<li><p>Centralized Error Logging</p>
<ul>
<li>Use a Singleton-accessed central error logging object and report all exceptions to it. If it is a distributed system, each local singleton will collaborate with a central error logger.</li>
</ul>
</li>
<li><p>Error Dialog</p></li>
</ul>
<blockquote><p>Proxy</p></blockquote>
<p>Problem: Direct access to a real subject object is not desired or possible. What to do?</p>
<p>Solution: Add a level of indirection with a surrogate proxy object that implements the same interface as the subject object, and is responsibility for controlling or enhancing access to it.</p>
<blockquote><p>Abstract Factory</p></blockquote>
<p>Problem: How to create families of related classes that implement a common interface?</p>
<p>Solution: Define a factory interface (the abstract factory). Define a concrete factory class for each family of things to create. Optionally, define a true abstract class that implements the factory interface and provides common services to the concrete factories that extend it.</p>
<h3>Elaboration Iteration 3 – Package Design</h3>
<h3>Elaboration Iteration 3 – Designing a Persistence Framework with Patterns</h3>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Grafana源码分析]]></title>
<link href="http://cs50Mu.github.io/blog/2021/02/05/sourcecode-of-grafana/"/>
<updated>2021-02-05T12:04:00+08:00</updated>
<id>http://cs50Mu.github.io/blog/2021/02/05/sourcecode-of-grafana</id>
<content type="html"><![CDATA[<h2>Grafana源码分析</h2>
<h3>服务自动注入 / inject</h3>
<p>代码里的service使用了一个包来实现自动注入:<a href="https://github.com/facebookarchive/inject"><code>facebookarchive / inject</code></a></p>
<p>要实现这个自动,需要做以下准备工作:</p>
<p>打struct tag</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='go'><span class='line'><span class="kd">type</span> <span class="nx">HTTPServer</span> <span class="kd">struct</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">log</span> <span class="nx">log</span><span class="p">.</span><span class="nx">Logger</span>
</span><span class='line'> <span class="nx">macaron</span> <span class="o">*</span><span class="nx">macaron</span><span class="p">.</span><span class="nx">Macaron</span>
</span><span class='line'> <span class="nx">context</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span>
</span><span class='line'> <span class="nx">streamManager</span> <span class="o">*</span><span class="nx">live</span><span class="p">.</span><span class="nx">StreamManager</span>
</span><span class='line'> <span class="nx">httpSrv</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Server</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">RouteRegister</span> <span class="nx">routing</span><span class="p">.</span><span class="nx">RouteRegister</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">Bus</span> <span class="nx">bus</span><span class="p">.</span><span class="nx">Bus</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">RenderService</span> <span class="nx">rendering</span><span class="p">.</span><span class="nx">Service</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">Cfg</span> <span class="o">*</span><span class="nx">setting</span><span class="p">.</span><span class="nx">Cfg</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">HooksService</span> <span class="o">*</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">HooksService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">CacheService</span> <span class="o">*</span><span class="nx">localcache</span><span class="p">.</span><span class="nx">CacheService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">DatasourceCache</span> <span class="nx">datasources</span><span class="p">.</span><span class="nx">CacheService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">AuthTokenService</span> <span class="nx">models</span><span class="p">.</span><span class="nx">UserTokenService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">QuotaService</span> <span class="o">*</span><span class="nx">quota</span><span class="p">.</span><span class="nx">QuotaService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">RemoteCacheService</span> <span class="o">*</span><span class="nx">remotecache</span><span class="p">.</span><span class="nx">RemoteCache</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">ProvisioningService</span> <span class="nx">provisioning</span><span class="p">.</span><span class="nx">ProvisioningService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">Login</span> <span class="o">*</span><span class="nx">login</span><span class="p">.</span><span class="nx">LoginService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">License</span> <span class="nx">models</span><span class="p">.</span><span class="nx">Licensing</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">BackendPluginManager</span> <span class="nx">backendplugin</span><span class="p">.</span><span class="nx">Manager</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">PluginManager</span> <span class="o">*</span><span class="nx">plugins</span><span class="p">.</span><span class="nx">PluginManager</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="nx">SearchService</span> <span class="o">*</span><span class="nx">search</span><span class="p">.</span><span class="nx">SearchService</span> <span class="s">`inject:""`</span>
</span><span class='line'> <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>启动server时会build Service Graph:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
</pre></td><td class='code'><pre><code class='go'><span class='line'><span class="c1">// 获取注册的服务,具体实现比较简单,分析略过</span>
</span><span class='line'><span class="nx">services</span> <span class="o">:=</span> <span class="nx">registry</span><span class="p">.</span><span class="nx">GetServices</span><span class="p">()</span>
</span><span class='line'><span class="k">if</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">buildServiceGraph</span><span class="p">(</span><span class="nx">services</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="c1">// 看看它做了啥呢,这里就是关键了</span>
</span><span class='line'> <span class="c1">// buildServiceGraph builds a graph of services and their dependencies.</span>
</span><span class='line'> <span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Server</span><span class="p">)</span> <span class="nx">buildServiceGraph</span><span class="p">(</span><span class="nx">services</span> <span class="p">[]</span><span class="o">*</span><span class="nx">registry</span><span class="p">.</span><span class="nx">Descriptor</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// Specify service dependencies.</span>
</span><span class='line'> <span class="nx">objs</span> <span class="o">:=</span> <span class="p">[]</span><span class="kd">interface</span><span class="p">{}{</span>
</span><span class='line'> <span class="nx">bus</span><span class="p">.</span><span class="nx">GetBus</span><span class="p">(),</span>
</span><span class='line'> <span class="nx">s</span><span class="p">.</span><span class="nx">cfg</span><span class="p">,</span>
</span><span class='line'> <span class="nx">routing</span><span class="p">.</span><span class="nx">NewRouteRegister</span><span class="p">(</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">RequestMetrics</span><span class="p">,</span> <span class="nx">middleware</span><span class="p">.</span><span class="nx">RequestTracing</span><span class="p">),</span>
</span><span class='line'> <span class="nx">localcache</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="mi">5</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Minute</span><span class="p">,</span> <span class="mi">10</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Minute</span><span class="p">),</span>
</span><span class='line'> <span class="nx">s</span><span class="p">,</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">service</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">services</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">objs</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">objs</span><span class="p">,</span> <span class="nx">service</span><span class="p">.</span><span class="nx">Instance</span><span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">serviceGraph</span> <span class="nx">inject</span><span class="p">.</span><span class="nx">Graph</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// Provide services and their dependencies to the graph.</span>
</span><span class='line'> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">obj</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">objs</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// 奥秘在这里了</span>
</span><span class='line'> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">serviceGraph</span><span class="p">.</span><span class="nx">Provide</span><span class="p">(</span><span class="o">&</span><span class="nx">inject</span><span class="p">.</span><span class="nx">Object</span><span class="p">{</span><span class="nx">Value</span><span class="p">:</span> <span class="nx">obj</span><span class="p">});</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">errutil</span><span class="p">.</span><span class="nx">Wrapf</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">"Failed to provide object to the graph"</span><span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// Resolve services and their dependencies.</span>
</span><span class='line'> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">serviceGraph</span><span class="p">.</span><span class="nx">Populate</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">errutil</span><span class="p">.</span><span class="nx">Wrapf</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">"Failed to populate service dependency"</span><span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="kc">nil</span>
</span><span class='line'> <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h3>user login是如何实现的?</h3>
<p>有个middleware,在处理业务请求之前会先验证user</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
</pre></td><td class='code'><pre><code class='go'><span class='line'><span class="c1">// pkg/middleware/middleware.go</span>
</span><span class='line'><span class="kd">func</span> <span class="nx">GetContextHandler</span><span class="p">(</span>
</span><span class='line'> <span class="nx">ats</span> <span class="nx">models</span><span class="p">.</span><span class="nx">UserTokenService</span><span class="p">,</span>
</span><span class='line'> <span class="nx">remoteCache</span> <span class="o">*</span><span class="nx">remotecache</span><span class="p">.</span><span class="nx">RemoteCache</span><span class="p">,</span>
</span><span class='line'> <span class="nx">renderService</span> <span class="nx">rendering</span><span class="p">.</span><span class="nx">Service</span><span class="p">,</span>
</span><span class='line'><span class="p">)</span> <span class="nx">macaron</span><span class="p">.</span><span class="nx">Handler</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">func</span><span class="p">(</span><span class="nx">c</span> <span class="o">*</span><span class="nx">macaron</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">ctx</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">models</span><span class="p">.</span><span class="nx">ReqContext</span><span class="p">{</span>
</span><span class='line'> <span class="nx">Context</span><span class="p">:</span> <span class="nx">c</span><span class="p">,</span>
</span><span class='line'> <span class="nx">SignedInUser</span><span class="p">:</span> <span class="o">&</span><span class="nx">models</span><span class="p">.</span><span class="nx">SignedInUser</span><span class="p">{},</span>
</span><span class='line'> <span class="nx">IsSignedIn</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span><span class='line'> <span class="nx">AllowAnonymous</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span><span class='line'> <span class="nx">SkipCache</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span><span class='line'> <span class="nx">Logger</span><span class="p">:</span> <span class="nx">log</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"context"</span><span class="p">),</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">orgId</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span><span class='line'> <span class="nx">orgIdHeader</span> <span class="o">:=</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">Req</span><span class="p">.</span><span class="nx">Header</span><span class="p">.</span><span class="nx">Get</span><span class="p">(</span><span class="s">"X-Grafana-Org-Id"</span><span class="p">)</span>
</span><span class='line'> <span class="k">if</span> <span class="nx">orgIdHeader</span> <span class="o">!=</span> <span class="s">""</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">orgId</span><span class="p">,</span> <span class="nx">_</span> <span class="p">=</span> <span class="nx">strconv</span><span class="p">.</span><span class="nx">ParseInt</span><span class="p">(</span><span class="nx">orgIdHeader</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// the order in which these are tested are important</span>
</span><span class='line'> <span class="c1">// look for api key in Authorization header first</span>
</span><span class='line'> <span class="c1">// then init session and look for userId in session</span>
</span><span class='line'> <span class="c1">// then look for api key in session (special case for render calls via api)</span>
</span><span class='line'> <span class="c1">// then test if anonymous access is enabled</span>
</span><span class='line'> <span class="c1">// 这个写法可以学习一下</span>
</span><span class='line'> <span class="k">switch</span> <span class="p">{</span>
</span><span class='line'> <span class="k">case</span> <span class="nx">initContextWithRenderAuth</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">renderService</span><span class="p">):</span>
</span><span class='line'> <span class="k">case</span> <span class="nx">initContextWithApiKey</span><span class="p">(</span><span class="nx">ctx</span><span class="p">):</span>
</span><span class='line'> <span class="k">case</span> <span class="nx">initContextWithBasicAuth</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">orgId</span><span class="p">):</span>
</span><span class='line'> <span class="k">case</span> <span class="nx">initContextWithAuthProxy</span><span class="p">(</span><span class="nx">remoteCache</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">,</span> <span class="nx">orgId</span><span class="p">):</span>
</span><span class='line'> <span class="k">case</span> <span class="nx">initContextWithToken</span><span class="p">(</span><span class="nx">ats</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">,</span> <span class="nx">orgId</span><span class="p">):</span>
</span><span class='line'> <span class="k">case</span> <span class="nx">initContextWithAnonymousUser</span><span class="p">(</span><span class="nx">ctx</span><span class="p">):</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">ctx</span><span class="p">.</span><span class="nx">Logger</span> <span class="p">=</span> <span class="nx">log</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"context"</span><span class="p">,</span> <span class="s">"userId"</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">UserId</span><span class="p">,</span> <span class="s">"orgId"</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">OrgId</span><span class="p">,</span> <span class="s">"uname"</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">Login</span><span class="p">)</span>
</span><span class='line'> <span class="nx">ctx</span><span class="p">.</span><span class="nx">Data</span><span class="p">[</span><span class="s">"ctx"</span><span class="p">]</span> <span class="p">=</span> <span class="nx">ctx</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">c</span><span class="p">.</span><span class="nx">Map</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// update last seen every 5min</span>
</span><span class='line'> <span class="k">if</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">ShouldUpdateLastSeenAt</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">ctx</span><span class="p">.</span><span class="nx">Logger</span><span class="p">.</span><span class="nx">Debug</span><span class="p">(</span><span class="s">"Updating last user_seen_at"</span><span class="p">,</span> <span class="s">"user_id"</span><span class="p">,</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">UserId</span><span class="p">)</span>
</span><span class='line'> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">bus</span><span class="p">.</span><span class="nx">Dispatch</span><span class="p">(</span><span class="o">&</span><span class="nx">models</span><span class="p">.</span><span class="nx">UpdateUserLastSeenAtCommand</span><span class="p">{</span><span class="nx">UserId</span><span class="p">:</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">UserId</span><span class="p">});</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">ctx</span><span class="p">.</span><span class="nx">Logger</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">"Failed to update last_seen_at"</span><span class="p">,</span> <span class="s">"error"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
</pre></td><td class='code'><pre><code class='go'><span class='line'><span class="c1">// login接口的实现,它会调用下面的`AuthenticateUser`方法</span>
</span><span class='line'><span class="c1">// pkg/api/login.go</span>