jfeliu007 / goplantuml

PlantUML Class Diagram Generator for golang projects
MIT License
1.78k stars 167 forks source link

Support top-level functions #89

Open hupfdule opened 4 years ago

hupfdule commented 4 years ago

I have requested the same for bykof/go-plantuml, but open the same ticket here:

It would be nice if goplantuml would support top-level functions (instead of only methods).

The main problem will be the decision on how to represent these, as UML ususally doesn't provide a notion of top-level functions.

One possibility would be to misuse a class for that purpose. See this discussion about such a topic.

I have prepared a rough idea how that could be achieved.

For the following classes:

// mypackage/functions.go
package mypackage

func Function1() []string {
  return []string{}
}

func Function2(param1, param2 string) {
}
// otherpackage.functions.go
package otherpackage

func New() MyStruct {
  return MyStruct{}
}

func Frobnicate(subject []string) {
}
// otherpackage/mystruct.go
package otherpackage

import (
  "fmt"

  "my.domain/rough/mypackage"
)

type MyStruct struct {
  Name string
}

func (s *MyStruct) DoSomething() {
  v := mypackage.Function1()
  fmt.Println(v)
}

func (s *MyStruct) GetSomething() string {
  return s.Name
}

the following puml file could be generated:

@startuml
title Rough idea
namespace mypackage {
  class mypackage.functions << (F, blanchedalmond) >> {
    + Function1() []string
    + Function2(string, string)
  }
}
namespace otherpackage {
  class otherpackage.MyStruct << (S, aquamarine) >> {
    + Name string
    + DoSomething()
    + GetSomething() string
  }

  class otherpackage.functions << (F, blanchedalmond) >> {
    + New() MyStruct
    + Frobnicate([]string)
  }
}

otherpackage.MyStruct uses --> mypackage.functions
@enduml

which would be rendered as:

dummy

Here a class with the dummy name "functions" is generated inside each package to hold all global functions of that package. To differentiate between this function "holder" and real structs I added the "F" symbol to function "holder" as the "S" is applied for structs already. Maybe the functions "holder" could also be specified as "abstract".

As MyStruct calls mypackage.Function1 in its DoSomething() method I added a "usage"-association between them.

jfeliu007 commented 4 years ago

I am struggling with this one. And here is my reasons.

In one hand, I do see the usage of relating packages through this kind of usage. For example, you could argue that if package A uses top level functions of package B, that they are both related. But on the other hand, I can also see this could make the diagram extremely cluttered with a lot of connections which could prevent it from being actually useful. In my opinion, this is something that could potentially be its own type of graph. For example, goplantuml could support multiple types of graphs and this could be something different just representing the relationships between packages and the functions they call on each other.

I guess, one question I have, so that I could help better on this one, is that if you can provide a use case for this specific type of relationship. For example, a scenario in which this connection will really help in the understanding of a project as a whole, which is my end goal with this project. And also, if you can help me think of a way to not clutter the diagram with connections just because I am using the strings functions. I can see many structures in a project using packages like that.

hupfdule commented 4 years ago

I can clearly understand that you want to avoid cluttering the diagram to unreadability. Providing different types of diagram is an interesting idea, like an object oriented view and a package oriented view.

But actually, since functions are first-class-citizens in Go as well as methods I don't see that such a distinction actually exists. Leaving functions out will always lead to a loss of information. Would such a function be turned into a method it would show up. However there would really be no functional difference.

What I could imagine is specifying the subjects of interest when generating the diagram. Then the user can include only real object relationships (as it is at the moment) or or only the package relationships or both in the same diagram.

Actually I didn't expect that usages of functions or methods in the standard library would be taken into account. Therefore using the strings functions should not make a difference. That makes me think of whether it is worth it to restrict the diagram generation to the same project. I think that is the most interesting part. As it may sometimes be interesting to see connections to other libraries it would be nice to have an option to specify which libraries to take into account when generating the diagram.

btiernay commented 1 year ago

Agreed that this would be useful. The other cited project now supports this feature.

btiernay commented 1 year ago

If the concern is cluttering the diagram, we could add an option to make it opt in or out like the others that exist today.