Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. All high-level classes must depend only on Interfaces

All high-level classes must depend only on Interfaces

Scheduled Pinned Locked Moved The Lounge
comdesigngame-devbeta-testingtutorial
69 Posts 15 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Sander RosselS Sander Rossel

    I'd balk at the word "All". While I do use lots of interfaces, even for classes that rarely get a second implementation, I don't use an interface for everything. It's simply impossible now to say all your future "high-level classes" (whatever that means) need an interface or need to be injected. And if you use an interface, do it right. I've seen software that used interfaces like this:

    public interface ISomething { ... }
    public class Something : ISomething { ... }

    // Scattered throughout the code:
    ISomething something = new Something();

    // But then also:
    public Whatever DoSomeCalculations(Something something) { ... }

    Their idea was that you could now easily write a Something2 and replace all new Something() with new Something2() if that was ever necessary. If that's how you're going to "use" interfaces, you might as well not. And then the occassional idiot saying everything needs an interface. So with interfaces it's like with many things in life: it depends.

    Best, Sander Azure DevOps Succinctly (free eBook) Azure Serverless Succinctly (free eBook) Migrating Apps to the Cloud with Azure arrgh.js - Bringing LINQ to JavaScript

    R Offline
    R Offline
    raddevus
    wrote on last edited by
    #13

    Fantastic post! Great points and right along the lines as what I was thinking. Thanks for the interesting discussion on this :thumbsup:

    1 Reply Last reply
    0
    • R raddevus

      That’s actually a very good question It is a bit difficult to even explain that but think of any class that calls another to do work The PDF that I mentioned uses the example of a WebController (MVC Controller) as being the high level class that would call other classes to do work And high level class is basically saying “break apart all functionality (single responsibility principle)” Controller here is just calling other things to do work.

      P Offline
      P Offline
      PIEBALDconsult
      wrote on last edited by
      #14

      I agree that that seems to be the only reasonable way to interpret it. As in a layered architecture. Yet you can also look at it the other way -- a "high-level" class has derived classes descending from it. Possibly, a better term would be "top-level" -- "high" doesn't necessarily indicate "top". I think the use of the term simply indicates that the author is addressing only a very narrow scope of software architecture. I might invert the definition though and say that a "high-level" class is one which depends only on interfaces.

      1 Reply Last reply
      0
      • R raddevus

        I'm very interested in feedback on this. Yes, it's somewhat related to my latest article[^], but I'm going through what I explain below, right now.. What if you were going to design some new service or app and you were told:

        Development Manger:

        "All high-level classes must depend only on Interfaces."

        What if I told you that and was entirely serious. Would you balk? or think, "Yes, that is the way it is and should be." After that your manager says,

        Development Manager:

        "Something else will decide how to build the implementation which will fulfill the Interfaces."

        Would that sound normal to you, or completely crazy? Or somewhere in between? The Implications Do you honestly understand the implications? No Implementation Code One of the implications is that the code Service or App you are creating basically has no implementation code in it. (Or very little.) Why? Because your high-level app only depends on easily-replaceable Interfaces. That means if you want to see the implementation, you'll need to go to the Library (probably a separate project) which contains the implementation that is used to fulfill the Interface. How do you feel about that? Do you know how crazy it is to look at project that has been designed this way? Have you ever experience a project that is carried out like this? Why I'm Thinking About This Even More? I have just completed 50 pages (of a total of 241) of the very old book (2013) DependencyInjection With Unity (free PDF or EPUB at link)[^].

        R Offline
        R Offline
        Ravi Bhavnani
        wrote on last edited by
        #15

        raddevus wrote:

        All high-level classes must depend only on Interfaces

        That's one of the tenets of dependency injection because it makes for a testable and extensible design.  We follow that guideline at my shop. (Apologies if I misunderstood your comment.) /ravi

        My new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com

        R J 2 Replies Last reply
        0
        • R Ravi Bhavnani

          raddevus wrote:

          All high-level classes must depend only on Interfaces

          That's one of the tenets of dependency injection because it makes for a testable and extensible design.  We follow that guideline at my shop. (Apologies if I misunderstood your comment.) /ravi

          My new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com

          R Offline
          R Offline
          raddevus
          wrote on last edited by
          #16

          Ravi Bhavnani wrote:

          That's one of the tenets of dependency injection because it makes for a testable and extensible design

          Yep, the devs who know about this know it really is like that. It's a foundational idea of DI. Thanks for commenting. I'm curious about : 1. how many developers really know that concept 2. how many developers / shops actually use it. 3. how devs who work at shops where it is used, like or dislike it. The comments so far have been very interesting. Have you, by chance, read that MS Unity PDF that I referenced in my original post? It has some great info on DI, but it's so old and further along the examples just jump into extreme details of using the Unity container. Oy! they should've made smaller set of examples. That's actually what I was trying with my latest article. Thanks again for the conversation.

          E R 2 Replies Last reply
          0
          • R raddevus

            englebart:

            If your IDE can’t show you all of the implementors of the interface in milliseconds, then try a better IDE.

            Truth! Part of our problem is that we are using VS 2013 :|

            E Offline
            E Offline
            englebart
            wrote on last edited by
            #17

            One step above csc.exe!

            1 Reply Last reply
            0
            • R raddevus

              I'm very interested in feedback on this. Yes, it's somewhat related to my latest article[^], but I'm going through what I explain below, right now.. What if you were going to design some new service or app and you were told:

              Development Manger:

              "All high-level classes must depend only on Interfaces."

              What if I told you that and was entirely serious. Would you balk? or think, "Yes, that is the way it is and should be." After that your manager says,

              Development Manager:

              "Something else will decide how to build the implementation which will fulfill the Interfaces."

              Would that sound normal to you, or completely crazy? Or somewhere in between? The Implications Do you honestly understand the implications? No Implementation Code One of the implications is that the code Service or App you are creating basically has no implementation code in it. (Or very little.) Why? Because your high-level app only depends on easily-replaceable Interfaces. That means if you want to see the implementation, you'll need to go to the Library (probably a separate project) which contains the implementation that is used to fulfill the Interface. How do you feel about that? Do you know how crazy it is to look at project that has been designed this way? Have you ever experience a project that is carried out like this? Why I'm Thinking About This Even More? I have just completed 50 pages (of a total of 241) of the very old book (2013) DependencyInjection With Unity (free PDF or EPUB at link)[^].

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #18

              It only makes sense to me when it can be more than one "is a". Other than that, it's another "ritual". And all you keep doing is going back and forth between (one) "implementation" and interface; until it's obvious one needs (or can benefit from) an interface. Then you also have to deal with the school that says "no inheritance"; which in essence means no "base methods"; virtual or otherwise. Another pointless ritual that only becomes "real" because someone "ordered" it; or can't decide when it is appropriate. See: "abstract" TextBoxBase.

              "Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I

              E 1 Reply Last reply
              0
              • R raddevus

                Ravi Bhavnani wrote:

                That's one of the tenets of dependency injection because it makes for a testable and extensible design

                Yep, the devs who know about this know it really is like that. It's a foundational idea of DI. Thanks for commenting. I'm curious about : 1. how many developers really know that concept 2. how many developers / shops actually use it. 3. how devs who work at shops where it is used, like or dislike it. The comments so far have been very interesting. Have you, by chance, read that MS Unity PDF that I referenced in my original post? It has some great info on DI, but it's so old and further along the examples just jump into extreme details of using the Unity container. Oy! they should've made smaller set of examples. That's actually what I was trying with my latest article. Thanks again for the conversation.

                E Offline
                E Offline
                englebart
                wrote on last edited by
                #19

                Our latest “fresh” developers think OOP is microservices… Cannot even refactor simple code: Original code did X 5 times, why does the new code do X 4 times? Even some of the more experienced group is too reliant on full solutions on StackOverflow, etc. They cannot take two topics and synthesize a unique solution.

                1 Reply Last reply
                0
                • L Lost User

                  It only makes sense to me when it can be more than one "is a". Other than that, it's another "ritual". And all you keep doing is going back and forth between (one) "implementation" and interface; until it's obvious one needs (or can benefit from) an interface. Then you also have to deal with the school that says "no inheritance"; which in essence means no "base methods"; virtual or otherwise. Another pointless ritual that only becomes "real" because someone "ordered" it; or can't decide when it is appropriate. See: "abstract" TextBoxBase.

                  "Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I

                  E Offline
                  E Offline
                  englebart
                  wrote on last edited by
                  #20

                  I do like the rule of no concrete super/base classes. One concrete type extending another concrete type always causes grief down the road when someone adds a third concrete type into the mix.

                  J 1 Reply Last reply
                  0
                  • R raddevus

                    Ravi Bhavnani wrote:

                    That's one of the tenets of dependency injection because it makes for a testable and extensible design

                    Yep, the devs who know about this know it really is like that. It's a foundational idea of DI. Thanks for commenting. I'm curious about : 1. how many developers really know that concept 2. how many developers / shops actually use it. 3. how devs who work at shops where it is used, like or dislike it. The comments so far have been very interesting. Have you, by chance, read that MS Unity PDF that I referenced in my original post? It has some great info on DI, but it's so old and further along the examples just jump into extreme details of using the Unity container. Oy! they should've made smaller set of examples. That's actually what I was trying with my latest article. Thanks again for the conversation.

                    R Offline
                    R Offline
                    Ravi Bhavnani
                    wrote on last edited by
                    #21

                    raddevus wrote:

                    how many developers really know that concept

                    I would have assumed devs with some experience would be aware of this.  In our shop it's a given because you can't write a unit test with a mocked dependency without using this paradigm. :)   It's also one of our pre-interview phone screen questions. There's another subtle aspect to this, though: when using MEF, you can encounter a run-time failure (error constructing a service class) when any dependency in the chain fails to construct because of a missing [Export] attribute on a class in the dependency hierarchy.  I didn't want our devs to have to manually check for this so I wrote a tool that reflects the codebase and identifies these broken classes. /ravi

                    My new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com

                    E H 2 Replies Last reply
                    0
                    • R raddevus

                      I'm very interested in feedback on this. Yes, it's somewhat related to my latest article[^], but I'm going through what I explain below, right now.. What if you were going to design some new service or app and you were told:

                      Development Manger:

                      "All high-level classes must depend only on Interfaces."

                      What if I told you that and was entirely serious. Would you balk? or think, "Yes, that is the way it is and should be." After that your manager says,

                      Development Manager:

                      "Something else will decide how to build the implementation which will fulfill the Interfaces."

                      Would that sound normal to you, or completely crazy? Or somewhere in between? The Implications Do you honestly understand the implications? No Implementation Code One of the implications is that the code Service or App you are creating basically has no implementation code in it. (Or very little.) Why? Because your high-level app only depends on easily-replaceable Interfaces. That means if you want to see the implementation, you'll need to go to the Library (probably a separate project) which contains the implementation that is used to fulfill the Interface. How do you feel about that? Do you know how crazy it is to look at project that has been designed this way? Have you ever experience a project that is carried out like this? Why I'm Thinking About This Even More? I have just completed 50 pages (of a total of 241) of the very old book (2013) DependencyInjection With Unity (free PDF or EPUB at link)[^].

                      P Offline
                      P Offline
                      Peter Moore Chicago
                      wrote on last edited by
                      #22

                      Whoever gave that directive is a man after my own heart. It's extreme, to be sure. Realistic to literally follow 100% of the time? Probably not. But as an aspiration, a philosophy - absolutely. If you do this, you will be able to grow and scale your products effortlessly for decades - basically for as long as the programming language you use is supported - without a rewrite. Nuget packages, even entire application frameworks will come and go, yet your core code will be snug as a bug in a rug, wrapped in layers of abstraction that shield it from the chaos. When your favorite library is deprecated, revealed to have a critical vulnerability, or the vendor jacks up the price on you, you scoff at how simple it is to assign someone to find a replacement and write the wrapper layer - *completely independently of everyone else*. Your customer tells you the application you designed for Azure now needs to run on AWS? "No problem", you say, "give me a week." Microsoft decides to make 100 new breaking changes to ASP.NET Core? Bah! The upgrade takes an hour. You will never be stuck relying on proprietary technology outside of your control ever again. The term "technical debt" won't even be part of your vocabulary. So yes. Those who know, do this.

                      R J R 3 Replies Last reply
                      0
                      • R raddevus

                        I'm very interested in feedback on this. Yes, it's somewhat related to my latest article[^], but I'm going through what I explain below, right now.. What if you were going to design some new service or app and you were told:

                        Development Manger:

                        "All high-level classes must depend only on Interfaces."

                        What if I told you that and was entirely serious. Would you balk? or think, "Yes, that is the way it is and should be." After that your manager says,

                        Development Manager:

                        "Something else will decide how to build the implementation which will fulfill the Interfaces."

                        Would that sound normal to you, or completely crazy? Or somewhere in between? The Implications Do you honestly understand the implications? No Implementation Code One of the implications is that the code Service or App you are creating basically has no implementation code in it. (Or very little.) Why? Because your high-level app only depends on easily-replaceable Interfaces. That means if you want to see the implementation, you'll need to go to the Library (probably a separate project) which contains the implementation that is used to fulfill the Interface. How do you feel about that? Do you know how crazy it is to look at project that has been designed this way? Have you ever experience a project that is carried out like this? Why I'm Thinking About This Even More? I have just completed 50 pages (of a total of 241) of the very old book (2013) DependencyInjection With Unity (free PDF or EPUB at link)[^].

                        J Offline
                        J Offline
                        jschell
                        wrote on last edited by
                        #23

                        raddevus wrote:

                        Would you balk? or think, "Yes, that is the way it is and should be."

                        Depends. If one complex layer (A) is dependent on another complex layer (B) then unit testing A becomes quite a bit more difficult if B does not provide and interface.

                        raddevus wrote:

                        Do you know how crazy it is to look at project that has been designed this way?

                        Designing general solutions based on one implementation will fail. The general solution will encapsulate all of the assumptions about the single implementation. So it achieves nothing in terms of generalization. Even when multiple implementations are known it requires rigorous oversight to insure that someone doesn't attempt to generalize a subsection of the implementations. They end up doing the same thing - implementing based on just the subsection.

                        1 Reply Last reply
                        0
                        • P Peter Moore Chicago

                          Whoever gave that directive is a man after my own heart. It's extreme, to be sure. Realistic to literally follow 100% of the time? Probably not. But as an aspiration, a philosophy - absolutely. If you do this, you will be able to grow and scale your products effortlessly for decades - basically for as long as the programming language you use is supported - without a rewrite. Nuget packages, even entire application frameworks will come and go, yet your core code will be snug as a bug in a rug, wrapped in layers of abstraction that shield it from the chaos. When your favorite library is deprecated, revealed to have a critical vulnerability, or the vendor jacks up the price on you, you scoff at how simple it is to assign someone to find a replacement and write the wrapper layer - *completely independently of everyone else*. Your customer tells you the application you designed for Azure now needs to run on AWS? "No problem", you say, "give me a week." Microsoft decides to make 100 new breaking changes to ASP.NET Core? Bah! The upgrade takes an hour. You will never be stuck relying on proprietary technology outside of your control ever again. The term "technical debt" won't even be part of your vocabulary. So yes. Those who know, do this.

                          R Offline
                          R Offline
                          raddevus
                          wrote on last edited by
                          #24

                          Yep, I think you nailed the truth of it. It is definitely a core practice to follow. Very few people think of software dev in these terms. I'm guessing you've built or worked on extremely large projects?

                          1 Reply Last reply
                          0
                          • E englebart

                            We try to follow this principle. Even if you do something like: IProvider thing = new RealProvider(); It makes you plan in terms of the consumer. If you end up with multiple providers later, switching to IOC is really easy. Or substituting a mock for testing, or writing tests based on IProvider, or etc And of course, all the high level code that is calling the interfaces is “real” code. If your IDE can’t show you all of the implementors of the interface in milliseconds, then try a better IDE.

                            J Offline
                            J Offline
                            jschell
                            wrote on last edited by
                            #25

                            englebart wrote:

                            If you end up with multiple providers later,

                            That however is the problem. First of course it assumes that that is realistically even possible. Second it assumes that the generalized interface will actually be abstract. So a different provider can be put in. Databases are an excellent example of this. They do in fact change on occasion. But excluding very simple usages I have never seen this go smoothly or quickly. I saw one company that specifically claimed (marketing) that their product was database agnostic and yet I saw the following 1. The product could not meet performance goals by probably at least an order of magnitude. 2. Their 'schema' was obviously generated in such a way that it would make any DBA tasked with supporting it not happy at all (as the DBA I talked to reported.) 3. They spent months on site trying to get it to work correctly and fast enough to be even possible for the company to use it. Still working on it when I left the company.

                            E 1 Reply Last reply
                            0
                            • R Ravi Bhavnani

                              raddevus wrote:

                              All high-level classes must depend only on Interfaces

                              That's one of the tenets of dependency injection because it makes for a testable and extensible design.  We follow that guideline at my shop. (Apologies if I misunderstood your comment.) /ravi

                              My new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com

                              J Offline
                              J Offline
                              jschell
                              wrote on last edited by
                              #26

                              Ravi Bhavnani wrote:

                              That's one of the tenets of dependency injection because it makes for a testable and extensible design.

                              Those are buzz words however. It is like saying that the code should be 'readable'. Has anyone measured, objective measurements, how successful that is? How do you create a design that is 'extensible' when you do not know what business will be like in 5 years? Or 20? What are you testing exactly? How do you measure it? Are bugs in production compared to those in QA and those in development? Does your testing cover not only simple unit testing but complex scenarios? What above fail over testing? What about production (not QA) testing? Do you have actual injection scenarios that test different scenarios. This is possible in certain situations such as in performance testing specific code. But it must be plan for and then actually used in an ongoing way.

                              R 1 Reply Last reply
                              0
                              • E englebart

                                I do like the rule of no concrete super/base classes. One concrete type extending another concrete type always causes grief down the road when someone adds a third concrete type into the mix.

                                J Offline
                                J Offline
                                jschell
                                wrote on last edited by
                                #27

                                englebart wrote:

                                One concrete type extending another concrete type

                                The problem there however is overuse of inheritance. The solution is to use composition instead.

                                1 Reply Last reply
                                0
                                • J jschell

                                  englebart wrote:

                                  If you end up with multiple providers later,

                                  That however is the problem. First of course it assumes that that is realistically even possible. Second it assumes that the generalized interface will actually be abstract. So a different provider can be put in. Databases are an excellent example of this. They do in fact change on occasion. But excluding very simple usages I have never seen this go smoothly or quickly. I saw one company that specifically claimed (marketing) that their product was database agnostic and yet I saw the following 1. The product could not meet performance goals by probably at least an order of magnitude. 2. Their 'schema' was obviously generated in such a way that it would make any DBA tasked with supporting it not happy at all (as the DBA I talked to reported.) 3. They spent months on site trying to get it to work correctly and fast enough to be even possible for the company to use it. Still working on it when I left the company.

                                  E Offline
                                  E Offline
                                  englebart
                                  wrote on last edited by
                                  #28

                                  I stopped reading at “(marketing)”. 😊 Marketing still received their bonus? Database compatibility layers are a whole different ball of yarn. Rarely do I ever have a second implementation, but I still like designing to the interface. (and keeping all dependency graphs one way)

                                  1 Reply Last reply
                                  0
                                  • R Ravi Bhavnani

                                    raddevus wrote:

                                    how many developers really know that concept

                                    I would have assumed devs with some experience would be aware of this.  In our shop it's a given because you can't write a unit test with a mocked dependency without using this paradigm. :)   It's also one of our pre-interview phone screen questions. There's another subtle aspect to this, though: when using MEF, you can encounter a run-time failure (error constructing a service class) when any dependency in the chain fails to construct because of a missing [Export] attribute on a class in the dependency hierarchy.  I didn't want our devs to have to manually check for this so I wrote a tool that reflects the codebase and identifies these broken classes. /ravi

                                    My new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com

                                    E Offline
                                    E Offline
                                    englebart
                                    wrote on last edited by
                                    #29

                                    Article? Or owned by the employer?

                                    R 1 Reply Last reply
                                    0
                                    • R raddevus

                                      I'm very interested in feedback on this. Yes, it's somewhat related to my latest article[^], but I'm going through what I explain below, right now.. What if you were going to design some new service or app and you were told:

                                      Development Manger:

                                      "All high-level classes must depend only on Interfaces."

                                      What if I told you that and was entirely serious. Would you balk? or think, "Yes, that is the way it is and should be." After that your manager says,

                                      Development Manager:

                                      "Something else will decide how to build the implementation which will fulfill the Interfaces."

                                      Would that sound normal to you, or completely crazy? Or somewhere in between? The Implications Do you honestly understand the implications? No Implementation Code One of the implications is that the code Service or App you are creating basically has no implementation code in it. (Or very little.) Why? Because your high-level app only depends on easily-replaceable Interfaces. That means if you want to see the implementation, you'll need to go to the Library (probably a separate project) which contains the implementation that is used to fulfill the Interface. How do you feel about that? Do you know how crazy it is to look at project that has been designed this way? Have you ever experience a project that is carried out like this? Why I'm Thinking About This Even More? I have just completed 50 pages (of a total of 241) of the very old book (2013) DependencyInjection With Unity (free PDF or EPUB at link)[^].

                                      E Offline
                                      E Offline
                                      englebart
                                      wrote on last edited by
                                      #30

                                      Another corollary that a comment triggered,

                                      Quote:

                                      Create a facade around any API that you are using to protect your code from changes in the API.

                                      R 1 Reply Last reply
                                      0
                                      • E englebart

                                        Another corollary that a comment triggered,

                                        Quote:

                                        Create a facade around any API that you are using to protect your code from changes in the API.

                                        R Offline
                                        R Offline
                                        raddevus
                                        wrote on last edited by
                                        #31

                                        quote

                                        Create a facade around any API that you are using to protect your code from changes in the API.

                                        A great idea that no one ever does. Ok, not no one, but it is done more rarely than it should be. Also, there are physical limitations to it. We use a 3rd party component that has 100s methods. We should wrap the component but it gonna take a while. :)

                                        E H 2 Replies Last reply
                                        0
                                        • R raddevus

                                          quote

                                          Create a facade around any API that you are using to protect your code from changes in the API.

                                          A great idea that no one ever does. Ok, not no one, but it is done more rarely than it should be. Also, there are physical limitations to it. We use a 3rd party component that has 100s methods. We should wrap the component but it gonna take a while. :)

                                          E Offline
                                          E Offline
                                          englebart
                                          wrote on last edited by
                                          #32

                                          A 1:1 mapping is not what I was envisioning. (Beginners might miss that joke! What’s the point?) Facade/Wrapper/Adapter/Proxy/etc

                                          J 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups